]> git.wh0rd.org - tt-rss.git/commitdiff
rework pref-feeds dialog; update other pref panes
authorAndrew Dolgov <fox@madoka.volgo-balt.ru>
Wed, 17 Nov 2010 18:13:41 +0000 (21:13 +0300)
committerAndrew Dolgov <fox@madoka.volgo-balt.ru>
Wed, 17 Nov 2010 18:13:41 +0000 (21:13 +0300)
backend.php
functions.php
lib/CheckBoxTree.js [new file with mode: 0644]
modules/pref-feeds.php
modules/pref-filters.php
modules/pref-labels.php
prefs.js

index 9a1a4d7137ed03aac704c7b26ba371321fd46d48..3d415eb5e5d86d8920e95a2f214d3e4335d9d5bc 100644 (file)
                break; // rpc
 
                case "feeds":
-                       $print_exec_time = true;
-
                        $subop = $_REQUEST["subop"];
+                       $root = (bool)$_REQUEST["root"];
 
                        switch($subop) {
                                case "catchupAll":
 
                        }
 
-                       print json_encode(outputFeedList($link));
+                       if (!$root) {
+                               print json_encode(outputFeedList($link));
+                       } else {
+
+                               $feeds = outputFeedList($link, false);
+
+                               $root = array();
+                               $root['id'] = 'root';
+                               $root['name'] = __('Feeds');
+                               $root['items'] = $feeds['items'];
+
+                               $fl = array();
+                               $fl['identifier'] = 'id';
+                               $fl['label'] = 'name';
+                               $fl['items'] = array($root);
+
+                               print json_encode($fl);
+                       }
 
                break; // feeds
 
index a6977b2a21b7f93374d34a231a242a398a1ccf45..2282cb744eaf1cd5a8a879d908303ebdd0f8a3c7 100644 (file)
 
                }
        
-       function outputFeedList($link) {
+       function outputFeedList($link, $special = true) {
 
                $feedlist = array();
 
 
                /* virtual feeds */
 
-               if ($enable_cats) {
-                       $cat_hidden = get_pref($link, "_COLLAPSED_SPECIAL");
-                       $cat = feedlist_init_cat($link, -1, $cat_hidden);
-               } else {
-                       $cat['items'] = array();
-               }
-
-               foreach (array(-4, -3, -1, -2, 0) as $i) {
-                       array_push($cat['items'], feedlist_init_feed($link, $i));
-               }
+               if ($special) {
 
-               if ($enable_cats) {
-                       array_push($feedlist['items'], $cat);
-               } else {
-                       $feedlist['items'] = array_merge($feedlist['items'], $cat['items']);
-               }
-
-               $result = db_query($link, "SELECT * FROM
-                       ttrss_labels2 WHERE owner_uid = '$owner_uid' ORDER by caption");
+                       if ($enable_cats) {
+                               $cat_hidden = get_pref($link, "_COLLAPSED_SPECIAL");
+                               $cat = feedlist_init_cat($link, -1, $cat_hidden);
+                       } else {
+                               $cat['items'] = array();
+                       }
        
-               if (get_pref($link, 'ENABLE_FEED_CATS')) {
-                       $cat_hidden = get_pref($link, "_COLLAPSED_LABELS");
-                       $cat = feedlist_init_cat($link, -2, $cat_hidden);
-               } else {
-                       $cat['items'] = array();
-               }
-
-               while ($line = db_fetch_assoc($result)) {
-
-                       $label_id = -$line['id'] - 11;
-                       $count = getFeedUnread($link, $label_id);
+                       foreach (array(-4, -3, -1, -2, 0) as $i) {
+                               array_push($cat['items'], feedlist_init_feed($link, $i));
+                       }
+       
+                       if ($enable_cats) {
+                               array_push($feedlist['items'], $cat);
+                       } else {
+                               $feedlist['items'] = array_merge($feedlist['items'], $cat['items']);
+                       }
+       
+                       $result = db_query($link, "SELECT * FROM
+                               ttrss_labels2 WHERE owner_uid = '$owner_uid' ORDER by caption");
+               
+                       if (get_pref($link, 'ENABLE_FEED_CATS')) {
+                               $cat_hidden = get_pref($link, "_COLLAPSED_LABELS");
+                               $cat = feedlist_init_cat($link, -2, $cat_hidden);
+                       } else {
+                               $cat['items'] = array();
+                       }
 
-                       array_push($cat['items'], feedlist_init_feed($link, $label_id, 
-                               false, $count));
+                       while ($line = db_fetch_assoc($result)) {
+       
+                               $label_id = -$line['id'] - 11;
+                               $count = getFeedUnread($link, $label_id);
+       
+                               array_push($cat['items'], feedlist_init_feed($link, $label_id, 
+                                       false, $count));
+                       }
+       
+                       if ($enable_cats) {
+                               array_push($feedlist['items'], $cat);
+                       } else {
+                               $feedlist['items'] = array_merge($feedlist['items'], $cat['items']);
+                       }
                }
 
-               if ($enable_cats) {
-                       array_push($feedlist['items'], $cat);
-               } else {
-                       $feedlist['items'] = array_merge($feedlist['items'], $cat['items']);
-               }
        
 /*             if (get_pref($link, 'ENABLE_FEED_CATS')) {
                        if (get_pref($link, "FEEDS_SORT_BY_UNREAD")) {
                        $cat_unread = getCategoryUnread($link, $cat_id);
                }
 
-               $obj['id'] = 'CAT:' . ((int)$cat_id);
+               $obj['id'] = 'CAT:' . $cat_id;
                $obj['items'] = array();
                $obj['name'] = getCategoryTitle($link, $cat_id);
                $obj['type'] = 'feed';
                $obj['unread'] = (int) $cat_unread;
                $obj['hidden'] = $hidden;
+               $obj['bare_id'] = $cat_id;
 
                return $obj;
        }
 
        function feedlist_init_feed($link, $feed_id, $title = false, $unread = false, $error = '', $updated = '') {
                $obj = array();
+               $feed_id = (int) $feed_id;
 
                if (!$title) 
                        $title = getFeedTitle($link, $feed_id, false);
                $obj['error'] = $error;
                $obj['updated'] = $updated;
                $obj['icon'] = getFeedIcon($feed_id);
+               $obj['checkbox'] = false;
+               $obj['bare_id'] = $feed_id;
 
                return $obj;
        }
diff --git a/lib/CheckBoxTree.js b/lib/CheckBoxTree.js
new file mode 100644 (file)
index 0000000..35e7039
--- /dev/null
@@ -0,0 +1,464 @@
+dojo.provide("lib.CheckBoxTree");
+dojo.provide("lib.CheckBoxStoreModel");
+
+// THIS WIDGET IS BASED ON DOJO/DIJIT 1.4.0 AND WILL NOT WORK WITH PREVIOUS VERSIONS
+//
+//     Release date: 02/05/2010
+//
+
+dojo.require("dijit.Tree");
+dojo.require("dijit.form.CheckBox");
+
+dojo.declare( "lib.CheckBoxStoreModel", dijit.tree.TreeStoreModel, 
+{
+       // checkboxAll: Boolean
+       //              If true, every node in the tree will receive a checkbox regardless if the 'checkbox' attribute 
+       //              is specified in the dojo.data.
+       checkboxAll: true,
+
+       // checkboxState: Boolean
+       //              The default state applied to every checkbox unless otherwise specified in the dojo.data.
+       //              (see also: checkboxIdent)
+       checkboxState: false,
+
+       // checkboxRoot: Boolean
+       //              If true, the root node will receive a checkbox eventhough it's not a true entry in the store.
+       //              This attribute is independent of the showRoot attribute of the tree itself. If the tree
+       //              attribute 'showRoot' is set to false to checkbox for the root will not show either.  
+       checkboxRoot: false,
+
+       // checkboxStrict: Boolean
+       //              If true, a strict parent-child checkbox relation is maintained. For example, if all children 
+       //              are checked the parent will automatically be checked or if any of the children are unchecked
+       //              the parent will be unchecked. 
+       checkboxStrict: true,
+
+       // checkboxIdent: String
+       //              The attribute name (attribute of the dojo.data.item) that specifies that items checkbox initial
+       //              state. Example: { name:'Egypt', type:'country', checkbox: true }
+       //              If a dojo.data.item has no 'checkbox' attribute specified it will depend on the attribute
+       //              'checkboxAll' if one will be created automatically and if so what the initial state will be as
+       //              specified by 'checkboxState'. 
+       checkboxIdent: "checkbox",
+
+       updateCheckbox: function(/*dojo.data.Item*/ storeItem, /*Boolean*/ newState ) {
+               // summary:
+               //              Update the checkbox state (true/false) for the item and the associated parent and 
+               //              child checkboxes if any. 
+               // description:
+               //              Update a single checkbox state (true/false) for the item and the associated parent 
+               //              and child checkboxes if any. This function is called from the tree if a user checked
+               //              or unchecked a checkbox on the tree. The parent and child tree nodes are updated to 
+               //              maintain consistency if 'checkboxStrict' is set to true.
+               //      storeItem:
+               //              The item in the dojo.data.store whos checkbox state needs updating.
+               //      newState:
+               //              The new state of the checkbox: true or false
+               //      example:
+               //      | model.updateCheckboxState(item, true);
+               //
+               this._setCheckboxState( storeItem, newState );
+               if( this.checkboxStrict ) {
+                       this._updateChildCheckbox( storeItem, newState );
+                       this._updateParentCheckbox( storeItem, newState );
+               }
+       },
+       setAllChecked: function(checked) {
+               var items = this.store._arrayOfAllItems;
+               this.setCheckboxState(items, checked);
+       },
+       setCheckboxState: function(items, checked) {
+               for (var i = 0; i < items.length; i++) {
+                       this._setCheckboxState(items[i], checked);
+               }
+       },
+       getCheckedItems: function() {
+               var items = this.store._arrayOfAllItems;
+               var result = [];
+
+               for (var i = 0; i < items.length; i++) {
+                       if (this.store.getValue(items[i], 'checkbox')) 
+                               result.push(items[i]);
+               }
+
+               return result;
+   },
+
+       getCheckboxState: function(/*dojo.data.Item*/ storeItem) {
+               // summary:
+               //              Get the current checkbox state from the dojo.data.store.
+               // description:
+               //              Get the current checkbox state from the dojo.data store. A checkbox can have three
+               //              different states: true, false or undefined. Undefined in this context means no
+               //              checkbox identifier (checkboxIdent) was found in the dojo.data store. Depending on
+               //              the checkbox attributes as specified above the following will take place:
+               //              a)      If the current checkbox state is undefined and the checkbox attribute 'checkboxAll' or
+               //                      'checkboxRoot' is true one will be created and the default state 'checkboxState' will
+               //                      be applied.
+               //              b)      If the current state is undefined and 'checkboxAll' is false the state undefined remains
+               //                      unchanged and is returned. This will prevent any tree node from creating a checkbox.
+               //
+               //      storeItem:
+               //              The item in the dojo.data.store whos checkbox state is returned.
+               //      example:
+               //      | var currState = model.getCheckboxState(item);
+               //              
+               var currState = undefined;
+               
+               // Special handling required for the 'fake' root entry (the root is NOT a dojo.data.item).
+               if ( storeItem == this.root ) {
+                       if( typeof(storeItem.checkbox) == "undefined" ) {
+                               this.root.checkbox = undefined;         // create a new checbox reference as undefined.
+                               if( this.checkboxRoot ) {
+                                       currState = this.root.checkbox = this.checkboxState;
+                               }
+                       } else {
+                               currState = this.root.checkbox;
+                       }
+               } else {        // a valid dojo.store.item
+                       currState = this.store.getValue(storeItem, this.checkboxIdent);
+                       if( currState == undefined && this.checkboxAll) {
+                               this._setCheckboxState( storeItem, this.checkboxState );
+                               currState = this.checkboxState;
+                       }
+               }
+               return currState  // the current state of the checkbox (true/false or undefined)
+       },
+
+       _setCheckboxState: function(/*dojo.data.Item*/ storeItem, /*Boolean*/ newState ) {
+               // summary:
+               //              Set/update the checkbox state on the dojo.data store.
+               // description:
+               //              Set/update the checkbox state on the dojo.data.store. Retreive the current
+               //              state of the checkbox and validate if an update is required, this will keep 
+               //              update events to a minimum. On completion a 'onCheckboxChange' event is
+               //              triggered. 
+               //              If the current state is undefined (ie: no checkbox attribute specified for 
+               //              this dojo.data.item) the 'checkboxAll' attribute is checked     to see if one 
+               //              needs to be created. In case of the root the 'checkboxRoot' attribute is checked.
+               //              NOTE: the store.setValue function will create the 'checkbox' attribute for the 
+               //              item if none exists.   
+               //      storeItem:
+               //              The item in the dojo.data.store whos checkbox state is updated.
+               //      newState:
+               //              The new state of the checkbox: true or false
+               //      example:
+               //      | model.setCheckboxState(item, true);
+               //
+               var stateChanged = true;
+               
+               if( storeItem != this.root ) {
+                       var currState = this.store.getValue(storeItem, this.checkboxIdent);
+                       if( currState != newState && ( currState !== undefined || this.checkboxAll ) ) {
+                               this.store.setValue(storeItem, this.checkboxIdent, newState);
+                       } else {
+                               stateChanged = false;   // No changes to the checkbox
+                       }
+               } else {  // Tree root instance
+                       if( this.root.checkbox != newState && ( this.root.checkbox !== undefined || this.checkboxRoot ) ) {
+                               this.root.checkbox = newState;
+                       } else {
+                               stateChanged = false;
+                       }
+               }
+               if( stateChanged ) {    // In case of any changes trigger the update event.
+                       this.onCheckboxChange(storeItem);
+               }
+               return stateChanged;
+       },
+       
+       _updateChildCheckbox: function(/*dojo.data.Item*/ parentItem, /*Boolean*/ newState ) {
+               //      summary:
+               //              Set all child checkboxes to true/false depending on the parent checkbox state.
+               //      description:
+               //              If a parent checkbox changes state, all child and grandchild checkboxes will be 
+               //              updated to reflect the change. For example, if the parent state is set to true, 
+               //              all child and grandchild checkboxes will receive that same 'true' state.
+               //              If a child checkbox changes state and has multiple parent, all of its parents
+               //              need to be re-evaluated.
+               //      parentItem:
+               //              The parent dojo.data.item whos child/grandchild checkboxes require updating.
+               //      newState:
+               //              The new state of the checkbox: true or false
+               //
+               if( this.mayHaveChildren( parentItem )) {
+                       this.getChildren( parentItem, dojo.hitch( this,
+                               function( children ) {
+                                       dojo.forEach( children, function(child) {
+                                               if( this._setCheckboxState(child, newState) ) {                                 
+                                                       var parents = this._getParentsItem(child);
+                                                       if( parents.length > 1 ) {
+                                                               this._updateParentCheckbox( child, newState );
+                                                       }
+                                               }
+                                               if( this.mayHaveChildren( child )) {
+                                                       this._updateChildCheckbox( child, newState );
+                                               }
+                                       }, this );
+                               }),
+                               function(err) {
+                                       console.error(this, ": updating child checkboxes: ", err);
+                               } 
+                       );
+               }
+       },
+
+       _updateParentCheckbox: function(/*dojo.data.Item*/ storeItem, /*Boolean*/ newState ) {
+               //      summary:
+               //              Update the parent checkbox state depending on the state of all child checkboxes.
+               //      description:
+               //              Update the parent checkbox state depending on the state of all child checkboxes.
+               //              The parent checkbox automatically changes state if ALL child checkboxes are true
+               //              or false. If, as a result, the parent checkbox changes state, we will check if 
+               //              its parent needs to be updated as well all the way upto the root.
+               //      storeItem:
+               //              The dojo.data.item whos parent checkboxes require updating.
+               //      newState:
+               //              The new state of the checkbox: true or false
+               //
+               var parents = this._getParentsItem(storeItem);
+               dojo.forEach( parents, function( parentItem ) {
+                       if( newState ) { // new state = true (checked)
+                               this.getChildren( parentItem, dojo.hitch( this,
+                                       function(siblings) {
+                                               var allChecked  = true;                 
+                                               dojo.some( siblings, function(sibling) {
+                                                       siblState = this.getCheckboxState(sibling);
+                                                       if( siblState !== undefined && allChecked )
+                                                               allChecked = siblState; 
+                                                       return !(allChecked);
+                                               }, this );
+                                               if( allChecked ) {
+                                                       this._setCheckboxState( parentItem, true );
+                                                       this._updateParentCheckbox( parentItem, true );
+                                               }
+                                       }),
+                                       function(err) {
+                                               console.error(this, ": updating parent checkboxes: ", err);
+                                       }
+                               );
+                       } else {        // new state = false (unchecked)
+                               if( this._setCheckboxState( parentItem, false ) ) {
+                                       this._updateParentCheckbox( parentItem, false );
+                               }
+                       }
+               }, this );
+       },
+       
+       _getParentsItem: function(/*dojo.data.Item*/ storeItem ) {
+               // summary:
+               //              Get the parent(s) of a dojo.data item.  
+               // description:
+               //              Get the parent(s) of a dojo.data item. The '_reverseRefMap' entry of the item is
+               //              used to identify the parent(s). A child will have a parent reference if the parent 
+               //              specified the '_reference' attribute. 
+               //              For example: children:[{_reference:'Mexico'}, {_reference:'Canada'}, ...
+               //      storeItem:
+               //              The dojo.data.item whos parent(s) will be returned.
+               //
+               var parents = [];
+
+               if( storeItem != this.root ) {
+                       var references = storeItem[this.store._reverseRefMap];
+                       for(itemId in references ) {
+                               parents.push(this.store._itemsByIdentity[itemId]);
+                       }
+                       if (!parents.length) {
+                               parents.push(this.root);
+                       }
+               }
+               return parents // parent(s) of a dojo.data.item (Array of dojo.data.items)
+       },
+
+       validateData: function(/*dojo.data.Item*/ storeItem, /*thisObject*/ scope ) {
+               // summary:
+               //              Validate/normalize the parent(s) checkbox data in the dojo.data store.
+               // description:
+               //              Validate/normalize the parent-child checkbox relationship if the attribute
+               //              'checkboxStrict' is set to true. This function is called as part of the post 
+               //              creation of the Tree instance. All parent checkboxes are set to the appropriate
+               //              state according to the actual state(s) of their children. 
+               //              This will potentionally overwrite whatever was specified for the parent in the
+               //              dojo.data store. This will garantee the tree is in a consistent state after startup.
+               //      storeItem:
+               //              The element to start traversing the dojo.data.store, typically model.root
+               //      scope:
+               //              The scope to use when this method executes.
+               //      example:
+               //      | this.model.validateData(this.model.root, this.model);
+               //
+               if( !scope.checkboxStrict ) {
+                       return;
+               }
+               scope.getChildren( storeItem, dojo.hitch( scope,
+                       function(children) {
+                               var allChecked  = true;
+                               var childState;
+                               dojo.forEach( children, function( child ) {
+                                       if( this.mayHaveChildren( child )) {
+                                               this.validateData( child, this );
+                                       }
+                                       childState = this.getCheckboxState( child );
+                                       if( childState !== undefined && allChecked )
+                                               allChecked = childState; 
+                               }, this);
+
+                               if ( this._setCheckboxState( storeItem, allChecked) ) {
+                                       this._updateParentCheckbox( storeItem, allChecked);
+                               }
+                       }),
+                       function(err) {
+                               console.error(this, ": validating checkbox data: ", err);
+                       } 
+               );
+       },
+
+       onCheckboxChange: function(/*dojo.data.Item*/ storeItem ) {
+               // summary:
+               //              Callback whenever a checkbox state has changed state, so that 
+               //              the Tree can update the checkbox.  This callback is generally
+               //              triggered by the '_setCheckboxState' function. 
+               // tags:
+               //              callback
+       }
+               
+});
+
+dojo.declare( "lib._CheckBoxTreeNode", dijit._TreeNode,
+{
+       // _checkbox: [protected] dojo.doc.element
+       //              Local reference to the dojo.doc.element of type 'checkbox'
+       _checkbox: null,
+
+       _createCheckbox: function() {
+               // summary:
+               //              Create a checkbox on the CheckBoxTreeNode
+               // description:
+               //              Create a checkbox on the CheckBoxTreeNode. The checkbox is ONLY created if a
+               //              valid reference was found in the dojo.data store or the attribute 'checkboxAll'
+               //              is set to true. If the current state is 'undefined' no reference was found and 
+               //              'checkboxAll' is set to false.
+               //              Note: the attribute 'checkboxAll' is validated by the getCheckboxState function
+               //              therefore no need to do that here. (see getCheckboxState for details).
+               //              
+               var     currState = this.tree.model.getCheckboxState( this.item );
+               if( currState !== undefined ) {
+                       this._checkbox = new dijit.form.CheckBox();
+                       //this._checkbox = dojo.doc.createElement('input');
+                       this._checkbox.type    = 'checkbox';
+                       this._checkbox.attr('checked', currState);
+                       dojo.place(this._checkbox.domNode, this.expandoNode, 'after');
+               }
+       },
+       
+       postCreate: function() {
+               // summary:
+               //              Handle the creation of the checkbox after the CheckBoxTreeNode has been instanciated.
+               // description:
+               //              Handle the creation of the checkbox after the CheckBoxTreeNode has been instanciated.
+               this._createCheckbox();
+               this.inherited( arguments );
+       }
+
+});
+
+dojo.declare( "lib.CheckBoxTree", dijit.Tree,
+{
+       
+       onNodeChecked: function(/*dojo.data.Item*/ storeItem, /*treeNode*/ treeNode) {
+               // summary:
+               //              Callback when a checkbox tree node is checked
+               // tags:
+               //              callback
+       },
+       
+       onNodeUnchecked: function(/*dojo.data.Item*/ storeItem, /* treeNode */ treeNode) {
+               // summary:
+               //              Callback when a checkbox tree node is unchecked
+               // tags:
+               //              callback
+       },
+       
+       _onClick: function(/*TreeNode*/ nodeWidget, /*Event*/ e) {
+               // summary:
+               //              Translates click events into commands for the controller to process
+               // description:
+               //              the _onClick function is called whenever a 'click' is detected. This
+               //              instance of _onClick only handles the click events associated with
+               //              the checkbox whos DOM name is INPUT.
+               // 
+               var domElement = e.target;
+
+               // Only handle checkbox clicks here
+               if(domElement.type != 'checkbox') {
+                       return this.inherited( arguments );
+               }
+
+               this._publish("execute", { item: nodeWidget.item, node: nodeWidget} );
+               // Go tell the model to update the checkbox state
+               
+               this.model.updateCheckbox( nodeWidget.item, nodeWidget._checkbox.checked ); 
+               // Generate some additional events
+               //this.onClick( nodeWidget.item, nodeWidget, e );
+               if(nodeWidget._checkbox.checked) {
+                       this.onNodeChecked( nodeWidget.item, nodeWidget);
+               } else {
+                       this.onNodeUnchecked( nodeWidget.item, nodeWidget);
+               }
+               this.focusNode(nodeWidget);
+       },
+       
+       _onCheckboxChange: function(/*dojo.data.Item*/ storeItem ) {
+               // summary:
+               //              Processes notification of a change to a checkbox state (triggered by the model).
+               // description:
+               //              Whenever the model changes the state of a checkbox in the dojo.data.store it will 
+               //              trigger the 'onCheckboxChange' event allowing the Tree to make the same changes 
+               //              on the tree Node. There are several conditions why a tree node or checkbox does not
+               //              exists:
+               //              a)      The node has not been created yet (the user has not expanded the tree node yet).
+               //              b)      The checkbox may be null if condition (a) exists or no 'checkbox' attribute was
+               //                      specified for the associated dojo.data.item and the attribute 'checkboxAll' is 
+               //                      set to false. 
+               // tags:
+               //              callback
+               var model        = this.model,
+                       identity = model.getIdentity(storeItem),
+                       nodes    = this._itemNodesMap[identity];
+
+               // As of dijit.Tree 1.4 multiple references (parents) are supported, therefore we may have
+               // to update multiple nodes which are all associated with the same dojo.data.item.
+               if( nodes ) {
+                       dojo.forEach( nodes, function(node) {
+                               if( node._checkbox != null ) {
+                                       node._checkbox.attr('checked', this.model.getCheckboxState( storeItem ));
+                               }
+                       }, this );
+               }
+       }, 
+
+       postCreate: function() {
+               // summary:
+               //              Handle any specifics related to the tree and model after the instanciation of the Tree. 
+               // description:
+               //              Validate if we have a 'write' store first. Subscribe to the 'onCheckboxChange' event 
+               //              (triggered by the model) and kickoff the initial checkbox data validation.
+               //
+               var store = this.model.store;
+               if(!store.getFeatures()['dojo.data.api.Write']){
+                       throw new Error("lib.CheckboxTree: store must support dojo.data.Write");
+               }
+               this.connect(this.model, "onCheckboxChange", "_onCheckboxChange");
+               this.model.validateData( this.model.root, this.model );
+               this.inherited(arguments);
+       },
+
+       _createTreeNode: function( args ) {
+               // summary:
+               //              Create a new CheckboxTreeNode instance.
+               // description:
+               //              Create a new CheckboxTreeNode instance.
+               return new lib._CheckBoxTreeNode(args);
+       }
+
+});
index d8df49ab3053dd2d3e9424f76c34ca35db476633..783dd34a1445bb64e7c84d0e2828bf73d8a2f6f1 100644 (file)
 
                print "<div dojoType=\"dijit.Toolbar\">";
 
+               /* 
                print "<div style='float : right'> 
                        <input id=\"feed_search\" size=\"20\" type=\"search\"
                                onfocus=\"disableHotkeys();\" 
                                onchange=\"updateFeedList()\" value=\"$feed_search\">
                        <button onclick=\"updateFeedList()\">".
                                __('Search')."</button>
-                       </div>";
-               
-               print "<button onclick=\"quickAddFeed()\">"
-                       .__('Subscribe to feed')."</button> ";
+                               </div>"; */
+
+               print "<div dojoType=\"dijit.form.DropDownButton\">".
+                       "<span>" . __('Select')."</span>";
+
+               print "<div dojoType=\"dijit.Menu\" style=\"display: none;\">";
+               print "<div onclick=\"dijit.byId('feedTree').model.setAllChecked(true)\" 
+                       dojoType=\"dijit.MenuItem\">".__('All')."</div>";
+               print "<div onclick=\"dijit.byId('feedTree').model.setAllChecked(false)\" 
+                       dojoType=\"dijit.MenuItem\">".__('None')."</div>";
+               print "</div>";
+
+               /* print "<div onclick=\"selectTableRows('prefFeedList', 'all')\">".__('All')."</div>,
+                       <div href=\"#\" onclick=\"selectTableRows('prefFeedList', 'none')\">".__('None')."</div>"; */
+
+               print "</div>";
 
-               print "<button onclick=\"editSelectedFeed()\">".
-                       __('Edit feeds')."</button> ";
+               print "<button dojoType=\"dijit.form.Button\" onclick=\"quickAddFeed()\">"
+                       .__('Subscribe to feed')."</button dojoType=\"dijit.form.Button\"> ";
+
+               print "<button dojoType=\"dijit.form.Button\" onclick=\"editSelectedFeed()\">".
+                       __('Edit feeds')."</button dojoType=\"dijit.form.Button\"> ";
 
                if (get_pref($link, 'ENABLE_FEED_CATS')) {
 
-                       print "<button onclick=\"editFeedCats()\">".
-                               __('Edit categories')."</button> ";
+                       print "<button dojoType=\"dijit.form.Button\" onclick=\"editFeedCats()\">".
+                               __('Edit categories')."</button dojoType=\"dijit.form.Button\"> ";
                }
 
-               print "<button onclick=\"removeSelectedFeeds()\">"
-                       .__('Unsubscribe')."</button> ";
+               print "<button dojoType=\"dijit.form.Button\" onclick=\"removeSelectedFeeds()\">"
+                       .__('Unsubscribe')."</button dojoType=\"dijit.form.Button\"> ";
 
                if (defined('_ENABLE_FEED_DEBUGGING')) {
 
 
                print "</div>"; # toolbar
 
+               print "<div id=\"feedlistLoading\">
+               <img src='images/indicator_tiny.gif'>".
+                __("Loading, please wait...")."</div>";
+
+               print "<div dojoType=\"dojo.data.ItemFileWriteStore\" jsId=\"feedStore\" 
+                       url=\"backend.php?op=feeds&root=1\">
+               </div>
+               <div dojoType=\"lib.CheckBoxStoreModel\" jsId=\"feedModel\" store=\"feedStore\"
+               query=\"{id:'root'}\" rootId=\"root\" rootLabel=\"Feeds\"
+                       childrenAttrs=\"items\" checkboxStrict=\"false\" checkboxAll=\"false\">
+               </div>
+               <div dojoType=\"lib.CheckBoxTree\" id=\"feedTree\" _dndController=\"dijit.tree.dndSource\" 
+                       betweenThreshold=\"1\"
+                       model=\"feedModel\" openOnClick=\"false\">
+               <script type=\"dojo/method\" event=\"onClick\" args=\"item\">
+                       var id = String(item.id);
+                       var bare_id = id.substr(id.indexOf(':')+1);
+
+                       console.log('onClick: ' + id);
+
+                       if (id.match('FEED')) {
+                               editFeed(bare_id, event);
+                       }
+                       
+               </script>
+               <script type=\"dojo/method\" event=\"onLoad\" args=\"item\">
+                       Element.hide(\"feedlistLoading\");
+               </script>
+               <script type=\"dojo/method\" event=\"checkItemAcceptance\" args=\"item, source, position\">
+                       var source_item = dijit.getEnclosingWidget(source);
+                       console.log(item);
+                       console.log(source_item);
+               </script>
+
+               </div>";
+
+               /*
                $feeds_sort = db_escape_string($_REQUEST["sort"]);
 
                if (!$feeds_sort || $feeds_sort == "undefined") {
                        }
                        print "</p>";
 
-               }
+               } */
 
                print "</div>"; # feeds pane
 
index 7b64b2a8f997a781d0dd1d9cf1ca8d17ac2ba9c5..d21f353350eea126c9f510c06a78c1b85fdca5af 100644 (file)
                print "<div id=\"pref-filter-toolbar\" dojoType=\"dijit.Toolbar\">";
 
                print "<div style='float : right; padding-right : 4px;'>
-                       <input id=\"filter_search\" size=\"20\" type=\"search\"
+                       <input dojoType=\"dijit.form.TextBox\" id=\"filter_search\" size=\"20\" type=\"search\"
                                onfocus=\"javascript:disableHotkeys();\" 
                                onblur=\"javascript:enableHotkeys();\"
                                onchange=\"javascript:updateFilterList()\" value=\"$filter_search\">
-                       <button onclick=\"javascript:updateFilterList()\">".__('Search')."</button>
+                       <button dojoType=\"dijit.form.Button\" onclick=\"javascript:updateFilterList()\">".__('Search')."</button>
                </div>";
 
-               print "<button onclick=\"return quickAddFilter()\">".
-                       __('Create filter')."</button> "; 
+               print "<button dojoType=\"dijit.form.Button\" onclick=\"return quickAddFilter()\">".
+                       __('Create filter')."</button dojoType=\"dijit.form.Button\"> "; 
 
-               print "<button onclick=\"return editSelectedFilter()\">".
-                       __('Edit')."</button> ";
+               print "<button dojoType=\"dijit.form.Button\" onclick=\"return editSelectedFilter()\">".
+                       __('Edit')."</button dojoType=\"dijit.form.Button\"> ";
 
-               print "<button onclick=\"return removeSelectedFilters()\">".
-                       __('Remove')."</button> ";
+               print "<button dojoType=\"dijit.form.Button\" onclick=\"return removeSelectedFilters()\">".
+                       __('Remove')."</button dojoType=\"dijit.form.Button\"> ";
 
                if (defined('_ENABLE_FEED_DEBUGGING')) {
-                       print "<button onclick=\"rescore_all_feeds()\">".
-                               __('Rescore articles')."</button> "; 
+                       print "<button dojoType=\"dijit.form.Button\" onclick=\"rescore_all_feeds()\">".
+                               __('Rescore articles')."</button dojoType=\"dijit.form.Button\"> "; 
                }
 
                print "</div>"; # toolbar
index e683ab6154491206b56f9c1a09bd7f4fed9daae5..c794e023ecd7d3ce635e9d4316169dd950e9a7e2 100644 (file)
 
                                if (label_create($link, $caption)) {
                                        if (!$output) {
-                                               print T_sprintf("Created label <b>%s</b>", htmlspecialchars($caption));
+                                               //print T_sprintf("Created label <b>%s</b>", htmlspecialchars($caption));
                                        }
                                }
 
 
                print "<div style='float : right; padding-right : 4px'>
                        <input id=\"label_search\" size=\"20\" type=\"search\"
+                               dojoType=\"dijit.form.TextBox\"
                                onfocus=\"javascript:disableHotkeys();\" 
                                onblur=\"javascript:enableHotkeys();\"
                                onchange=\"javascript:updateLabelList()\" value=\"$label_search\">
-                       <button onclick=\"javascript:updateLabelList()\">".__('Search')."</button>
+                       <button dojoType=\"dijit.form.Button\" onclick=\"javascript:updateLabelList()\">".__('Search')."</button>
                        </div>";
 
-               print"<button onclick=\"return addLabel()\">".
-                       __('Create label')."</button> ";
+               print"<button dojoType=\"dijit.form.Button\" onclick=\"return addLabel()\">".
+                       __('Create label')."</button dojoType=\"dijit.form.Button\"> ";
 
-               print "<button onclick=\"removeSelectedLabels()\">".
-                       __('Remove')."</button> ";
+               print "<button dojoType=\"dijit.form.Button\" onclick=\"removeSelectedLabels()\">".
+                       __('Remove')."</button dojoType=\"dijit.form.Button\"> ";
 
-               print "<button onclick=\"labelColorReset()\">".
-                       __('Clear colors')."</button>";
+               print "<button dojoType=\"dijit.form.Button\" onclick=\"labelColorReset()\">".
+                       __('Clear colors')."</button dojoType=\"dijit.form.Button\">";
 
 
                print "</div>"; #toolbar
index 2f8240926d52c8f299cec5e8f52fe1ea6c25a294..3bdf36bc6b9889521cab5866e8a71b5d4a4dc8cf 100644 (file)
--- a/prefs.js
+++ b/prefs.js
@@ -395,8 +395,8 @@ function editFeed(feed, event) {
        
                        notify_progress("Loading, please wait...");
 
-                       selectTableRows('prefFeedList', 'none');        
-                       selectTableRowById('FEEDR-'+feed, 'FRCHK-'+feed, true);
+//                     selectTableRows('prefFeedList', 'none');        
+//                     selectTableRowById('FEEDR-'+feed, 'FRCHK-'+feed, true);
        
                        var query = "?op=pref-feeds&subop=editfeed&id=" +
                                param_escape(feed);
@@ -409,9 +409,9 @@ function editFeed(feed, event) {
                                        } });
 
                } else if (event.ctrlKey) {
-                       var cb = $('FRCHK-' + feed);
-                       cb.checked = !cb.checked;
-                       toggleSelectRow(cb);
+//                     var cb = $('FRCHK-' + feed);
+//                     cb.checked = !cb.checked;
+//                     toggleSelectRow(cb);
                }
 
 
@@ -429,7 +429,15 @@ function getSelectedUsers() {
 }
 
 function getSelectedFeeds() {
-       return getSelectedTableRowIds("prefFeedList");
+       var tree = dijit.byId("feedTree");
+       var items = tree.model.getCheckedItems();
+       var rv = [];
+
+       items.each(function(item) {
+               rv.push(tree.model.store.getValue(item, 'bare_id'));
+       });
+
+       return rv;
 }
 
 function getSelectedFilters() {
@@ -1156,7 +1164,17 @@ function init() {
                dojo.require("dijit.layout.ContentPane");
                dojo.require("dijit.Dialog");
                dojo.require("dijit.form.Button");
+               dojo.require("dijit.form.TextBox");
                dojo.require("dijit.Toolbar");
+               dojo.require("dojo.data.ItemFileWriteStore");
+               dojo.require("dijit.Tree");
+               dojo.require("dijit.form.DropDownButton");
+               dojo.require("dijit.Menu");
+               dojo.require("dijit.tree.dndSource");
+
+               dojo.registerModulePath("lib", "..");
+
+               dojo.require("lib.CheckBoxTree");
 
                loading_set_progress(30);