From 8d59e3b9f0f55b8ebc219964be9fefb1fec86b19 Mon Sep 17 00:00:00 2001 From: Brice Maron Date: Tue, 26 Jun 2012 17:43:03 +0200 Subject: [PATCH] First version of Bookmark popup enhanced. Need more work --- addBm.php | 37 +- css/bookmarks.css | 64 ++++ css/jquery.tagit.css | 110 ++++++ js/addBm.js | 26 ++ js/tag-it.js | 759 ++++++++++++++++++++++++++++++++++++++ lib/bookmarks.php | 8 + templates/addBm.php | 58 ++- templates/bookmarklet.php | 2 +- 8 files changed, 1050 insertions(+), 14 deletions(-) create mode 100644 css/jquery.tagit.css create mode 100644 js/tag-it.js diff --git a/addBm.php b/addBm.php index 4df93c8b..3412e9ac 100644 --- a/addBm.php +++ b/addBm.php @@ -27,7 +27,40 @@ OCP\User::checkLoggedIn(); OCP\App::checkAppEnabled('bookmarks'); +if(!isset($_GET['url']) || trim($_GET['url']) == '') { + header("HTTP/1.0 404 Not Found"); + $tmpl = new OCP\Template( '', '404', 'guest' ); + $tmpl->printPage(); + exit; +} + require_once('bookmarksHelper.php'); -addBookmark($_GET['url'], '', 'Read-Later'); -include 'templates/addBm.php'; +if(isset($_POST['url'])) { + addBookmark($_POST['url'], '', 'Read-Later'); +} + +OCP\Util::addscript('bookmarks','tag-it'); +OCP\Util::addscript('bookmarks','addBm'); +OCP\Util::addStyle('bookmarks', 'bookmarks'); +OCP\Util::addStyle('bookmarks', 'jquery.tagit'); + +$bm = array('title'=>'hello world', + 'url'=> $_GET['url'], + 'tags'=> array('@admin','music','test'), + 'desc'=>'A fancy description', + 'is_public'=>1, +); + +//Find All Tags +$qtags = OC_Bookmarks_Bookmarks::findTags(); +$tags = array(); +foreach($qtags as $tag) { + $tags[] = $tag['tag']; +} + +$tmpl = new OCP\Template( 'bookmarks', 'addBm', 'empty' ); +$tmpl->assign('bookmark', $bm); +$tmpl->assign('tags', json_encode($tags), false); + +$tmpl->printPage(); diff --git a/css/bookmarks.css b/css/bookmarks.css index a67afcd4..0c664d6e 100644 --- a/css/bookmarks.css +++ b/css/bookmarks.css @@ -85,3 +85,67 @@ display: none; margin-left: 5px; } + +#addBm { + background: none repeat scroll 0 0 #F8F8F8; + border-radius: 0.5em 0.5em 0.5em 0.5em; + color: #555555; + margin: 1em; + padding: 0.5em 1em; + text-shadow: 0 1px 0 #FFFFFF; + width: 500px; + +} +.bm_desc { + width:90%; +} +#addBm h1 { + font-weight: bold; + border-bottom: 1px solid #BABABA; + +} + +#addBm #url { + display:none; +} + +#addBm fieldset > ul > li { + margin-top: 1em; +} +#addBm label { + display:block; + width:100%; +} +#addBm #is_public_label { + display: inline; + +} +#addBm fieldset input[type="text"], #addBm textarea { + width:100%; +} +#addBm textarea{ + min-width:250px; +/* min-height: 70px; */ +} +#addBm #close_btn +{ +/* background-color: #EEEEEE; */ + height: 18px; + margin: -20px 0 0; + padding: 1px; + float:right; + width: 19px; +} +#addBm .submit { + float: right; +} + +#addBm ul.tagit { background:white; } + +#addBm input.ui-autocomplete-input{ + box-shadow:none; +} + +.ui-autocomplete { +/* background: none repeat scroll 0 0 #DEE7F8; */ +} \ No newline at end of file diff --git a/css/jquery.tagit.css b/css/jquery.tagit.css new file mode 100644 index 00000000..1e7e0239 --- /dev/null +++ b/css/jquery.tagit.css @@ -0,0 +1,110 @@ +ul.tagit { + padding: 1px 5px; + overflow: auto; + margin-left: inherit; /* usually we don't want the regular ul margins. */ + margin-right: inherit; +} +ul.tagit li { + display: block; + float: left; + margin: 2px 5px 2px 0; +} +ul.tagit li.tagit-choice { + padding: .2em 18px .2em .5em; + position: relative; + line-height: inherit; +} +ul.tagit li.tagit-new { + padding: .25em 4px .25em 0; +} + +ul.tagit li.tagit-choice a.tagit-label { + cursor: pointer; + text-decoration: none; +} +ul.tagit li.tagit-choice .close { + cursor: pointer; + position: absolute; + right: .1em; + top: 50%; + margin-top: -8px; +} + +/* used for some custom themes that don't need image icons */ +ul.tagit li.tagit-choice .close .text-icon { + display: none; +} + +ul.tagit li.tagit-choice input { + display: block; + float: left; + margin: 2px 5px 2px 0; +} +ul.tagit input[type="text"] { + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; + + border: none; + margin: 0; + padding: 0; + width: inherit; + background-color: inherit; + outline: none; +} + + +/***** ZENDESK ***/ + +/* Optional scoped theme for tag-it which mimics the zendesk widget. */ + + +ul.tagit { + border-style: solid; + border-width: 1px; + border-color: #C6C6C6; + background: inherit; +} +ul.tagit li.tagit-choice { + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-border-radius: 6px; + border: 1px solid #CAD8F3; + + background: none; + background-color: #DEE7F8; + + color: #555; + font-weight: normal; +} +ul.tagit li.tagit-choice a.close { + text-decoration: none; +} +ul.tagit li.tagit-choice .close { + right: .4em; +} +ul.tagit li.tagit-choice .ui-icon { + display: none; +} +ul.tagit li.tagit-choice .close .text-icon { + display: inline; + font-family: arial, sans-serif; + font-size: 16px; + line-height: 16px; + color: #777; +} +ul.tagit li.tagit-choice:hover, ul.tagit li.tagit-choice.remove { + background-color: #bbcef1; + border-color: #6d95e0; +} +ul.tagit li.tagit-choice a.tagLabel:hover, +ul.tagit li.tagit-choice a.close .text-icon:hover { + color: #222; +} +ul.tagit input[type="text"] { + color: #333333; + background: none; +} + + + diff --git a/js/addBm.js b/js/addBm.js index 625ac842..006a8aa0 100644 --- a/js/addBm.js +++ b/js/addBm.js @@ -1,5 +1,14 @@ $(document).ready(function() { $('#bookmark_add_submit').click(addBookmark); + $('#url-ro img').click(editUrl); + $('#url').keypress(changeUrl); + $('#addBm').submit(bookletSubmit); + $('#tags').tagit({ + allowSpaces: true, + availableTags: sampleTags, + itemName: 'item', + fieldName: 'tags', + }); }); function addBookmark(event) { @@ -13,4 +22,21 @@ function addBookmark(event) { window.close(); } }); +} +function editUrl(event) { + $('#url').slideToggle(); +} +function changeUrl(event) { + $('#url-ro code').text($('#url').val()); +} +function bookletSubmit(event) { + event.preventDefault(); + $.ajax({ + type: 'POST', + url: $('#addBm').attr('action'), + data: $('#addBm').serialize(), + success: function(data){ + self.close(); + } + }); } \ No newline at end of file diff --git a/js/tag-it.js b/js/tag-it.js new file mode 100644 index 00000000..73d8ab95 --- /dev/null +++ b/js/tag-it.js @@ -0,0 +1,759 @@ +/* +* jQuery UI Tag-it! +* +* @version v2.0 (06/2011) +* +* Copyright 2011, Levy Carneiro Jr. +* Released under the MIT license. +* http://aehlke.github.com/tag-it/LICENSE +* +* Homepage: +* http://aehlke.github.com/tag-it/ +* +* Authors: +* Levy Carneiro Jr. +* Martin Rehfeld +* Tobias Schmidt +* Skylar Challand +* Alex Ehlke +* +* Maintainer: +* Alex Ehlke - Twitter: @aehlke +* +* Dependencies: +* jQuery v1.4+ +* jQuery UI v1.8+ +*/ +(function($) { + + $.widget('ui.tagit', { + options: { + itemName : 'item', + fieldName : 'tags', + availableTags : [], + tagSource : null, + removeConfirmation: false, + caseSensitive : true, + + // When enabled, quotes are not neccesary + // for inputting multi-word tags. + allowSpaces: false, + + // The below options are for using a single field instead of several + // for our form values. + // + // When enabled, will use a single hidden field for the form, + // rather than one per tag. It will delimit tags in the field + // with singleFieldDelimiter. + // + // The easiest way to use singleField is to just instantiate tag-it + // on an INPUT element, in which case singleField is automatically + // set to true, and singleFieldNode is set to that element. This + // way, you don't need to fiddle with these options. + singleField: false, + + singleFieldDelimiter: ',', + + // Set this to an input DOM node to use an existing form field. + // Any text in it will be erased on init. But it will be + // populated with the text of tags as they are created, + // delimited by singleFieldDelimiter. + // + // If this is not set, we create an input node for it, + // with the name given in settings.fieldName, + // ignoring settings.itemName. + singleFieldNode: null, + + // Optionally set a tabindex attribute on the input that gets + // created for tag-it. + tabIndex: null, + + + // Event callbacks. + onTagAdded : null, + onTagRemoved: null, + onTagClicked: null + }, + + + _create: function() { + // for handling static scoping inside callbacks + var that = this; + + // There are 2 kinds of DOM nodes this widget can be instantiated on: + // 1. UL, OL, or some element containing either of these. + // 2. INPUT, in which case 'singleField' is overridden to true, + // a UL is created and the INPUT is hidden. + if (this.element.is('input')) { + this.tagList = $('').insertAfter(this.element); + this.options.singleField = true; + this.options.singleFieldNode = this.element; + this.element.css('display', 'none'); + } else { + this.tagList = this.element.find('ul, ol').andSelf().last(); + } + + this._tagInput = $('').addClass('ui-widget-content'); + if (this.options.tabIndex) { + this._tagInput.attr('tabindex', this.options.tabIndex); + } + + this.options.tagSource = this.options.tagSource || function(search, showChoices) { + var filter = search.term.toLowerCase(); + var choices = $.grep(that.options.availableTags, function(element) { + // Only match autocomplete options that begin with the search term. + // (Case insensitive.) + return (element.toLowerCase().indexOf(filter) === 0); + }); + showChoices(that._subtractArray(choices, that.assignedTags())); + }; + + this.tagList + .addClass('tagit') + .addClass('ui-widget ui-widget-content ui-corner-all') + // Create the input field. + .append($('
  • ').append(this._tagInput)) + .click(function(e) { + var target = $(e.target); + if (target.hasClass('tagit-label')) { + that._trigger('onTagClicked', e, target.closest('.tagit-choice')); + } else { + // Sets the focus() to the input field, if the user + // clicks anywhere inside the UL. This is needed + // because the input field needs to be of a small size. + that._tagInput.focus(); + } + }); + + // Add existing tags from the list, if any. + this.tagList.children('li').each(function() { + if (!$(this).hasClass('tagit-new')) { + that.createTag($(this).html(), $(this).attr('class')); + $(this).remove(); + } + }); + + // Single field support. + if (this.options.singleField) { + if (this.options.singleFieldNode) { + // Add existing tags from the input field. + var node = $(this.options.singleFieldNode); + var tags = node.val().split(this.options.singleFieldDelimiter); + node.val(''); + $.each(tags, function(index, tag) { + that.createTag(tag); + }); + } else { + // Create our single field input after our list. + this.options.singleFieldNode = this.tagList.after(''); + } + } + + // Events. + this._tagInput + .keydown(function(event) { + // Backspace is not detected within a keypress, so it must use keydown. + if (event.which == $.ui.keyCode.BACKSPACE && that._tagInput.val() === '') { + var tag = that._lastTag(); + if (!that.options.removeConfirmation || tag.hasClass('remove')) { + // When backspace is pressed, the last tag is deleted. + that.removeTag(tag); + } else if (that.options.removeConfirmation) { + tag.addClass('remove ui-state-highlight'); + } + } else if (that.options.removeConfirmation) { + that._lastTag().removeClass('remove ui-state-highlight'); + } + + // Comma/Space/Enter are all valid delimiters for new tags, + // except when there is an open quote or if setting allowSpaces = true. + // Tab will also create a tag, unless the tag input is empty, in which case it isn't caught. + if ( + event.which == $.ui.keyCode.COMMA || + event.which == $.ui.keyCode.ENTER || + ( + event.which == $.ui.keyCode.TAB && + that._tagInput.val() !== '' + ) || + ( + event.which == $.ui.keyCode.SPACE && + that.options.allowSpaces !== true && + ( + $.trim(that._tagInput.val()).replace( /^s*/, '' ).charAt(0) != '"' || + ( + $.trim(that._tagInput.val()).charAt(0) == '"' && + $.trim(that._tagInput.val()).charAt($.trim(that._tagInput.val()).length - 1) == '"' && + $.trim(that._tagInput.val()).length - 1 !== 0 + ) + ) + ) + ) { + event.preventDefault(); + that.createTag(that._cleanedInput()); + + // The autocomplete doesn't close automatically when TAB is pressed. + // So let's ensure that it closes. + that._tagInput.autocomplete('close'); + } + }).blur(function(e){ + // Create a tag when the element loses focus (unless it's empty). + that.createTag(that._cleanedInput()); + }); + + + // Autocomplete. + if (this.options.availableTags || this.options.tagSource) { + this._tagInput.autocomplete({ + source: this.options.tagSource, + select: function(event, ui) { + // Delete the last tag if we autocomplete something despite the input being empty + // This happens because the input's blur event causes the tag to be created when + // the user clicks an autocomplete item. + // The only artifact of this is that while the user holds down the mouse button + // on the selected autocomplete item, a tag is shown with the pre-autocompleted text, + // and is changed to the autocompleted text upon mouseup. + if (that._tagInput.val() === '') { + that.removeTag(that._lastTag(), false); + } + that.createTag(ui.item.value); + // Preventing the tag input to be updated with the chosen value. + return false; + } + }); + } + }, + + _cleanedInput: function() { + // Returns the contents of the tag input, cleaned and ready to be passed to createTag + return $.trim(this._tagInput.val().replace(/^"(.*)"$/, '$1')); + }, + + _lastTag: function() { + return this.tagList.children('.tagit-choice:last'); + }, + + assignedTags: function() { + // Returns an array of tag string values + var that = this; + var tags = []; + if (this.options.singleField) { + tags = $(this.options.singleFieldNode).val().split(this.options.singleFieldDelimiter); + if (tags[0] === '') { + tags = []; + } + } else { + this.tagList.children('.tagit-choice').each(function() { + tags.push(that.tagLabel(this)); + }); + } + return tags; + }, + + _updateSingleTagsField: function(tags) { + // Takes a list of tag string values, updates this.options.singleFieldNode.val to the tags delimited by this.options.singleFieldDelimiter + $(this.options.singleFieldNode).val(tags.join(this.options.singleFieldDelimiter)); + }, + + _subtractArray: function(a1, a2) { + var result = []; + for (var i = 0; i < a1.length; i++) { + if ($.inArray(a1[i], a2) == -1) { + result.push(a1[i]); + } + } + return result; + }, + + tagLabel: function(tag) { + // Returns the tag's string label. + if (this.options.singleField) { + return $(tag).children('.tagit-label').text(); + } else { + return $(tag).children('input').val(); + } + }, + + _isNew: function(value) { + var that = this; + var isNew = true; + this.tagList.children('.tagit-choice').each(function(i) { + if (that._formatStr(value) == that._formatStr(that.tagLabel(this))) { + isNew = false; + return; + } + }); + return isNew; + }, + + _formatStr: function(str) { + if (this.options.caseSensitive) { + return str; + } + return $.trim(str.toLowerCase()); + }, + + createTag: function(value, additionalClass) { + that = this; + // Automatically trims the value of leading and trailing whitespace. + value = $.trim(value); + + if (!this._isNew(value) || value === '') { + return false; + } + + var label = $(this.options.onTagClicked ? '' : '').text(value); + + // Create tag. + var tag = $('
  • ') + .addClass('tagit-choice ui-widget-content ui-state-default ui-corner-all') + .addClass(additionalClass) + .append(label); + + // Button for removing the tag. + var removeTagIcon = $('') + .addClass('ui-icon ui-icon-close'); + var removeTag = $('\xd7') // \xd7 is an X + .addClass('close') + .append(removeTagIcon) + .click(function(e) { + // Removes a tag when the little 'x' is clicked. + that.removeTag(tag); + }); + tag.append(removeTag); + + // Unless options.singleField is set, each tag has a hidden input field inline. + if (this.options.singleField) { + var tags = this.assignedTags(); + tags.push(value); + this._updateSingleTagsField(tags); + } else { + var escapedValue = label.html(); + tag.append(''); + } + + this._trigger('onTagAdded', null, tag); + + // Cleaning the input. + this._tagInput.val(''); + + // insert tag + this._tagInput.parent().before(tag); + }, + + removeTag: function(tag, animate) { + if (typeof animate === 'undefined') { animate = true; } + + tag = $(tag); + + this._trigger('onTagRemoved', null, tag); + + if (this.options.singleField) { + var tags = this.assignedTags(); + var removedTagLabel = this.tagLabel(tag); + tags = $.grep(tags, function(el){ + return el != removedTagLabel; + }); + this._updateSingleTagsField(tags); + } + // Animate the removal. + if (animate) { + tag.fadeOut('fast').hide('blind', {direction: 'horizontal'}, 'fast', function(){ + tag.remove(); + }).dequeue(); + } else { + tag.remove(); + } + }, + + removeAll: function() { + // Removes all tags. Takes an optional `animate` argument. + var that = this; + this.tagList.children('.tagit-choice').each(function(index, tag) { + that.removeTag(tag, false); + }); + } + + }); + +})(jQuery); + + +/* +* jQuery UI Tag-it! +* +* @version v2.0 (06/2011) +* +* Copyright 2011, Levy Carneiro Jr. +* Released under the MIT license. +* http://aehlke.github.com/tag-it/LICENSE +* +* Homepage: +* http://aehlke.github.com/tag-it/ +* +* Authors: +* Levy Carneiro Jr. +* Martin Rehfeld +* Tobias Schmidt +* Skylar Challand +* Alex Ehlke +* +* Maintainer: +* Alex Ehlke - Twitter: @aehlke +* +* Dependencies: +* jQuery v1.4+ +* jQuery UI v1.8+ +*/ +(function($) { + + $.widget('ui.tagit', { + options: { + itemName : 'item', + fieldName : 'tags', + availableTags : [], + tagSource : null, + removeConfirmation: false, + caseSensitive : true, + + // When enabled, quotes are not neccesary + // for inputting multi-word tags. + allowSpaces: false, + + // The below options are for using a single field instead of several + // for our form values. + // + // When enabled, will use a single hidden field for the form, + // rather than one per tag. It will delimit tags in the field + // with singleFieldDelimiter. + // + // The easiest way to use singleField is to just instantiate tag-it + // on an INPUT element, in which case singleField is automatically + // set to true, and singleFieldNode is set to that element. This + // way, you don't need to fiddle with these options. + singleField: false, + + singleFieldDelimiter: ',', + + // Set this to an input DOM node to use an existing form field. + // Any text in it will be erased on init. But it will be + // populated with the text of tags as they are created, + // delimited by singleFieldDelimiter. + // + // If this is not set, we create an input node for it, + // with the name given in settings.fieldName, + // ignoring settings.itemName. + singleFieldNode: null, + + // Optionally set a tabindex attribute on the input that gets + // created for tag-it. + tabIndex: null, + + + // Event callbacks. + onTagAdded : null, + onTagRemoved: null, + onTagClicked: null + }, + + + _create: function() { + // for handling static scoping inside callbacks + var that = this; + + // There are 2 kinds of DOM nodes this widget can be instantiated on: + // 1. UL, OL, or some element containing either of these. + // 2. INPUT, in which case 'singleField' is overridden to true, + // a UL is created and the INPUT is hidden. + if (this.element.is('input')) { + this.tagList = $('').insertAfter(this.element); + this.options.singleField = true; + this.options.singleFieldNode = this.element; + this.element.css('display', 'none'); + } else { + this.tagList = this.element.find('ul, ol').andSelf().last(); + } + + this._tagInput = $('').addClass('ui-widget-content'); + if (this.options.tabIndex) { + this._tagInput.attr('tabindex', this.options.tabIndex); + } + + this.options.tagSource = this.options.tagSource || function(search, showChoices) { + var filter = search.term.toLowerCase(); + var choices = $.grep(that.options.availableTags, function(element) { + // Only match autocomplete options that begin with the search term. + // (Case insensitive.) + return (element.toLowerCase().indexOf(filter) === 0); + }); + showChoices(that._subtractArray(choices, that.assignedTags())); + }; + + this.tagList + .addClass('tagit') + .addClass('ui-widget ui-widget-content ui-corner-all') + // Create the input field. + .append($('
  • ').append(this._tagInput)) + .click(function(e) { + var target = $(e.target); + if (target.hasClass('tagit-label')) { + that._trigger('onTagClicked', e, target.closest('.tagit-choice')); + } else { + // Sets the focus() to the input field, if the user + // clicks anywhere inside the UL. This is needed + // because the input field needs to be of a small size. + that._tagInput.focus(); + } + }); + + // Add existing tags from the list, if any. + this.tagList.children('li').each(function() { + if (!$(this).hasClass('tagit-new')) { + that.createTag($(this).html(), $(this).attr('class')); + $(this).remove(); + } + }); + + // Single field support. + if (this.options.singleField) { + if (this.options.singleFieldNode) { + // Add existing tags from the input field. + var node = $(this.options.singleFieldNode); + var tags = node.val().split(this.options.singleFieldDelimiter); + node.val(''); + $.each(tags, function(index, tag) { + that.createTag(tag); + }); + } else { + // Create our single field input after our list. + this.options.singleFieldNode = this.tagList.after(''); + } + } + + // Events. + this._tagInput + .keydown(function(event) { + // Backspace is not detected within a keypress, so it must use keydown. + if (event.which == $.ui.keyCode.BACKSPACE && that._tagInput.val() === '') { + var tag = that._lastTag(); + if (!that.options.removeConfirmation || tag.hasClass('remove')) { + // When backspace is pressed, the last tag is deleted. + that.removeTag(tag); + } else if (that.options.removeConfirmation) { + tag.addClass('remove ui-state-highlight'); + } + } else if (that.options.removeConfirmation) { + that._lastTag().removeClass('remove ui-state-highlight'); + } + + // Comma/Space/Enter are all valid delimiters for new tags, + // except when there is an open quote or if setting allowSpaces = true. + // Tab will also create a tag, unless the tag input is empty, in which case it isn't caught. + if ( + event.which == $.ui.keyCode.COMMA || + event.which == $.ui.keyCode.ENTER || + ( + event.which == $.ui.keyCode.TAB && + that._tagInput.val() !== '' + ) || + ( + event.which == $.ui.keyCode.SPACE && + that.options.allowSpaces !== true && + ( + $.trim(that._tagInput.val()).replace( /^s*/, '' ).charAt(0) != '"' || + ( + $.trim(that._tagInput.val()).charAt(0) == '"' && + $.trim(that._tagInput.val()).charAt($.trim(that._tagInput.val()).length - 1) == '"' && + $.trim(that._tagInput.val()).length - 1 !== 0 + ) + ) + ) + ) { + event.preventDefault(); + that.createTag(that._cleanedInput()); + + // The autocomplete doesn't close automatically when TAB is pressed. + // So let's ensure that it closes. + that._tagInput.autocomplete('close'); + } + }).blur(function(e){ + // Create a tag when the element loses focus (unless it's empty). + that.createTag(that._cleanedInput()); + }); + + + // Autocomplete. + if (this.options.availableTags || this.options.tagSource) { + this._tagInput.autocomplete({ + source: this.options.tagSource, + select: function(event, ui) { + // Delete the last tag if we autocomplete something despite the input being empty + // This happens because the input's blur event causes the tag to be created when + // the user clicks an autocomplete item. + // The only artifact of this is that while the user holds down the mouse button + // on the selected autocomplete item, a tag is shown with the pre-autocompleted text, + // and is changed to the autocompleted text upon mouseup. + if (that._tagInput.val() === '') { + that.removeTag(that._lastTag(), false); + } + that.createTag(ui.item.value); + // Preventing the tag input to be updated with the chosen value. + return false; + } + }); + } + }, + + _cleanedInput: function() { + // Returns the contents of the tag input, cleaned and ready to be passed to createTag + return $.trim(this._tagInput.val().replace(/^"(.*)"$/, '$1')); + }, + + _lastTag: function() { + return this.tagList.children('.tagit-choice:last'); + }, + + assignedTags: function() { + // Returns an array of tag string values + var that = this; + var tags = []; + if (this.options.singleField) { + tags = $(this.options.singleFieldNode).val().split(this.options.singleFieldDelimiter); + if (tags[0] === '') { + tags = []; + } + } else { + this.tagList.children('.tagit-choice').each(function() { + tags.push(that.tagLabel(this)); + }); + } + return tags; + }, + + _updateSingleTagsField: function(tags) { + // Takes a list of tag string values, updates this.options.singleFieldNode.val to the tags delimited by this.options.singleFieldDelimiter + $(this.options.singleFieldNode).val(tags.join(this.options.singleFieldDelimiter)); + }, + + _subtractArray: function(a1, a2) { + var result = []; + for (var i = 0; i < a1.length; i++) { + if ($.inArray(a1[i], a2) == -1) { + result.push(a1[i]); + } + } + return result; + }, + + tagLabel: function(tag) { + // Returns the tag's string label. + if (this.options.singleField) { + return $(tag).children('.tagit-label').text(); + } else { + return $(tag).children('input').val(); + } + }, + + _isNew: function(value) { + var that = this; + var isNew = true; + this.tagList.children('.tagit-choice').each(function(i) { + if (that._formatStr(value) == that._formatStr(that.tagLabel(this))) { + isNew = false; + return; + } + }); + return isNew; + }, + + _formatStr: function(str) { + if (this.options.caseSensitive) { + return str; + } + return $.trim(str.toLowerCase()); + }, + + createTag: function(value, additionalClass) { + that = this; + // Automatically trims the value of leading and trailing whitespace. + value = $.trim(value); + + if (!this._isNew(value) || value === '') { + return false; + } + + var label = $(this.options.onTagClicked ? '' : '').text(value); + + // Create tag. + var tag = $('
  • ') + .addClass('tagit-choice ui-widget-content ui-state-default ui-corner-all') + .addClass(additionalClass) + .append(label); + + // Button for removing the tag. + var removeTagIcon = $('') + .addClass('ui-icon ui-icon-close'); + var removeTag = $('\xd7') // \xd7 is an X + .addClass('close') + .append(removeTagIcon) + .click(function(e) { + // Removes a tag when the little 'x' is clicked. + that.removeTag(tag); + }); + tag.append(removeTag); + + // Unless options.singleField is set, each tag has a hidden input field inline. + if (this.options.singleField) { + var tags = this.assignedTags(); + tags.push(value); + this._updateSingleTagsField(tags); + } else { + var escapedValue = label.html(); + tag.append(''); + } + + this._trigger('onTagAdded', null, tag); + + // Cleaning the input. + this._tagInput.val(''); + + // insert tag + this._tagInput.parent().before(tag); + }, + + removeTag: function(tag, animate) { + if (typeof animate === 'undefined') { animate = true; } + + tag = $(tag); + + this._trigger('onTagRemoved', null, tag); + + if (this.options.singleField) { + var tags = this.assignedTags(); + var removedTagLabel = this.tagLabel(tag); + tags = $.grep(tags, function(el){ + return el != removedTagLabel; + }); + this._updateSingleTagsField(tags); + } + // Animate the removal. + if (animate) { + tag.fadeOut('fast').hide('blind', {direction: 'horizontal'}, 'fast', function(){ + tag.remove(); + }).dequeue(); + } else { + tag.remove(); + } + }, + + removeAll: function() { + // Removes all tags. Takes an optional `animate` argument. + var that = this; + this.tagList.children('.tagit-choice').each(function(index, tag) { + that.removeTag(tag, false); + }); + } + + }); + +})(jQuery); + diff --git a/lib/bookmarks.php b/lib/bookmarks.php index e1e13388..b72a1f6c 100644 --- a/lib/bookmarks.php +++ b/lib/bookmarks.php @@ -25,6 +25,14 @@ */ class OC_Bookmarks_Bookmarks{ + /** + * @brief Finds all tags for bookmarks + */ + public static function findTags($offset = 0, $limit = 10){ + $query = OCP\DB::prepare('SELECT distinct tag from *PREFIX*bookmarks_tags LIMIT '.$offset.', '.$limit); + $tags = $query->execute()->fetchAll(); + return $tags; + } /** * @brief Finds all bookmarks, matching the filter * @param offset result offset diff --git a/templates/addBm.php b/templates/addBm.php index 357e0a18..dceaaaeb 100644 --- a/templates/addBm.php +++ b/templates/addBm.php @@ -1,11 +1,47 @@ - - - - - Read later - ownCloud - - -

    Saved!

    - Close the window - - \ No newline at end of file +
    +

    t('Add a bookmark');?>

    + +
    +
      +
    • + + +
    • + +
    • + +
      + + <?php echo $l->t('Edit');?> +
      + +
    • + +
    • + +
        + +
      • + +
      +
    • + +
    • + + +
    • + +
    • + " /> + id="is_public" name="is_public"> + +
    • + +
    + +
    + +
    \ No newline at end of file diff --git a/templates/bookmarklet.php b/templates/bookmarklet.php index 1802814d..6c7933c7 100644 --- a/templates/bookmarklet.php +++ b/templates/bookmarklet.php @@ -3,6 +3,6 @@ function createBookmarklet() { $l = OC_L10N::get('bookmarks'); echo '' . $l->t('Drag this to your browser bookmarks and click it, when you want to bookmark a webpage quickly:') . '' - . '' + . '' . $l->t('Read later') . ''; }