浏览代码

switch modules to new dojo definition format

Andrew Dolgov 8 年之前
父节点
当前提交
d39a2f8005
共有 7 个文件被更改,包括 1210 次插入1193 次删除
  1. 506 504
      js/FeedTree.js
  2. 115 114
      js/PrefFeedTree.js
  3. 94 88
      js/PrefFilterTree.js
  4. 31 31
      js/PrefLabelTree.js
  5. 4 7
      js/prefs.js
  6. 2 3
      js/tt-rss.js
  7. 458 446
      lib/CheckBoxTree.js

+ 506 - 504
js/FeedTree.js

@@ -1,589 +1,591 @@
-dojo.provide("fox.FeedTree");
-dojo.provide("fox.FeedStoreModel");
-
-dojo.require("dijit.Tree");
-dojo.require("dijit.Menu");
-
-dojo.declare("fox.FeedStoreModel", dijit.tree.ForestStoreModel, {
-	getItemsInCategory: function (id) {
-		if (!this.store._itemsByIdentity) return undefined;
-
-		cat = this.store._itemsByIdentity['CAT:' + id];
-
-		if (cat && cat.items)
-			return cat.items;
-		else
-			return undefined;
-
-	},
-	getItemById: function(id) {
-		return this.store._itemsByIdentity[id];
-	},
-	getFeedValue: function(feed, is_cat, key) {
-		if (!this.store._itemsByIdentity) return undefined;
-
-		if (is_cat)
-			treeItem = this.store._itemsByIdentity['CAT:' + feed];
-		else
-			treeItem = this.store._itemsByIdentity['FEED:' + feed];
-
-		if (treeItem)
-			return this.store.getValue(treeItem, key);
-	},
-	getFeedName: function(feed, is_cat) {
-		return this.getFeedValue(feed, is_cat, 'name');
-	},
-	getFeedUnread: function(feed, is_cat) {
-		var unread = parseInt(this.getFeedValue(feed, is_cat, 'unread'));
-		return (isNaN(unread)) ? 0 : unread;
-	},
-	setFeedUnread: function(feed, is_cat, unread) {
-		return this.setFeedValue(feed, is_cat, 'unread', parseInt(unread));
-	},
-	setFeedValue: function(feed, is_cat, key, value) {
-		if (!value) value = '';
-		if (!this.store._itemsByIdentity) return undefined;
-
-		if (is_cat)
-			treeItem = this.store._itemsByIdentity['CAT:' + feed];
-		else
-			treeItem = this.store._itemsByIdentity['FEED:' + feed];
-
-		if (treeItem)
-			return this.store.setValue(treeItem, key, value);
-	},
-	getNextUnreadFeed: function (feed, is_cat) {
-		if (!this.store._itemsByIdentity)
-			return null;
+require(["dojo/_base/declare", "dijit/tree/ForestStoreModel"], function (declare) {
+
+	return declare("fox.FeedStoreModel", dijit.tree.ForestStoreModel, {
+		getItemsInCategory: function (id) {
+			if (!this.store._itemsByIdentity) return undefined;
+
+			cat = this.store._itemsByIdentity['CAT:' + id];
+
+			if (cat && cat.items)
+				return cat.items;
+			else
+				return undefined;
+
+		},
+		getItemById: function (id) {
+			return this.store._itemsByIdentity[id];
+		},
+		getFeedValue: function (feed, is_cat, key) {
+			if (!this.store._itemsByIdentity) return undefined;
+
+			if (is_cat)
+				treeItem = this.store._itemsByIdentity['CAT:' + feed];
+			else
+				treeItem = this.store._itemsByIdentity['FEED:' + feed];
+
+			if (treeItem)
+				return this.store.getValue(treeItem, key);
+		},
+		getFeedName: function (feed, is_cat) {
+			return this.getFeedValue(feed, is_cat, 'name');
+		},
+		getFeedUnread: function (feed, is_cat) {
+			var unread = parseInt(this.getFeedValue(feed, is_cat, 'unread'));
+			return (isNaN(unread)) ? 0 : unread;
+		},
+		setFeedUnread: function (feed, is_cat, unread) {
+			return this.setFeedValue(feed, is_cat, 'unread', parseInt(unread));
+		},
+		setFeedValue: function (feed, is_cat, key, value) {
+			if (!value) value = '';
+			if (!this.store._itemsByIdentity) return undefined;
+
+			if (is_cat)
+				treeItem = this.store._itemsByIdentity['CAT:' + feed];
+			else
+				treeItem = this.store._itemsByIdentity['FEED:' + feed];
+
+			if (treeItem)
+				return this.store.setValue(treeItem, key, value);
+		},
+		getNextUnreadFeed: function (feed, is_cat) {
+			if (!this.store._itemsByIdentity)
+				return null;
 
-		if (is_cat) {
-			treeItem = this.store._itemsByIdentity['CAT:' + feed];
-		} else {
-			treeItem = this.store._itemsByIdentity['FEED:' + feed];
-		}
+			if (is_cat) {
+				treeItem = this.store._itemsByIdentity['CAT:' + feed];
+			} else {
+				treeItem = this.store._itemsByIdentity['FEED:' + feed];
+			}
 
-		items = this.store._arrayOfAllItems;
+			items = this.store._arrayOfAllItems;
 
-		for (var i = 0; i < items.length; i++) {
-			if (items[i] == treeItem) {
+			for (var i = 0; i < items.length; i++) {
+				if (items[i] == treeItem) {
 
-				for (var j = i+1; j < items.length; j++) {
-					var unread = this.store.getValue(items[j], 'unread');
-					var id = this.store.getValue(items[j], 'id');
+					for (var j = i + 1; j < items.length; j++) {
+						var unread = this.store.getValue(items[j], 'unread');
+						var id = this.store.getValue(items[j], 'id');
 
-					if (unread > 0 && ((is_cat && id.match("CAT:")) || (!is_cat && id.match("FEED:")))) {
-						if( !is_cat || ! (this.store.hasAttribute(items[j], 'parent_id') && this.store.getValue(items[j], 'parent_id') == feed) ) return items[j];
+						if (unread > 0 && ((is_cat && id.match("CAT:")) || (!is_cat && id.match("FEED:")))) {
+							if (!is_cat || !(this.store.hasAttribute(items[j], 'parent_id') && this.store.getValue(items[j], 'parent_id') == feed)) return items[j];
+						}
 					}
-				}
 
-				for (var j = 0; j < i; j++) {
-					var unread = this.store.getValue(items[j], 'unread');
-					var id = this.store.getValue(items[j], 'id');
+					for (var j = 0; j < i; j++) {
+						var unread = this.store.getValue(items[j], 'unread');
+						var id = this.store.getValue(items[j], 'id');
 
-					if (unread > 0 && ((is_cat && id.match("CAT:")) || (!is_cat && id.match("FEED:")))) {
-						if( !is_cat || ! (this.store.hasAttribute(items[j], 'parent_id') && this.store.getValue(items[j], 'parent_id') == feed) ) return items[j];
+						if (unread > 0 && ((is_cat && id.match("CAT:")) || (!is_cat && id.match("FEED:")))) {
+							if (!is_cat || !(this.store.hasAttribute(items[j], 'parent_id') && this.store.getValue(items[j], 'parent_id') == feed)) return items[j];
+						}
 					}
 				}
 			}
-		}
-
-		return null;
-	},
-	hasCats: function() {
-		if (this.store && this.store._itemsByIdentity)
-			return this.store._itemsByIdentity['CAT:-1'] != undefined;
-		else
-			return false;
-	},
+
+			return null;
+		},
+		hasCats: function () {
+			if (this.store && this.store._itemsByIdentity)
+				return this.store._itemsByIdentity['CAT:-1'] != undefined;
+			else
+				return false;
+		},
+
+	});
 });
 
-dojo.declare("fox.FeedTree", dijit.Tree, {
-	_onKeyPress: function(/* Event */ e) {
-		return; // Stop dijit.Tree from interpreting keystrokes
-	},
-	_createTreeNode: function(args) {
-		var tnode = new dijit._TreeNode(args);
+require(["dojo/_base/declare", "dijit/Tree", "dijit/Menu"], function (declare) {
 
-		if (args.item.icon && args.item.icon[0])
-			tnode.iconNode.src = args.item.icon[0];
+	return declare("fox.FeedTree", dijit.Tree, {
+		_onKeyPress: function(/* Event */ e) {
+			return; // Stop dijit.Tree from interpreting keystrokes
+		},
+		_createTreeNode: function(args) {
+			var tnode = new dijit._TreeNode(args);
 
-		var id = args.item.id[0];
-		var bare_id = parseInt(id.substr(id.indexOf(':')+1));
+			if (args.item.icon && args.item.icon[0])
+				tnode.iconNode.src = args.item.icon[0];
 
-		if (bare_id < _label_base_index) {
-			var span = dojo.doc.createElement('span');
-			var fg_color = args.item.fg_color[0];
-			var bg_color = args.item.bg_color[0];
+			var id = args.item.id[0];
+			var bare_id = parseInt(id.substr(id.indexOf(':')+1));
 
-			span.innerHTML = "&alpha;";
-			span.className = 'labelColorIndicator';
-			span.setStyle({
-				color: fg_color,
-				backgroundColor: bg_color});
+			if (bare_id < _label_base_index) {
+				var span = dojo.doc.createElement('span');
+				var fg_color = args.item.fg_color[0];
+				var bg_color = args.item.bg_color[0];
 
-			dojo.place(span, tnode.iconNode, 'replace');
-		}
+				span.innerHTML = "&alpha;";
+				span.className = 'labelColorIndicator';
+				span.setStyle({
+					color: fg_color,
+					backgroundColor: bg_color});
 
-		if (id.match("FEED:")) {
-			var menu = new dijit.Menu();
-			menu.row_id = bare_id;
+				dojo.place(span, tnode.iconNode, 'replace');
+			}
 
-			menu.addChild(new dijit.MenuItem({
-				label: __("Mark as read"),
-				onClick: function() {
-					catchupFeed(this.getParent().row_id);
-				}}));
+			if (id.match("FEED:")) {
+				var menu = new dijit.Menu();
+				menu.row_id = bare_id;
 
-			if (bare_id > 0) {
 				menu.addChild(new dijit.MenuItem({
-					label: __("Edit feed"),
+					label: __("Mark as read"),
 					onClick: function() {
-						editFeed(this.getParent().row_id, false);
+						catchupFeed(this.getParent().row_id);
 					}}));
 
-				/* menu.addChild(new dijit.MenuItem({
-					label: __("Update feed"),
+				if (bare_id > 0) {
+					menu.addChild(new dijit.MenuItem({
+						label: __("Edit feed"),
+						onClick: function() {
+							editFeed(this.getParent().row_id, false);
+						}}));
+
+					/* menu.addChild(new dijit.MenuItem({
+					 label: __("Update feed"),
+					 onClick: function() {
+					 heduleFeedUpdate(this.getParent().row_id, false);
+					 }})); */
+				}
+
+				menu.bindDomNode(tnode.domNode);
+				tnode._menu = menu;
+			}
+
+			if (id.match("CAT:") && bare_id >= 0) {
+				var menu = new dijit.Menu();
+				menu.row_id = bare_id;
+
+				menu.addChild(new dijit.MenuItem({
+					label: __("Mark as read"),
 					onClick: function() {
-						heduleFeedUpdate(this.getParent().row_id, false);
-					}})); */
+						catchupFeed(this.getParent().row_id, true);
+					}}));
+
+				menu.bindDomNode(tnode.domNode);
+				tnode._menu = menu;
 			}
 
-			menu.bindDomNode(tnode.domNode);
-			tnode._menu = menu;
-		}
-
-		if (id.match("CAT:") && bare_id >= 0) {
-			var menu = new dijit.Menu();
-			menu.row_id = bare_id;
-
-			menu.addChild(new dijit.MenuItem({
-				label: __("Mark as read"),
-				onClick: function() {
-					catchupFeed(this.getParent().row_id, true);
-				}}));
-
-			menu.bindDomNode(tnode.domNode);
-			tnode._menu = menu;
-		}
-
-		if (id.match("CAT:")) {
-			loading = dojo.doc.createElement('img');
-			loading.className = 'loadingNode';
-			loading.src = 'images/blank_icon.gif';
-			dojo.place(loading, tnode.labelNode, 'after');
-			tnode.loadingNode = loading;
-		}
-
-		if (id.match("CAT:") && bare_id == -1) {
-			var menu = new dijit.Menu();
-			menu.row_id = bare_id;
-
-			menu.addChild(new dijit.MenuItem({
-				label: __("Mark all feeds as read"),
-				onClick: function() {
-					catchupAllFeeds();
-				}}));
-
-			menu.bindDomNode(tnode.domNode);
-			tnode._menu = menu;
-		}
-
-		ctr = dojo.doc.createElement('span');
-		ctr.className = 'counterNode';
-		ctr.innerHTML = args.item.unread > 0 ? args.item.unread : args.item.auxcounter;
-
-		//args.item.unread > 0 ? ctr.addClassName("unread") : ctr.removeClassName("unread");
-
-		args.item.unread > 0 || args.item.auxcounter > 0 ? Element.show(ctr) : Element.hide(ctr);
-
-		args.item.unread == 0 && args.item.auxcounter > 0 ? ctr.addClassName("aux") : ctr.removeClassName("aux");
-
-		dojo.place(ctr, tnode.rowNode, 'first');
-		tnode.counterNode = ctr;
-
-		//tnode.labelNode.innerHTML = args.label;
-		return tnode;
-	},
-	postCreate: function() {
-		this.connect(this.model, "onChange", "updateCounter");
-		this.connect(this, "_expandNode", function() {
-			this.hideRead(getInitParam("hide_read_feeds"), getInitParam("hide_read_shows_special"));
-		});
-
-		this.inherited(arguments);
-	},
-	updateCounter: function (item) {
-		var tree = this;
-
-		//console.log("updateCounter: " + item.id[0] + " " + item.unread + " " + tree);
-
-		var node = tree._itemNodesMap[item.id];
-
-		if (node) {
-			node = node[0];
-
-			if (node.counterNode) {
-				ctr = node.counterNode;
-				ctr.innerHTML = item.unread > 0 ? item.unread : item.auxcounter;
-				item.unread > 0 || item.auxcounter > 0 ?
-					Effect.Appear(ctr, {duration : 0.3,
-					queue: { position: 'end', scope: 'CAPPEAR-' + item.id, limit: 1 }}) :
-						Element.hide(ctr);
+			if (id.match("CAT:")) {
+				loading = dojo.doc.createElement('img');
+				loading.className = 'loadingNode';
+				loading.src = 'images/blank_icon.gif';
+				dojo.place(loading, tnode.labelNode, 'after');
+				tnode.loadingNode = loading;
+			}
 
-				item.unread == 0 && item.auxcounter > 0 ? ctr.addClassName("aux") : ctr.removeClassName("aux");
+			if (id.match("CAT:") && bare_id == -1) {
+				var menu = new dijit.Menu();
+				menu.row_id = bare_id;
 
+				menu.addChild(new dijit.MenuItem({
+					label: __("Mark all feeds as read"),
+					onClick: function() {
+						catchupAllFeeds();
+					}}));
+
+				menu.bindDomNode(tnode.domNode);
+				tnode._menu = menu;
 			}
-		}
-
-	},
-	getTooltip: function (item) {
-		if (item.updated)
-			return item.updated;
-		else
-			return "";
-	},
-	getIconClass: function (item, opened) {
-		return (!item || this.model.mayHaveChildren(item)) ? (opened ? "dijitFolderOpened" : "dijitFolderClosed") : "feedIcon";
-	},
-	getLabelClass: function (item, opened) {
-		return (item.unread == 0) ? "dijitTreeLabel" : "dijitTreeLabel Unread";
-	},
-	getRowClass: function (item, opened) {
-		var rc = (!item.error || item.error == '') ? "dijitTreeRow" :
-			"dijitTreeRow Error";
-
-		if (item.unread > 0) rc += " Unread";
-
-		return rc;
-	},
-	getLabel: function(item) {
-		var name = String(item.name);
-
-		/* Horrible */
-		name = name.replace(/&quot;/g, "\"");
-		name = name.replace(/&amp;/g, "&");
-		name = name.replace(/&mdash;/g, "-");
-		name = name.replace(/&lt;/g, "<");
-		name = name.replace(/&gt;/g, ">");
-
-		/* var label;
-
-		if (item.unread > 0) {
-			label = name + " (" + item.unread + ")";
-		} else {
-			label = name;
-		} */
-
-		return name;
-	},
-	expandParentNodes: function(feed, is_cat, list) {
-		try {
-			for (var i = 0; i < list.length; i++) {
-				var id = String(list[i].id);
-				var item = this._itemNodesMap[id];
-
-				if (item) {
-					item = item[0];
-					this._expandNode(item);
+
+			ctr = dojo.doc.createElement('span');
+			ctr.className = 'counterNode';
+			ctr.innerHTML = args.item.unread > 0 ? args.item.unread : args.item.auxcounter;
+
+			//args.item.unread > 0 ? ctr.addClassName("unread") : ctr.removeClassName("unread");
+
+			args.item.unread > 0 || args.item.auxcounter > 0 ? Element.show(ctr) : Element.hide(ctr);
+
+			args.item.unread == 0 && args.item.auxcounter > 0 ? ctr.addClassName("aux") : ctr.removeClassName("aux");
+
+			dojo.place(ctr, tnode.rowNode, 'first');
+			tnode.counterNode = ctr;
+
+			//tnode.labelNode.innerHTML = args.label;
+			return tnode;
+		},
+		postCreate: function() {
+			this.connect(this.model, "onChange", "updateCounter");
+			this.connect(this, "_expandNode", function() {
+				this.hideRead(getInitParam("hide_read_feeds"), getInitParam("hide_read_shows_special"));
+			});
+
+			this.inherited(arguments);
+		},
+		updateCounter: function (item) {
+			var tree = this;
+
+			//console.log("updateCounter: " + item.id[0] + " " + item.unread + " " + tree);
+
+			var node = tree._itemNodesMap[item.id];
+
+			if (node) {
+				node = node[0];
+
+				if (node.counterNode) {
+					ctr = node.counterNode;
+					ctr.innerHTML = item.unread > 0 ? item.unread : item.auxcounter;
+					item.unread > 0 || item.auxcounter > 0 ?
+						Effect.Appear(ctr, {duration : 0.3,
+							queue: { position: 'end', scope: 'CAPPEAR-' + item.id, limit: 1 }}) :
+						Element.hide(ctr);
+
+					item.unread == 0 && item.auxcounter > 0 ? ctr.addClassName("aux") : ctr.removeClassName("aux");
+
 				}
 			}
-		} catch (e) {
-			exception_error("expandParentNodes", e);
-		}
-	},
-	findNodeParentsAndExpandThem: function(feed, is_cat, root, parents) {
-		// expands all parents of specified feed to properly mark it as active
-		// my fav thing about frameworks is doing everything myself
-		try {
-			var test_id = is_cat ? 'CAT:' + feed : 'FEED:' + feed;
-
-			if (!root) {
-				if (!this.model || !this.model.store) return false;
-
-				var items = this.model.store._arrayOfTopLevelItems;
-
-				for (var i = 0; i < items.length; i++) {
-					if (String(items[i].id) == test_id) {
-						this.expandParentNodes(feed, is_cat, parents);
-					} else {
-						this.findNodeParentsAndExpandThem(feed, is_cat, items[i], []);
+
+		},
+		getTooltip: function (item) {
+			if (item.updated)
+				return item.updated;
+			else
+				return "";
+		},
+		getIconClass: function (item, opened) {
+			return (!item || this.model.mayHaveChildren(item)) ? (opened ? "dijitFolderOpened" : "dijitFolderClosed") : "feedIcon";
+		},
+		getLabelClass: function (item, opened) {
+			return (item.unread == 0) ? "dijitTreeLabel" : "dijitTreeLabel Unread";
+		},
+		getRowClass: function (item, opened) {
+			var rc = (!item.error || item.error == '') ? "dijitTreeRow" :
+				"dijitTreeRow Error";
+
+			if (item.unread > 0) rc += " Unread";
+
+			return rc;
+		},
+		getLabel: function(item) {
+			var name = String(item.name);
+
+			/* Horrible */
+			name = name.replace(/&quot;/g, "\"");
+			name = name.replace(/&amp;/g, "&");
+			name = name.replace(/&mdash;/g, "-");
+			name = name.replace(/&lt;/g, "<");
+			name = name.replace(/&gt;/g, ">");
+
+			/* var label;
+
+			 if (item.unread > 0) {
+			 label = name + " (" + item.unread + ")";
+			 } else {
+			 label = name;
+			 } */
+
+			return name;
+		},
+		expandParentNodes: function(feed, is_cat, list) {
+			try {
+				for (var i = 0; i < list.length; i++) {
+					var id = String(list[i].id);
+					var item = this._itemNodesMap[id];
+
+					if (item) {
+						item = item[0];
+						this._expandNode(item);
 					}
 				}
-			} else {
-				if (root.items) {
-					parents.push(root);
+			} catch (e) {
+				exception_error("expandParentNodes", e);
+			}
+		},
+		findNodeParentsAndExpandThem: function(feed, is_cat, root, parents) {
+			// expands all parents of specified feed to properly mark it as active
+			// my fav thing about frameworks is doing everything myself
+			try {
+				var test_id = is_cat ? 'CAT:' + feed : 'FEED:' + feed;
+
+				if (!root) {
+					if (!this.model || !this.model.store) return false;
 
-					for (var i = 0; i < root.items.length; i++) {
-						if (String(root.items[i].id) == test_id) {
+					var items = this.model.store._arrayOfTopLevelItems;
+
+					for (var i = 0; i < items.length; i++) {
+						if (String(items[i].id) == test_id) {
 							this.expandParentNodes(feed, is_cat, parents);
 						} else {
-							this.findNodeParentsAndExpandThem(feed, is_cat, root.items[i], parents.slice(0));
+							this.findNodeParentsAndExpandThem(feed, is_cat, items[i], []);
 						}
 					}
 				} else {
-					if (String(root.id) == test_id) {
-						this.expandParentNodes(feed, is_cat, parents.slice(0));
+					if (root.items) {
+						parents.push(root);
+
+						for (var i = 0; i < root.items.length; i++) {
+							if (String(root.items[i].id) == test_id) {
+								this.expandParentNodes(feed, is_cat, parents);
+							} else {
+								this.findNodeParentsAndExpandThem(feed, is_cat, root.items[i], parents.slice(0));
+							}
+						}
+					} else {
+						if (String(root.id) == test_id) {
+							this.expandParentNodes(feed, is_cat, parents.slice(0));
+						}
 					}
 				}
+			} catch (e) {
+				exception_error("findNodeParentsAndExpandThem", e);
 			}
-		} catch (e) {
-			exception_error("findNodeParentsAndExpandThem", e);
-		}
-	},
-	selectFeed: function(feed, is_cat) {
-		this.findNodeParentsAndExpandThem(feed, is_cat, false, false);
-
-		if (is_cat)
-			treeNode = this._itemNodesMap['CAT:' + feed];
-		else
-			treeNode = this._itemNodesMap['FEED:' + feed];
-
-		if (treeNode) {
-			treeNode = treeNode[0];
-			if (!is_cat) this._expandNode(treeNode);
-			this.set("selectedNodes", [treeNode]);
-		}
-	},
-	setFeedIcon: function(feed, is_cat, src) {
-		if (is_cat)
-			treeNode = this._itemNodesMap['CAT:' + feed];
-		else
-			treeNode = this._itemNodesMap['FEED:' + feed];
-
-		if (treeNode) {
-			treeNode = treeNode[0];
-			treeNode.iconNode.src = src;
-			return true;
-		}
-		return false;
-	},
-	setFeedExpandoIcon: function(feed, is_cat, src) {
-		if (is_cat)
-			treeNode = this._itemNodesMap['CAT:' + feed];
-		else
-			treeNode = this._itemNodesMap['FEED:' + feed];
-
-		if (treeNode) {
-			treeNode = treeNode[0];
-			if (treeNode.loadingNode) {
-				treeNode.loadingNode.src = src;
-				return true;
-			} else {
-				treeNode.expandoNode.src = src;
-				return true;
-			}
-		}
-
-		return false;
-	},
-	hasCats: function() {
-		return this.model.hasCats();
-	},
-	hideReadCat: function (cat, hide, show_special) {
-		if (this.hasCats()) {
-			var tree = this;
+		},
+		selectFeed: function(feed, is_cat) {
+			this.findNodeParentsAndExpandThem(feed, is_cat, false, false);
 
-			if (cat && cat.items) {
-				var cat_unread = tree.hideReadFeeds(cat.items, hide, show_special);
+			if (is_cat)
+				treeNode = this._itemNodesMap['CAT:' + feed];
+			else
+				treeNode = this._itemNodesMap['FEED:' + feed];
+
+			if (treeNode) {
+				treeNode = treeNode[0];
+				if (!is_cat) this._expandNode(treeNode);
+				this.set("selectedNodes", [treeNode]);
+			}
+		},
+		setFeedIcon: function(feed, is_cat, src) {
+			if (is_cat)
+				treeNode = this._itemNodesMap['CAT:' + feed];
+			else
+				treeNode = this._itemNodesMap['FEED:' + feed];
 
-				var id = String(cat.id);
-				var node = tree._itemNodesMap[id];
-				var bare_id = parseInt(id.substr(id.indexOf(":")+1));
+			if (treeNode) {
+				treeNode = treeNode[0];
+				treeNode.iconNode.src = src;
+				return true;
+			}
+			return false;
+		},
+		setFeedExpandoIcon: function(feed, is_cat, src) {
+			if (is_cat)
+				treeNode = this._itemNodesMap['CAT:' + feed];
+			else
+				treeNode = this._itemNodesMap['FEED:' + feed];
 
-				if (node) {
-					var check_unread = tree.model.getFeedUnread(bare_id, true);
+			if (treeNode) {
+				treeNode = treeNode[0];
+				if (treeNode.loadingNode) {
+					treeNode.loadingNode.src = src;
+					return true;
+				} else {
+					treeNode.expandoNode.src = src;
+					return true;
+				}
+			}
 
-					if (hide && cat_unread == 0 && check_unread == 0 && (id != "CAT:-1" || !show_special)) {
-						Effect.Fade(node[0].rowNode, {duration : 0.3,
-							queue: { position: 'end', scope: 'FFADE-' + id, limit: 1 }});
-					} else {
-						Element.show(node[0].rowNode);
-						++cat_unread;
+			return false;
+		},
+		hasCats: function() {
+			return this.model.hasCats();
+		},
+		hideReadCat: function (cat, hide, show_special) {
+			if (this.hasCats()) {
+				var tree = this;
+
+				if (cat && cat.items) {
+					var cat_unread = tree.hideReadFeeds(cat.items, hide, show_special);
+
+					var id = String(cat.id);
+					var node = tree._itemNodesMap[id];
+					var bare_id = parseInt(id.substr(id.indexOf(":")+1));
+
+					if (node) {
+						var check_unread = tree.model.getFeedUnread(bare_id, true);
+
+						if (hide && cat_unread == 0 && check_unread == 0 && (id != "CAT:-1" || !show_special)) {
+							Effect.Fade(node[0].rowNode, {duration : 0.3,
+								queue: { position: 'end', scope: 'FFADE-' + id, limit: 1 }});
+						} else {
+							Element.show(node[0].rowNode);
+							++cat_unread;
+						}
 					}
 				}
 			}
-		}
-	},
-	hideRead: function (hide, show_special) {
-		if (this.hasCats()) {
+		},
+		hideRead: function (hide, show_special) {
+			if (this.hasCats()) {
+
+				var tree = this;
+				var cats = this.model.store._arrayOfTopLevelItems;
 
+				cats.each(function(cat) {
+					tree.hideReadCat(cat, hide, show_special);
+				});
+
+			} else {
+				this.hideReadFeeds(this.model.store._arrayOfTopLevelItems, hide,
+					show_special);
+			}
+		},
+		hideReadFeeds: function (items, hide, show_special) {
 			var tree = this;
-			var cats = this.model.store._arrayOfTopLevelItems;
+			var cat_unread = 0;
 
-			cats.each(function(cat) {
-				tree.hideReadCat(cat, hide, show_special);
-			});
+			items.each(function(feed) {
+				var id = String(feed.id);
 
-		} else {
-			this.hideReadFeeds(this.model.store._arrayOfTopLevelItems, hide,
-				show_special);
-		}
-	},
-	hideReadFeeds: function (items, hide, show_special) {
-		var tree = this;
-		var cat_unread = 0;
-
-		items.each(function(feed) {
-			var id = String(feed.id);
-
-			// it's a subcategory
-			if (feed.items) {
-				tree.hideReadCat(feed, hide, show_special);
-			} else {	// it's a feed
-				var bare_id = parseInt(feed.bare_id);;
-
-				var unread = feed.unread[0];
-				var has_error = feed.error[0] != '';
-				var node = tree._itemNodesMap[id];
-
-				if (node) {
-					if (hide && unread == 0 && !has_error && (bare_id > 0 || bare_id < _label_base_index || !show_special)) {
-						Effect.Fade(node[0].rowNode, {duration : 0.3,
-							queue: { position: 'end', scope: 'FFADE-' + id, limit: 1 }});
-					} else {
-						Element.show(node[0].rowNode);
-						++cat_unread;
+				// it's a subcategory
+				if (feed.items) {
+					tree.hideReadCat(feed, hide, show_special);
+				} else {	// it's a feed
+					var bare_id = parseInt(feed.bare_id);;
+
+					var unread = feed.unread[0];
+					var has_error = feed.error[0] != '';
+					var node = tree._itemNodesMap[id];
+
+					if (node) {
+						if (hide && unread == 0 && !has_error && (bare_id > 0 || bare_id < _label_base_index || !show_special)) {
+							Effect.Fade(node[0].rowNode, {duration : 0.3,
+								queue: { position: 'end', scope: 'FFADE-' + id, limit: 1 }});
+						} else {
+							Element.show(node[0].rowNode);
+							++cat_unread;
+						}
 					}
 				}
-			}
-		});
+			});
 
-		return cat_unread;
-	},
-	collapseCat: function(id) {
-		if (!this.model.hasCats()) return;
+			return cat_unread;
+		},
+		collapseCat: function(id) {
+			if (!this.model.hasCats()) return;
 
-		var tree = this;
+			var tree = this;
 
-		var node = tree._itemNodesMap['CAT:' + id][0];
-		var item = tree.model.store._itemsByIdentity['CAT:' + id];
+			var node = tree._itemNodesMap['CAT:' + id][0];
+			var item = tree.model.store._itemsByIdentity['CAT:' + id];
 
-		if (node && item) {
-			if (!node.isExpanded)
-				tree._expandNode(node);
-			else
-				tree._collapseNode(node);
+			if (node && item) {
+				if (!node.isExpanded)
+					tree._expandNode(node);
+				else
+					tree._collapseNode(node);
 
-		}
-	},
-	getVisibleUnreadFeeds: function() {
-		var items = this.model.store._arrayOfAllItems;
-		var rv = [];
+			}
+		},
+		getVisibleUnreadFeeds: function() {
+			var items = this.model.store._arrayOfAllItems;
+			var rv = [];
 
-		for (var i = 0; i < items.length; i++) {
-			var id = String(items[i].id);
-			var box = this._itemNodesMap[id];
+			for (var i = 0; i < items.length; i++) {
+				var id = String(items[i].id);
+				var box = this._itemNodesMap[id];
 
-			if (box) {
-				var row = box[0].rowNode;
-				var cat = false;
+				if (box) {
+					var row = box[0].rowNode;
+					var cat = false;
 
-				try {
-					cat = box[0].rowNode.parentNode.parentNode;
-				} catch (e) { }
+					try {
+						cat = box[0].rowNode.parentNode.parentNode;
+					} catch (e) { }
 
-				if (row) {
-					if (Element.visible(row) && (!cat || Element.visible(cat))) {
-						var feed_id = String(items[i].bare_id);
-						var is_cat = !id.match('FEED:');
-						var unread = this.model.getFeedUnread(feed_id, is_cat);
+					if (row) {
+						if (Element.visible(row) && (!cat || Element.visible(cat))) {
+							var feed_id = String(items[i].bare_id);
+							var is_cat = !id.match('FEED:');
+							var unread = this.model.getFeedUnread(feed_id, is_cat);
 
-						if (unread > 0)
-							rv.push([feed_id, is_cat]);
+							if (unread > 0)
+								rv.push([feed_id, is_cat]);
 
+						}
 					}
 				}
 			}
-		}
-
-		return rv;
-	},
-	getNextFeed: function (feed, is_cat) {
-		if (is_cat) {
-			treeItem = this.model.store._itemsByIdentity['CAT:' + feed];
-		} else {
-			treeItem = this.model.store._itemsByIdentity['FEED:' + feed];
-		}
-
-		items = this.model.store._arrayOfAllItems;
-		var item = items[0];
-
-		for (var i = 0; i < items.length; i++) {
-			if (items[i] == treeItem) {
-
-				for (var j = i+1; j < items.length; j++) {
-					var id = String(items[j].id);
-					var box = this._itemNodesMap[id];
-
-					if (box) {
-						var row = box[0].rowNode;
-						var cat = box[0].rowNode.parentNode.parentNode;
-
-						if (Element.visible(cat) && Element.visible(row)) {
-							item = items[j];
-							break;
+
+			return rv;
+		},
+		getNextFeed: function (feed, is_cat) {
+			if (is_cat) {
+				treeItem = this.model.store._itemsByIdentity['CAT:' + feed];
+			} else {
+				treeItem = this.model.store._itemsByIdentity['FEED:' + feed];
+			}
+
+			items = this.model.store._arrayOfAllItems;
+			var item = items[0];
+
+			for (var i = 0; i < items.length; i++) {
+				if (items[i] == treeItem) {
+
+					for (var j = i+1; j < items.length; j++) {
+						var id = String(items[j].id);
+						var box = this._itemNodesMap[id];
+
+						if (box) {
+							var row = box[0].rowNode;
+							var cat = box[0].rowNode.parentNode.parentNode;
+
+							if (Element.visible(cat) && Element.visible(row)) {
+								item = items[j];
+								break;
+							}
 						}
 					}
+					break;
 				}
-				break;
 			}
-		}
 
-		if (item) {
-			return [this.model.store.getValue(item, 'bare_id'),
-					 	!this.model.store.getValue(item, 'id').match('FEED:')];
-		} else {
-			return false;
-		}
-	},
-	getPreviousFeed: function (feed, is_cat) {
-		if (is_cat) {
-			treeItem = this.model.store._itemsByIdentity['CAT:' + feed];
-		} else {
-			treeItem = this.model.store._itemsByIdentity['FEED:' + feed];
-		}
-
-		items = this.model.store._arrayOfAllItems;
-		var item = items[0] == treeItem ? items[items.length-1] : items[0];
-
-		for (var i = 0; i < items.length; i++) {
-			if (items[i] == treeItem) {
-
-				for (var j = i-1; j > 0; j--) {
-					var id = String(items[j].id);
-					var box = this._itemNodesMap[id];
-
-					if (box) {
-						var row = box[0].rowNode;
-						var cat = box[0].rowNode.parentNode.parentNode;
-
-						if (Element.visible(cat) && Element.visible(row)) {
-							item = items[j];
-							break;
+			if (item) {
+				return [this.model.store.getValue(item, 'bare_id'),
+					!this.model.store.getValue(item, 'id').match('FEED:')];
+			} else {
+				return false;
+			}
+		},
+		getPreviousFeed: function (feed, is_cat) {
+			if (is_cat) {
+				treeItem = this.model.store._itemsByIdentity['CAT:' + feed];
+			} else {
+				treeItem = this.model.store._itemsByIdentity['FEED:' + feed];
+			}
+
+			items = this.model.store._arrayOfAllItems;
+			var item = items[0] == treeItem ? items[items.length-1] : items[0];
+
+			for (var i = 0; i < items.length; i++) {
+				if (items[i] == treeItem) {
+
+					for (var j = i-1; j > 0; j--) {
+						var id = String(items[j].id);
+						var box = this._itemNodesMap[id];
+
+						if (box) {
+							var row = box[0].rowNode;
+							var cat = box[0].rowNode.parentNode.parentNode;
+
+							if (Element.visible(cat) && Element.visible(row)) {
+								item = items[j];
+								break;
+							}
 						}
-					}
 
+					}
+					break;
 				}
-				break;
 			}
-		}
 
-		if (item) {
-			return [this.model.store.getValue(item, 'bare_id'),
-					 	!this.model.store.getValue(item, 'id').match('FEED:')];
-		} else {
-			return false;
-		}
+			if (item) {
+				return [this.model.store.getValue(item, 'bare_id'),
+					!this.model.store.getValue(item, 'id').match('FEED:')];
+			} else {
+				return false;
+			}
 
-	},
-	getFeedCategory: function(feed) {
-		try {
-			return this.getNodesByItem(this.model.store.
+		},
+		getFeedCategory: function(feed) {
+			try {
+				return this.getNodesByItem(this.model.store.
 					_itemsByIdentity["FEED:" + feed])[0].
-					getParent().item.bare_id[0];
+				getParent().item.bare_id[0];
 
-		} catch (e) {
-			return false;
-		}
-	},
+			} catch (e) {
+				return false;
+			}
+		},
+	});
 });
+

+ 115 - 114
js/PrefFeedTree.js

@@ -1,125 +1,126 @@
-dojo.provide("fox.PrefFeedTree");
-dojo.provide("fox.PrefFeedStore");
+require(["dojo/_base/declare", "dojo/data/ItemFileWriteStore"], function (declare) {
 
-dojo.require("lib.CheckBoxTree");
-dojo.require("dojo.data.ItemFileWriteStore");
+	return declare("fox.PrefFeedStore", dojo.data.ItemFileWriteStore, {
 
-dojo.declare("fox.PrefFeedStore", dojo.data.ItemFileWriteStore, {
+		_saveEverything: function(saveCompleteCallback, saveFailedCallback,
+								  newFileContentString) {
 
-	_saveEverything: function(saveCompleteCallback, saveFailedCallback,
-								newFileContentString) {
+			dojo.xhrPost({
+				url: "backend.php",
+				content: {op: "pref-feeds", method: "savefeedorder",
+					payload: newFileContentString},
+				error: saveFailedCallback,
+				load: saveCompleteCallback});
+		},
 
-		dojo.xhrPost({
-			url: "backend.php",
-			content: {op: "pref-feeds", method: "savefeedorder",
-				payload: newFileContentString},
-			error: saveFailedCallback,
-			load: saveCompleteCallback});
-	},
+	});
 
 });
 
-dojo.declare("fox.PrefFeedTree", lib.CheckBoxTree, {
-	_createTreeNode: function(args) {
-		var tnode = this.inherited(arguments);
-
-		if (args.item.icon)
-			tnode.iconNode.src = args.item.icon[0];
-
-		var param = this.model.store.getValue(args.item, 'param');
-
-		if (param) {
-			param = dojo.doc.createElement('span');
-			param.className = 'feedParam';
-			param.innerHTML = args.item.param[0];
-			//dojo.place(param, tnode.labelNode, 'after');
-			dojo.place(param, tnode.rowNode, 'first');
-		}
-
-		var id = args.item.id[0];
-		var bare_id = parseInt(id.substr(id.indexOf(':')+1));
-
-		if (id.match("CAT:") && bare_id > 0) {
-			var menu = new dijit.Menu();
-			menu.row_id = bare_id;
-			menu.item = args.item;
-
-			menu.addChild(new dijit.MenuItem({
-				label: __("Edit category"),
-				onClick: function() {
-					editCat(this.getParent().row_id, this.getParent().item, null);
-				}}));
-
-
-			menu.addChild(new dijit.MenuItem({
-				label: __("Remove category"),
-				onClick: function() {
-					removeCategory(this.getParent().row_id, this.getParent().item);
-				}}));
-
-			menu.bindDomNode(tnode.domNode);
-			tnode._menu = menu;
-		} else if (id.match("FEED:")) {
-			var menu = new dijit.Menu();
-			menu.row_id = bare_id;
-			menu.item = args.item;
-
-			menu.addChild(new dijit.MenuItem({
-				label: __("Edit feed"),
-				onClick: function() {
-					editFeed(this.getParent().row_id);
-				}}));
-
-			menu.addChild(new dijit.MenuItem({
-				label: __("Unsubscribe"),
-				onClick: function() {
-					unsubscribeFeed(this.getParent().row_id, this.getParent().item.name);
-				}}));
-
-			menu.bindDomNode(tnode.domNode);
-			tnode._menu = menu;
-
-		}
-
-		return tnode;
-	},
-	onDndDrop: function() {
-		this.inherited(arguments);
-		this.tree.model.store.save();
-	},
-	getRowClass: function (item, opened) {
-		return (!item.error || item.error == '') ? "dijitTreeRow" :
-			"dijitTreeRow Error";
-	},
-	getIconClass: function (item, opened) {
-		return (!item || this.model.store.getValue(item, 'type') == 'category') ? (opened ? "dijitFolderOpened" : "dijitFolderClosed") : "feedIcon";
-	},
-	checkItemAcceptance: function(target, source, position) {
-		var item = dijit.getEnclosingWidget(target).item;
-
-		// disable copying items
-		source.copyState = function() { return false; };
-
-		var source_item = false;
-
-		source.forInSelectedItems(function(node) {
-			source_item = node.data.item;
-		});
-
-		if (!source_item || !item) return false;
-
-		var id = this.tree.model.store.getValue(item, 'id');
-		var source_id = source.tree.model.store.getValue(source_item, 'id');
-
-		//console.log(id + " " + position + " " + source_id);
-
-		if (source_id.match("FEED:")) {
-			return ((id.match("CAT:") && position == "over") ||
+require(["dojo/_base/declare", "lib/CheckBoxTree"], function (declare) {
+
+	return declare("fox.PrefFeedTree", lib.CheckBoxTree, {
+		_createTreeNode: function(args) {
+			var tnode = this.inherited(arguments);
+
+			if (args.item.icon)
+				tnode.iconNode.src = args.item.icon[0];
+
+			var param = this.model.store.getValue(args.item, 'param');
+
+			if (param) {
+				param = dojo.doc.createElement('span');
+				param.className = 'feedParam';
+				param.innerHTML = args.item.param[0];
+				//dojo.place(param, tnode.labelNode, 'after');
+				dojo.place(param, tnode.rowNode, 'first');
+			}
+
+			var id = args.item.id[0];
+			var bare_id = parseInt(id.substr(id.indexOf(':')+1));
+
+			if (id.match("CAT:") && bare_id > 0) {
+				var menu = new dijit.Menu();
+				menu.row_id = bare_id;
+				menu.item = args.item;
+
+				menu.addChild(new dijit.MenuItem({
+					label: __("Edit category"),
+					onClick: function() {
+						editCat(this.getParent().row_id, this.getParent().item, null);
+					}}));
+
+
+				menu.addChild(new dijit.MenuItem({
+					label: __("Remove category"),
+					onClick: function() {
+						removeCategory(this.getParent().row_id, this.getParent().item);
+					}}));
+
+				menu.bindDomNode(tnode.domNode);
+				tnode._menu = menu;
+			} else if (id.match("FEED:")) {
+				var menu = new dijit.Menu();
+				menu.row_id = bare_id;
+				menu.item = args.item;
+
+				menu.addChild(new dijit.MenuItem({
+					label: __("Edit feed"),
+					onClick: function() {
+						editFeed(this.getParent().row_id);
+					}}));
+
+				menu.addChild(new dijit.MenuItem({
+					label: __("Unsubscribe"),
+					onClick: function() {
+						unsubscribeFeed(this.getParent().row_id, this.getParent().item.name);
+					}}));
+
+				menu.bindDomNode(tnode.domNode);
+				tnode._menu = menu;
+
+			}
+
+			return tnode;
+		},
+		onDndDrop: function() {
+			this.inherited(arguments);
+			this.tree.model.store.save();
+		},
+		getRowClass: function (item, opened) {
+			return (!item.error || item.error == '') ? "dijitTreeRow" :
+				"dijitTreeRow Error";
+		},
+		getIconClass: function (item, opened) {
+			return (!item || this.model.store.getValue(item, 'type') == 'category') ? (opened ? "dijitFolderOpened" : "dijitFolderClosed") : "feedIcon";
+		},
+		checkItemAcceptance: function(target, source, position) {
+			var item = dijit.getEnclosingWidget(target).item;
+
+			// disable copying items
+			source.copyState = function() { return false; };
+
+			var source_item = false;
+
+			source.forInSelectedItems(function(node) {
+				source_item = node.data.item;
+			});
+
+			if (!source_item || !item) return false;
+
+			var id = this.tree.model.store.getValue(item, 'id');
+			var source_id = source.tree.model.store.getValue(source_item, 'id');
+
+			//console.log(id + " " + position + " " + source_id);
+
+			if (source_id.match("FEED:")) {
+				return ((id.match("CAT:") && position == "over") ||
 				(id.match("FEED:") && position != "over"));
-		} else if (source_id.match("CAT:")) {
-			return ((id.match("CAT:") && !id.match("CAT:0")) ||
+			} else if (source_id.match("CAT:")) {
+				return ((id.match("CAT:") && !id.match("CAT:0")) ||
 				(id.match("root") && position == "over"));
-		}
-	},
+			}
+		},
+	});
 });
 

+ 94 - 88
js/PrefFilterTree.js

@@ -1,96 +1,102 @@
-dojo.provide("fox.PrefFilterTree");
+require(["dojo/_base/declare", "dojo/data/ItemFileWriteStore"], function (declare) {
 
-dojo.require("lib.CheckBoxTree");
-dojo.require("dojo.data.ItemFileWriteStore");
+	return declare("fox.PrefFilterStore", dojo.data.ItemFileWriteStore, {
 
-dojo.declare("fox.PrefFilterStore", dojo.data.ItemFileWriteStore, {
+		_saveEverything: function (saveCompleteCallback, saveFailedCallback,
+								   newFileContentString) {
 
-	_saveEverything: function(saveCompleteCallback, saveFailedCallback,
-								newFileContentString) {
-
-		dojo.xhrPost({
-			url: "backend.php",
-			content: {op: "pref-filters", method: "savefilterorder",
-				payload: newFileContentString},
-			error: saveFailedCallback,
-			load: saveCompleteCallback});
-	},
+			dojo.xhrPost({
+				url: "backend.php",
+				content: {
+					op: "pref-filters", method: "savefilterorder",
+					payload: newFileContentString
+				},
+				error: saveFailedCallback,
+				load: saveCompleteCallback
+			});
+		},
 
+	});
 });
 
-dojo.declare("fox.PrefFilterTree", lib.CheckBoxTree, {
-	_createTreeNode: function(args) {
-		var tnode = this.inherited(arguments);
-
-		var enabled = this.model.store.getValue(args.item, 'enabled');
-		var param = this.model.store.getValue(args.item, 'param');
-		var rules = this.model.store.getValue(args.item, 'rules');
-
-		if (param) {
-			param = dojo.doc.createElement('span');
-			param.className = (enabled != false) ? 'labelParam' : 'labelParam filterDisabled';
-			param.innerHTML = args.item.param[0];
-			dojo.place(param, tnode.rowNode, 'first');
-		}
-
-		if (rules) {
-			param = dojo.doc.createElement('span');
-			param.className = 'filterRules';
-			param.innerHTML = rules;
-			dojo.place(param, tnode.rowNode, 'next');
-		}
-
-		if (this.model.store.getValue(args.item, 'id') != 'root') {
-			var img = dojo.doc.createElement('img');
-			img.src ='images/filter.png';
-			img.className = 'markedPic';
-			tnode._filterIconNode = img;
-			dojo.place(tnode._filterIconNode, tnode.labelNode, 'before');
-		}
-
-		return tnode;
-	},
-
-	getLabel: function(item) {
-		var label = item.name;
-
-		var feed = this.model.store.getValue(item, 'feed');
-		var inverse = this.model.store.getValue(item, 'inverse');
-
-		if (feed)
-			label += " (" + __("in") + " " + feed + ")";
-
-		if (inverse)
-			label += " (" + __("Inverse") + ")";
-
-/*		if (item.param)
-			label = "<span class=\"labelFixedLength\">" + label +
-				"</span>" + item.param[0]; */
-
-		return label;
-	},
-	getIconClass: function (item, opened) {
-		return (!item || this.model.mayHaveChildren(item)) ? (opened ? "dijitFolderOpened" : "dijitFolderClosed") : "invisible";
-	},
-	getLabelClass: function (item, opened) {
-		var enabled = this.model.store.getValue(item, 'enabled');
-		return (enabled != false) ? "dijitTreeLabel labelFixedLength" : "dijitTreeLabel labelFixedLength filterDisabled";
-	},
-	getRowClass: function (item, opened) {
-		return (!item.error || item.error == '') ? "dijitTreeRow" :
-			"dijitTreeRow Error";
-	},
-	checkItemAcceptance: function(target, source, position) {
-		var item = dijit.getEnclosingWidget(target).item;
-
-		// disable copying items
-		source.copyState = function() { return false; };
-
-		return position != 'over';
-	},
-	onDndDrop: function() {
-		this.inherited(arguments);
-		this.tree.model.store.save();
-	},
+require(["dojo/_base/declare", "lib/CheckBoxTree"], function (declare) {
+
+	return declare("fox.PrefFilterTree", lib.CheckBoxTree, {
+		_createTreeNode: function(args) {
+			var tnode = this.inherited(arguments);
+
+			var enabled = this.model.store.getValue(args.item, 'enabled');
+			var param = this.model.store.getValue(args.item, 'param');
+			var rules = this.model.store.getValue(args.item, 'rules');
+
+			if (param) {
+				param = dojo.doc.createElement('span');
+				param.className = (enabled != false) ? 'labelParam' : 'labelParam filterDisabled';
+				param.innerHTML = args.item.param[0];
+				dojo.place(param, tnode.rowNode, 'first');
+			}
+
+			if (rules) {
+				param = dojo.doc.createElement('span');
+				param.className = 'filterRules';
+				param.innerHTML = rules;
+				dojo.place(param, tnode.rowNode, 'next');
+			}
+
+			if (this.model.store.getValue(args.item, 'id') != 'root') {
+				var img = dojo.doc.createElement('img');
+				img.src ='images/filter.png';
+				img.className = 'markedPic';
+				tnode._filterIconNode = img;
+				dojo.place(tnode._filterIconNode, tnode.labelNode, 'before');
+			}
+
+			return tnode;
+		},
+
+		getLabel: function(item) {
+			var label = item.name;
+
+			var feed = this.model.store.getValue(item, 'feed');
+			var inverse = this.model.store.getValue(item, 'inverse');
+
+			if (feed)
+				label += " (" + __("in") + " " + feed + ")";
+
+			if (inverse)
+				label += " (" + __("Inverse") + ")";
+
+			/*		if (item.param)
+			 label = "<span class=\"labelFixedLength\">" + label +
+			 "</span>" + item.param[0]; */
+
+			return label;
+		},
+		getIconClass: function (item, opened) {
+			return (!item || this.model.mayHaveChildren(item)) ? (opened ? "dijitFolderOpened" : "dijitFolderClosed") : "invisible";
+		},
+		getLabelClass: function (item, opened) {
+			var enabled = this.model.store.getValue(item, 'enabled');
+			return (enabled != false) ? "dijitTreeLabel labelFixedLength" : "dijitTreeLabel labelFixedLength filterDisabled";
+		},
+		getRowClass: function (item, opened) {
+			return (!item.error || item.error == '') ? "dijitTreeRow" :
+				"dijitTreeRow Error";
+		},
+		checkItemAcceptance: function(target, source, position) {
+			var item = dijit.getEnclosingWidget(target).item;
+
+			// disable copying items
+			source.copyState = function() { return false; };
+
+			return position != 'over';
+		},
+		onDndDrop: function() {
+			this.inherited(arguments);
+			this.tree.model.store.save();
+		},
+	});
+
 });
 
+

+ 31 - 31
js/PrefLabelTree.js

@@ -1,43 +1,43 @@
-dojo.provide("fox.PrefLabelTree");
+require(["dojo/_base/declare", "lib/CheckBoxTree", "dijit/form/DropDownButton"], function (declare) {
 
-dojo.require("lib.CheckBoxTree");
-dojo.require("dijit.form.DropDownButton");
+	return declare("fox.PrefLabelTree", lib.CheckBoxTree, {
+		setNameById: function (id, name) {
+			var item = this.model.store._itemsByIdentity['LABEL:' + id];
 
-dojo.declare("fox.PrefLabelTree", lib.CheckBoxTree, {
-	setNameById: function (id, name) {
-		var item = this.model.store._itemsByIdentity['LABEL:' + id];
+			if (item)
+				this.model.store.setValue(item, 'name', name);
 
-		if (item)
-			this.model.store.setValue(item, 'name', name);
+		},
+		_createTreeNode: function(args) {
+			var tnode = this.inherited(arguments);
 
-	},
-	_createTreeNode: function(args) {
-		var tnode = this.inherited(arguments);
+			var fg_color = this.model.store.getValue(args.item, 'fg_color');
+			var bg_color = this.model.store.getValue(args.item, 'bg_color');
+			var type = this.model.store.getValue(args.item, 'type');
+			var bare_id = this.model.store.getValue(args.item, 'bare_id');
 
-		var fg_color = this.model.store.getValue(args.item, 'fg_color');
-		var bg_color = this.model.store.getValue(args.item, 'bg_color');
-		var type = this.model.store.getValue(args.item, 'type');
-		var bare_id = this.model.store.getValue(args.item, 'bare_id');
+			if (type == 'label') {
+				var span = dojo.doc.createElement('span');
+				span.innerHTML = '&alpha;';
+				span.className = 'labelColorIndicator';
+				span.id = 'LICID-' + bare_id;
 
-		if (type == 'label') {
-			var span = dojo.doc.createElement('span');
-			span.innerHTML = '&alpha;';
-			span.className = 'labelColorIndicator';
-			span.id = 'LICID-' + bare_id;
+				span.setStyle({
+					color: fg_color,
+					backgroundColor: bg_color});
 
-			span.setStyle({
-				color: fg_color,
-				backgroundColor: bg_color});
+				tnode._labelIconNode = span;
 
-			tnode._labelIconNode = span;
+				dojo.place(tnode._labelIconNode, tnode.labelNode, 'before');
+			}
 
-			dojo.place(tnode._labelIconNode, tnode.labelNode, 'before');
-		}
+			return tnode;
+		},
+		getIconClass: function (item, opened) {
+			return (!item || this.model.mayHaveChildren(item)) ? (opened ? "dijitFolderOpened" : "dijitFolderClosed") : "invisible";
+		},
+	});
 
-		return tnode;
-	},
-	getIconClass: function (item, opened) {
-		return (!item || this.model.mayHaveChildren(item)) ? (opened ? "dijitFolderOpened" : "dijitFolderClosed") : "invisible";
-	},
 });
 
+

+ 4 - 7
js/prefs.js

@@ -943,15 +943,12 @@ function init() {
 			"dijit/Toolbar",
 			"dijit/Tree",
 			"dijit/tree/dndSource",
-			"dojo/data/ItemFileWriteStore"], function (dojo, ready, parser) {
+			"dojo/data/ItemFileWriteStore",
+			"fox/PrefFeedTree",
+			"fox/PrefFilterTree",
+			"fox/PrefLabelTree" ], function (dojo, ready, parser) {
 
 				ready(function() {
-
-					dojo.require("lib.CheckBoxTree");
-					dojo.require("fox.PrefFeedTree");
-					dojo.require("fox.PrefFilterTree");
-					dojo.require("fox.PrefLabelTree");
-
 					parser.parse();
 
 					loading_set_progress(50);

+ 2 - 3
js/tt-rss.js

@@ -248,12 +248,11 @@ function init() {
 				"dijit/Tree",
 				"dijit/tree/dndSource",
 				"dijit/tree/ForestStoreModel",
-				"dojo/data/ItemFileWriteStore" ], function (dojo, ready, parser) {
+				"dojo/data/ItemFileWriteStore",
+				"fox/FeedTree" ], function (dojo, ready, parser) {
 
 				ready(function() {
 
-					dojo.require("fox.FeedTree");
-
 					parser.parse();
 
 					if (!genericSanityCheck())

+ 458 - 446
lib/CheckBoxTree.js

@@ -1,474 +1,486 @@
-dojo.provide("lib.CheckBoxTree");
-dojo.provide("lib.CheckBoxStoreModel");
+//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 ) { I don't need all this 1-1 stuff, only parent -> child (fox)
-			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).
-		// this stuff is only relevant for Forest store -fox
-/*		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;
+//dojo.require("dijit.Tree");
+//dojo.require("dijit.form.CheckBox");
+
+require(["dojo/_base/declare", "dijit/tree/TreeStoreModel"], function (declare) {
+
+	return 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 ) { I don't need all this 1-1 stuff, only parent -> child (fox)
+				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);
 				}
-			} 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;
-			}
-		} */
-
-		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 );
-							}
+			},
+			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).
+				// this stuff is only relevant for Forest store -fox
+				/*		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;
+				 }
+				 } */
+
+				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);
 						}
-						if( this.mayHaveChildren( child )) {
-							this._updateChildCheckbox( child, newState );
+					);
+				}
+			},
+
+			_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 );
-				}),
-				function(err) {
-					console.error(this, ": updating child checkboxes: ", err);
+					}
+				}, 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);
+					}
 				}
-			);
-		}
-	},
-
-	_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) {
+				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;
-						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 );
+						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, ": updating parent checkboxes: ", err);
+						console.error(this, ": validating checkbox data: ", 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]);
+			},
+
+			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
 			}
-			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);
+		});
+
+});
+
+require(["dojo/_base/declare", "dijit/Tree"], function (declare) {
+
+	return 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');
 				}
-			}),
-			function(err) {
-				console.error(this, ": validating checkbox data: ", err);
+			},
+
+			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);
 			}
-		);
-	},
-
-	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 );
-	}
+require(["dojo/_base/declare", "dijit/Tree"], function (declare) {
+
+	return 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
 
-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.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 );
 				}
-			}, 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);
-	}
+			},
+
+			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);
+			}
+
+		});
 
 });
+