]> source.dussan.org Git - nextcloud-server.git/commitdiff
JS version of the OCP\ITags interface
authorThomas Tanghus <thomas@tanghus.net>
Fri, 4 Oct 2013 15:21:52 +0000 (17:21 +0200)
committerThomas Tanghus <thomas@tanghus.net>
Fri, 4 Oct 2013 15:21:52 +0000 (17:21 +0200)
core/css/jquery.ocdialog.css
core/css/styles.css
core/js/tags.js [new file with mode: 0644]
core/routes.php
core/tags/controller.php [new file with mode: 0644]
core/templates/tags.html [new file with mode: 0644]

index aa72eaf8474ea409b064b2a8d0a6d8bd57e9858b..236968e3245b68e3ad7ba9138ec18c51aeac5be4 100644 (file)
@@ -29,6 +29,7 @@
        bottom: 0;
        display: block;
        margin-top: 10px;
+       width: 100%;
 }
 
 .oc-dialog-close {
index 06b61f0fa689d792a3e61b46e1c867c1baf6a30b..b0b247de9bc3de9ab4ae52304d4caa24023fb845 100644 (file)
@@ -726,15 +726,21 @@ span.ui-icon {float: left; margin: 3px 7px 30px 0;}
        height: 16px;
 }
 
-
-/* ---- CATEGORIES ---- */
-#categoryform .scrollarea { position:absolute; left:10px; top:10px; right:10px; bottom:50px; overflow:auto; border:1px solid #ddd; background:#f8f8f8; }
-#categoryform .bottombuttons { position:absolute; bottom:10px;}
-#categoryform .bottombuttons * { float:left;}
-/*#categorylist { border:1px solid #ddd;}*/
-#categorylist li { background:#f8f8f8; padding:.3em .8em; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; -webkit-transition:background-color 500ms; -moz-transition:background-color 500ms; -o-transition:background-color 500ms; transition:background-color 500ms; }
-#categorylist li:hover, #categorylist li:active { background:#eee; }
-#category_addinput { width:10em; }
+/* ---- TAGS ---- */
+#tagsdialog .content {
+       width: 100%; height: 280px;
+}
+#tagsdialog .scrollarea {
+       overflow:auto; border:1px solid #ddd;
+       width: 100%; height: 240px;
+}
+#tagsdialog .bottombuttons {
+        width: 100%; height: 30px;
+}
+#tagsdialog .bottombuttons * { float:left;}
+#tagsdialog .taglist li { background:#f8f8f8; padding:.3em .8em; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; -webkit-transition:background-color 500ms; -moz-transition:background-color 500ms; -o-transition:background-color 500ms; transition:background-color 500ms; }
+#tagsdialog .taglist li:hover, #tagsdialog .taglist li:active { background:#eee; }
+#tagsdialog .addinput { width: 90%; clear: both; }
 
 /* ---- APP SETTINGS ---- */
 .popup { background-color:white; border-radius:10px 10px 10px 10px; box-shadow:0 0 20px #888; color:#333; padding:10px; position:fixed !important; z-index:100; }
diff --git a/core/js/tags.js b/core/js/tags.js
new file mode 100644 (file)
index 0000000..a4c4290
--- /dev/null
@@ -0,0 +1,353 @@
+OC.Tags= {
+       edit:function(type, cb) {
+               if(!type && !this.type) {
+                       throw { name: 'MissingParameter', message: t('core', 'The object type is not specified.') };
+               }
+               type = type ? type : this.type;
+               var self = this;
+               $.when(this._getTemplate()).then(function($tmpl) {
+                       if(self.$dialog) {
+                               self.$dialog.ocdialog('close');
+                       }
+                       self.$dialog = $tmpl.octemplate({
+                               addText: t('core', 'Enter new')
+                       });
+                       $('body').append(self.$dialog);
+
+                       self.$dialog.ready(function() {
+                               self.$taglist = self.$dialog.find('.taglist');
+                               self.$taginput = self.$dialog.find('.addinput');
+                               self.$taglist.on('change', 'input:checkbox', function(event) {
+                                       self._handleChanges(self.$taglist, self.$taginput);
+                               });
+                               self.$taginput.on('input', function(event) {
+                                       self._handleChanges(self.$taglist, self.$taginput);
+                               });
+                               self.deleteButton = {
+                                       text: t('core', 'Delete'),
+                                       click: function() {self._deleteTags(self, type, self._selectedIds())},
+                               };
+                               self.addButton = {
+                                       text: t('core', 'Add'),
+                                       click: function() {self._addTag(self, type, self.$taginput.val())},
+                               };
+
+                               self._fillTagList(type, self.$taglist);
+                       });
+
+                       self.$dialog.ocdialog({
+                               title: t('core', 'Edit tags'),
+                               closeOnEscape: true,
+                               width: 250,
+                               height: 'auto',
+                               modal: true,
+                               //buttons: buttonlist,
+                               close: function(event, ui) {
+                                       try {
+                                               $(this).ocdialog('destroy').remove();
+                                       } catch(e) {console.warn(e);}
+                                       self.$dialog = null;
+                               }
+                       });
+               })
+               .fail(function(status, error) {
+                       // If the method is called while navigating away
+                       // from the page, it is probably not needed ;)
+                       if(status !== 0) {
+                               alert(t('core', 'Error loading dialog template: {error}', {error: error}));
+                       }
+               });
+       },
+       /**
+        * @param string type
+        * @return jQuery.Promise which resolves with an array of ids
+        */
+       getIdsForTag:function(type, tag) {
+               if(!type && !this.type) {
+                       throw new Error('The object type is not specified.');
+               }
+               type = type ? type : this.type;
+               var defer = $.Deferred(),
+                       self = this,
+                       url = OC.Router.generate('core_tags_ids_for_tag', {type: type});
+               $.getJSON(url, {tag: tag}, function(response) {
+                       if(response.status === 'success') {
+                               defer.resolve(response.ids);
+                       } else {
+                               defer.reject(response);
+                       }
+               });
+               return defer.promise();
+       },
+       /**
+        * @param string type
+        * @return jQuery.Promise which resolves with an array of ids
+        */
+       getFavorites:function(type) {
+               if(!type && !this.type) {
+                       throw new Error('The object type is not specified.');
+               }
+               type = type ? type : this.type;
+               var defer = $.Deferred(),
+                       self = this,
+                       url = OC.Router.generate('core_tags_favorites', {type: type});
+               $.getJSON(url, function(response) {
+                       if(response.status === 'success') {
+                               defer.resolve(response.ids);
+                       } else {
+                               defer.reject(response);
+                       }
+               });
+               return defer.promise();
+       },
+       /**
+        * @param string type
+        * @return jQuery.Promise which resolves with an array of id/name objects
+        */
+       getTags:function(type) {
+               if(!type && !this.type) {
+                       throw new Error('The object type is not specified.');
+               }
+               type = type ? type : this.type;
+               var defer = $.Deferred(),
+                       self = this,
+                       url = OC.Router.generate('core_tags_tags', {type: type});
+               $.getJSON(url, function(response) {
+                       if(response.status === 'success') {
+                               defer.resolve(response.tags);
+                       } else {
+                               defer.reject(response);
+                       }
+               });
+               return defer.promise();
+       },
+       /**
+        * @param int id
+        * @param string type
+        * @return jQuery.Promise
+        */
+       tagAs:function(id, tag, type) {
+               if(!type && !this.type) {
+                       throw new Error('The object type is not specified.');
+               }
+               type = type ? type : this.type;
+               var defer = $.Deferred(),
+                       self = this,
+                       url = OC.Router.generate('core_tags_tag', {type: type, id: id});
+               $.post(url, {tag: tag}, function(response) {
+                       if(response.result === 'success') {
+                               defer.resolve(response);
+                       } else {
+                               defer.reject(response);
+                       }
+               }).fail(function(jqXHR, textStatus, errorThrown) {
+                       defer.reject(jqXHR.status, errorThrown);
+               });
+               return defer.promise();
+       },
+       /**
+        * @param int id
+        * @param string type
+        * @return jQuery.Promise
+        */
+       unTag:function(id, tag, type) {
+               if(!type && !this.type) {
+                       throw new Error('The object type is not specified.');
+               }
+               type = type ? type : this.type;
+               var defer = $.Deferred(),
+                       self = this,
+                       url = OC.Router.generate('core_tags_untag', {type: type, id: id});
+               $.post(url, {tag: tag}, function(response) {
+                       if(response.result === 'success') {
+                               defer.resolve(response);
+                       } else {
+                               defer.reject(response);
+                       }
+               }).fail(function(jqXHR, textStatus, errorThrown) {
+                       defer.reject(jqXHR.status, errorThrown);
+               });
+               return defer.promise();
+       },
+       /**
+        * @param int id
+        * @param string type
+        * @return jQuery.Promise
+        */
+       addToFavorites:function(id, type) {
+               if(!type && !this.type) {
+                       throw new Error('The object type is not specified.');
+               }
+               type = type ? type : this.type;
+               var defer = $.Deferred(),
+                       self = this,
+                       url = OC.Router.generate('core_tags_favorite', {type: type, id: id});
+               $.post(url, function(response) {
+                       if(response.result === 'success') {
+                               defer.resolve(response);
+                       } else {
+                               defer.reject(response);
+                       }
+               }).fail(function(jqXHR, textStatus, errorThrown) {
+                       defer.reject(jqXHR.status, errorThrown);
+               });
+               return defer.promise();
+       },
+       /**
+        * @param int id
+        * @param string type
+        * @return jQuery.Promise
+        */
+       removeFromFavorites:function(id, type) {
+               if(!type && !this.type) {
+                       throw new Error('The object type is not specified.');
+               }
+               type = type ? type : this.type;
+               var defer = $.Deferred(),
+                       self = this,
+                       url = OC.Router.generate('core_tags_unfavorite', {type: type, id: id});
+               $.post(url, function(response) {
+                       if(response.result === 'success') {
+                               defer.resolve();
+                       } else {
+                               defer.reject(response);
+                       }
+               }).fail(function(jqXHR, textStatus, errorThrown) {
+                       defer.reject(jqXHR.status, errorThrown);
+               });
+               return defer.promise();
+       },
+       /**
+        * @param string tag
+        * @param string type
+        * @return jQuery.Promise which resolves with an object with the name and the new id
+        */
+       addTag:function(tag, type) {
+               if(!type && !this.type) {
+                       throw new Error('The object type is not specified.');
+               }
+               type = type ? type : this.type;
+               var defer = $.Deferred(),
+                       self = this,
+                       url = OC.Router.generate('core_tags_add', {type: type});
+               $.post(url,{tag:tag}, function(response) {
+                       if(typeof cb == 'function') {
+                               cb(response);
+                       }
+                       if(response.status === 'success') {
+                               defer.resolve({id:response.id, name: tag});
+                       } else {
+                               defer.reject(response);
+                       }
+               }).fail(function(jqXHR, textStatus, errorThrown) {
+                       defer.reject(jqXHR.status, errorThrown);
+               });
+               return defer.promise();
+       },
+       /**
+        * @param array tags
+        * @param string type
+        * @return jQuery.Promise
+        */
+       deleteTags:function(tags, type) {
+               if(!type && !this.type) {
+                       throw new Error('The object type is not specified.');
+               }
+               type = type ? type : this.type;
+               var defer = $.Deferred(),
+                       self = this,
+                       url = OC.Router.generate('core_tags_delete', {type: type});
+               if(!tags || !tags.length) {
+                       throw new Error(t('core', 'No tags selected for deletion.'));
+               }
+               var self = this;
+               $.post(url, {tags:tags}, function(response) {
+                       if(response.status === 'success') {
+                               defer.resolve(response.tags);
+                       } else {
+                               defer.reject(response);
+                       }
+               }).fail(function(jqXHR, textStatus, errorThrown) {
+                       defer.reject(jqXHR.status, errorThrown);
+               });
+               return defer.promise();
+       },
+       _update:function(tags, type) {
+               if(!this.$dialog) {
+                       return;
+               }
+               var $taglist = this.$dialog.find('.taglist'),
+                       self = this;
+               $taglist.empty();
+               $.each(tags, function(idx, tag) {
+                       var $item = self.$listTmpl.octemplate({id: tag.id, name: tag.name});
+                       $item.appendTo($taglist);
+               });
+               $(this).trigger('change', {type: type, tags: tags});
+               if(typeof this.changed === 'function') {
+                       this.changed(tags);
+               }
+       },
+       _getTemplate: function() {
+               var defer = $.Deferred();
+               if(!this.$template) {
+                       var self = this;
+                       $.get(OC.filePath('core', 'templates', 'tags.html'), function(tmpl) {
+                               self.$template = $(tmpl);
+                               self.$listTmpl = self.$template.find('.taglist li:first-child').detach();
+                               defer.resolve(self.$template);
+                       })
+                       .fail(function(jqXHR, textStatus, errorThrown) {
+                               defer.reject(jqXHR.status, errorThrown);
+                       });
+               } else {
+                       defer.resolve(this.$template);
+               }
+               return defer.promise();
+       },
+       _fillTagList: function(type) {
+               var self = this;
+               $.when(this.getTags(type))
+               .then(function(tags) {
+                       self._update(tags, type);
+               })
+               .fail(function(response) {
+                       console.warn(response);
+               });
+       },
+       _selectedIds: function() {
+               return $.map(this.$taglist.find('input:checked'), function(b) {return $(b).val();});
+       },
+       _handleChanges: function($list, $input) {
+               var ids = this._selectedIds();
+               var buttons = [];
+               if($input.val().length) {
+                       buttons.push(this.addButton);
+               }
+               if(ids.length) {
+                       buttons.push(this.deleteButton);
+               }
+               this.$dialog.ocdialog('option', 'buttons', buttons);
+       },
+       _deleteTags: function(self, type, ids) {
+               $.when(self.deleteTags(ids, type))
+               .then(function() {
+                       self._fillTagList(type);
+                       self.$dialog.ocdialog('option', 'buttons', []);
+               })
+               .fail(function(response) {
+                       console.warn(response);
+               });
+       },
+       _addTag: function(self, type, tag) {
+               $.when(self.addTag(tag, type))
+               .then(function(tag) {
+                       self._fillTagList(type);
+                       self.$taginput.val('').trigger('input');
+               })
+               .fail(function(response) {
+                       console.warn(response);
+               });
+       }
+}
+
index 57e25c0f1f7371576aeeece169f8225941b2d116..4163bdcd5bcbc2835146c7684064869c39ce7a5c 100644 (file)
@@ -23,19 +23,43 @@ $this->create('core_ajax_share', '/core/ajax/share.php')
 // Translations
 $this->create('core_ajax_translations', '/core/ajax/translations.php')
        ->actionInclude('core/ajax/translations.php');
-// VCategories
-$this->create('core_ajax_vcategories_add', '/core/ajax/vcategories/add.php')
-       ->actionInclude('core/ajax/vcategories/add.php');
-$this->create('core_ajax_vcategories_delete', '/core/ajax/vcategories/delete.php')
-       ->actionInclude('core/ajax/vcategories/delete.php');
-$this->create('core_ajax_vcategories_addtofavorites', '/core/ajax/vcategories/addToFavorites.php')
-       ->actionInclude('core/ajax/vcategories/addToFavorites.php');
-$this->create('core_ajax_vcategories_removefromfavorites', '/core/ajax/vcategories/removeFromFavorites.php')
-       ->actionInclude('core/ajax/vcategories/removeFromFavorites.php');
-$this->create('core_ajax_vcategories_favorites', '/core/ajax/vcategories/favorites.php')
-       ->actionInclude('core/ajax/vcategories/favorites.php');
-$this->create('core_ajax_vcategories_edit', '/core/ajax/vcategories/edit.php')
-       ->actionInclude('core/ajax/vcategories/edit.php');
+// Tags
+$this->create('core_tags_tags', '/tags/{type}')
+       ->get()
+       ->action('OC\Core\Tags\Controller', 'getTags')
+       ->requirements(array('type'));
+$this->create('core_tags_favorites', '/tags/{type}/favorites')
+       ->get()
+       ->action('OC\Core\Tags\Controller', 'getFavorites')
+       ->requirements(array('type'));
+$this->create('core_tags_ids_for_tag', '/tags/{type}/ids')
+       ->get()
+       ->action('OC\Core\Tags\Controller', 'getIdsForTag')
+       ->requirements(array('type'));
+$this->create('core_tags_favorite', '/tags/{type}/favorite/{id}/')
+       ->post()
+       ->action('OC\Core\Tags\Controller', 'favorite')
+       ->requirements(array('type', 'id'));
+$this->create('core_tags_unfavorite', '/tags/{type}/infavorite/{id}/')
+       ->post()
+       ->action('OC\Core\Tags\Controller', 'unFavorite')
+       ->requirements(array('type', 'id'));
+$this->create('core_tags_tag', '/tags/{type}/tag/{id}/')
+       ->post()
+       ->action('OC\Core\Tags\Controller', 'tagAs')
+       ->requirements(array('type', 'id'));
+$this->create('core_tags_untag', '/tags/{type}/untag/{id}/')
+       ->post()
+       ->action('OC\Core\Tags\Controller', 'unTag')
+       ->requirements(array('type', 'id'));
+$this->create('core_tags_add', '/tags/{type}/add')
+       ->post()
+       ->action('OC\Core\Tags\Controller', 'addTag')
+       ->requirements(array('type'));
+$this->create('core_tags_delete', '/tags/{type}/delete')
+       ->post()
+       ->action('OC\Core\Tags\Controller', 'deleteTags')
+       ->requirements(array('type'));
 // oC JS config
 $this->create('js_config', '/core/js/config.js')
        ->actionInclude('core/js/config.php');
diff --git a/core/tags/controller.php b/core/tags/controller.php
new file mode 100644 (file)
index 0000000..c790d43
--- /dev/null
@@ -0,0 +1,114 @@
+<?php
+/**
+ * Copyright (c) 2013 Thomas Tanghus (thomas@tanghus.net)
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace OC\Core\Tags;
+
+class Controller {
+       protected static function getTagger($type) {
+               \OC_JSON::checkLoggedIn();
+               \OC_JSON::callCheck();
+
+               try {
+                       $tagger = \OC::$server->getTagManager()->load($type);
+                       return $tagger;
+               } catch(\Exception $e) {
+                       \OCP\Util::writeLog('core', __METHOD__ . ' Exception: ' . $e->getMessage(), \OCP\Util::ERROR);
+                       $l = new \OC_L10n('core');
+                       \OC_JSON::error(array('message'=> $l->t('Error loading tags')));
+                       exit;
+               }
+       }
+
+       public static function getTags($args) {
+               $tagger = self::getTagger($args['type']);
+               \OC_JSON::success(array('tags'=> $tagger->getTags()));
+       }
+
+       public static function getFavorites($args) {
+               $tagger = self::getTagger($args['type']);
+               \OC_JSON::success(array('ids'=> $tagger->getFavorites()));
+       }
+
+       public static function getIdsForTag($args) {
+               $tagger = self::getTagger($args['type']);
+               \OC_JSON::success(array('ids'=> $tagger->getIdsForTag($_GET['tag'])));
+       }
+
+       public static function addTag($args) {
+               $tagger = self::getTagger($args['type']);
+
+               $id = $tagger->add(strip_tags($_POST['tag']));
+               if($id === false) {
+                       $l = new \OC_L10n('core');
+                       \OC_JSON::error(array('message'=> $l->t('Tag already exists')));
+               } else {
+                       \OC_JSON::success(array('id'=> $id));
+               }
+       }
+
+       public static function deleteTags($args) {
+               $tags = $_POST['tags'];
+               if(!is_array($tags)) {
+                       $tags = array($tags);
+               }
+
+               $tagger = self::getTagger($args['type']);
+
+               if(!$tagger->delete($tags)) {
+                       $l = new \OC_L10n('core');
+                       \OC_JSON::error(array('message'=> $l->t('Error deleting tag(s)')));
+               } else {
+                       \OC_JSON::success();
+               }
+       }
+
+       public static function tagAs($args) {
+               $tagger = self::getTagger($args['type']);
+
+               if(!$tagger->tagAs($args['id'], $_POST['tag'])) {
+                       $l = new \OC_L10n('core');
+                       \OC_JSON::error(array('message'=> $l->t('Error tagging')));
+               } else {
+                       \OC_JSON::success();
+               }
+       }
+
+       public static function unTag($args) {
+               $tagger = self::getTagger($args['type']);
+
+               if(!$tagger->unTag($args['id'], $_POST['tag'])) {
+                       $l = new \OC_L10n('core');
+                       \OC_JSON::error(array('message'=> $l->t('Error untagging')));
+               } else {
+                       \OC_JSON::success();
+               }
+       }
+
+       public static function favorite($args) {
+               $tagger = self::getTagger($args['type']);
+
+               if(!$tagger->addToFavorites($args['id'])) {
+                       $l = new \OC_L10n('core');
+                       \OC_JSON::error(array('message'=> $l->t('Error favoriting')));
+               } else {
+                       \OC_JSON::success();
+               }
+       }
+
+       public static function unFavorite($args) {
+               $tagger = self::getTagger($args['type']);
+
+               if(!$tagger->removeFromFavorites($args['id'])) {
+                       $l = new \OC_L10n('core');
+                       \OC_JSON::error(array('message'=> $l->t('Error unfavoriting')));
+               } else {
+                       \OC_JSON::success();
+               }
+       }
+
+}
diff --git a/core/templates/tags.html b/core/templates/tags.html
new file mode 100644 (file)
index 0000000..ae3d072
--- /dev/null
@@ -0,0 +1,14 @@
+<div id="tagsdialog">
+       <div class="content">
+               <div class="scrollarea">
+                       <ul class="taglist">
+                               <li><input type="checkbox" name="ids[]" id="tag_{id}" value="{name}" />
+                                       <label for="tag_{id}">{name}</label>
+                               </li>
+                       </ul>
+               </div>
+               <div class="bottombuttons">
+                       <input type="text" class="addinput" name="tag" placeholder="{addText}" />
+               </div>
+       </div>
+</div>