Guest User

Untitled

a guest
Jun 22nd, 2018
92
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.61 KB | None | 0 0
  1. // vim: sw=2:et
  2.  
  3. plugin.id = "channel-tree";
  4.  
  5. plugin.init = function(glob) {
  6. plugin.major = 1;
  7. plugin.minor = 0;
  8. plugin.version = plugin.major + "." + plugin.minor + " (10 Jun 2008)";
  9. plugin.description = "List tabs in a tree";
  10.  
  11. plugin.hooks = [];
  12. plugin.tags = [];
  13. plugin.nodes = [];
  14.  
  15. plugin.prefary = plugin.prefary.concat([
  16. ["showIcons", "true"]
  17. ]);
  18.  
  19. plugin.onPrefChanged = function(name, oldValue, newValue) {
  20. if(name == "showIcons") {
  21. plugin.applyShowIconPreference();
  22. }
  23. }
  24.  
  25. return "OK";
  26. }
  27.  
  28. plugin.enable = function() {
  29. var stylesheet = document.createProcessingInstruction("xml-stylesheet",
  30. 'href="' + plugin.cwd + 'style.css"');
  31. document.insertBefore(stylesheet, document.firstChild);
  32.  
  33. var splitter = document.createElement("splitter");
  34. var grippy = document.createElement("grippy");
  35. splitter.setAttribute("collapse", "before");
  36. splitter.setAttribute("id", "splitter[" + plugin.id + "]");
  37. splitter.setAttribute("persist", "collapsed left");
  38. splitter.appendChild(grippy);
  39.  
  40. var tree = document.createElement("tree");
  41. tree.setAttribute("id", "channel-tree");
  42. tree.setAttribute("hidecolumnpicker", "true");
  43. tree.setAttribute("seltype", "single");
  44. tree.setAttribute("width", "166");
  45. plugin.tree = tree;
  46. plugin.applyShowIconPreference();
  47.  
  48. var treeCols = document.createElement("treecols");
  49. var treeCol = document.createElement("treecol");
  50. treeCol.setAttribute("flex", "1");
  51. treeCol.setAttribute("primary", "true");
  52. treeCol.setAttribute("hideheader", "true");
  53.  
  54. tree.appendChild(treeCols);
  55. treeCols.appendChild(treeCol);
  56.  
  57. var treeChildren = document.createElement("treechildren");
  58. tree.appendChild(treeChildren);
  59. plugin.treeChildrenNode = treeChildren;
  60.  
  61. var box = document.getElementById("tabpanels-contents-box");
  62. plugin.insertNode(splitter, box, box.firstChild);
  63. plugin.insertNode(tree, box, box.firstChild);
  64. plugin.treeView = tree.view;
  65.  
  66. // add existing tabs into tree
  67. client.viewsArray.forEach(function(v) {
  68. plugin.handleNewView(v.source);
  69. });
  70. tree.treeBoxObject.clearStyleAndImageCaches();
  71.  
  72. plugin.addHook("create-tab-for-view",
  73. function(e) {
  74. var o = e.view;
  75. plugin.handleNewView(o);
  76. }, false);
  77.  
  78. plugin.addHook("delete-view",
  79. function(e) {
  80. var o = e.view
  81. var p = plugin.getTreeParent(o);
  82. if(!o.treeItemNode) return;
  83. // only delete from tree when o is a child node or it has no children
  84. if(plugin.hasNoChildrenInTree(o)) {
  85. o.treeItemNode.parentNode.removeChild(o.treeItemNode);
  86. delete o.treeItemNode;
  87. if("childrenNode" in o) delete o.treeChildrenNode;
  88. }
  89. }, false);
  90.  
  91. plugin.addHook("set-current-view",
  92. function(e) {
  93. var o = e.view;
  94. plugin.handleNewView(o);
  95. plugin.setCurrentView(o);
  96. }, false);
  97.  
  98. // switch view when tree item is selected
  99. tree.addEventListener("select",
  100. function(e) {
  101. selectedObject = plugin.objectSelectedInTree();
  102. // recreate view when it is closed, this happens for network tabs
  103. if(!("messages" in selectedObject)) {
  104. client.dispatch("create-tab-for-view", {view: selectedObject});
  105. }
  106. client.dispatch("set-current-view", {view: selectedObject});
  107. setTimeout('dispatch("focus-input")', 0);
  108. }, false);
  109.  
  110. // duplicate context menu of corresponding tabs to tree item
  111. plugin.contextId = "context:" + plugin.id;
  112. client.menuSpecs[plugin.contextId] = {
  113. getContext: function(cx) {
  114. if(!cx) cx = new Object();
  115. cx.__proto__ = getObjectDetails(plugin.objectSelectedInTree());
  116. return cx;
  117. },
  118. items: client.menuSpecs["context:tab"].items}
  119. tree.setAttribute("context", plugin.contextId);
  120. client.updateMenus();
  121.  
  122. // decorate setTabState function to make it update property on tree item
  123. plugin.originalSetTabState = setTabState;
  124. setTabState = function(source, what, callback) {
  125. plugin.handleNewView(source);
  126. plugin.originalSetTabState(source, what, callback);
  127.  
  128. // following block copied from static.js lines 2696-2718 function setTabState
  129. if (typeof source != "object")
  130. {
  131. if (!ASSERT(source in client.viewsArray,
  132. "INVALID SOURCE passed to setTabState"))
  133. return;
  134. source = client.viewsArray[source].source;
  135. }
  136.  
  137. plugin.syncStateForObject(source);
  138. }
  139.  
  140. return true;
  141. }
  142.  
  143. plugin.disable = function() {
  144. setTabState = plugin.originalSetTabState;
  145. plugin.hooks.forEach(function(hook) {
  146. client.commandManager.removeHook(hook.name, hook.id, hook.before);
  147. });
  148. plugin.tags.forEach(function(tag) {
  149. delete tag.object[tag.name];
  150. });
  151. plugin.nodes.forEach(function(node) {
  152. if(node.parentNode) {
  153. node.parentNode.removeChild(node);
  154. }
  155. });
  156. delete client.menuSpecs[plugin.contextId];
  157. client.updateMenus();
  158. return true;
  159. }
  160.  
  161. // --- home made "garbage collecting" helpers ---
  162.  
  163. // add a hook and remember it so it's automatically removed on disable
  164. plugin.addHook = function(name, callback, before) {
  165. var id = plugin.id + "-" + name;
  166. plugin.hooks.push({"name": name, "id": id, "before": before});
  167. client.commandManager.addHook(name, callback, id, before);
  168. }
  169.  
  170. // tag a property onto an object. at disable all these tags are automatically
  171. // removed
  172. plugin.tagObject = function(o, name, value) {
  173. o[name] = value;
  174. if(! plugin.tags.some(function(i) {return i.o == o && i.name == name;}) ) {
  175. plugin.tags.push({object: o, name: name});
  176. }
  177. }
  178.  
  179. // add a node in the DOM. it must have an ID and any existing node with the same ID
  180. // is removed (to clean up left overs from crashed plugin). at disable the node is
  181. // removed
  182. plugin.insertNode = function(node, under, before) {
  183. var existing;
  184. var id = node.getAttribute("id");
  185. while(existing = document.getElementById(id)) {
  186. existing.parentNode.removeChild(existing);
  187. }
  188. under.insertBefore(node, before);
  189. plugin.nodes.push(node);
  190. }
  191.  
  192. // --- helpers for maintaining representation of views in the tree ---
  193.  
  194. // if o has not been encountered, add to tree, otherwise do nothing
  195. plugin.handleNewView = function(o) {
  196. if(!o || !(o instanceof Object) || ("treeItemNode" in o)) return;
  197. var parent = plugin.getTreeParent(o);
  198. if(parent) {
  199. plugin.handleNewView(parent);
  200. plugin.addToTree(o, parent.treeChildrenNode);
  201. } else {
  202. plugin.addToTreeAsParent(o);
  203. }
  204. }
  205.  
  206. // add an entry to the tree for the object, under the treerows node specified by "at"
  207. plugin.addToTree = function(o, at) {
  208. var id = plugin.getIdForObject(o);
  209. var treeItem = document.getElementById(id);
  210. if(!treeItem) {
  211. // add to tree
  212. treeItem = document.createElement("treeitem");
  213. treeItem.setAttribute("id", id);
  214. var treeRow = document.createElement("treerow");
  215. var treeCell = document.createElement("treecell");
  216. treeCell.setAttribute("label", plugin.getLabelForObject(o));
  217.  
  218. treeItem.appendChild(treeRow);
  219. treeRow.appendChild(treeCell);
  220.  
  221. at.appendChild(treeItem);
  222. }
  223. // if the tree item is already there, associate it with the object
  224. plugin.tagObject(o, "treeItemNode", treeItem);
  225. plugin.tagObject(treeItem, "object", o);
  226. plugin.syncStateForObject(o);
  227. plugin.editPropertiesForObject(o, [], [o.TYPE]);
  228. return treeItem;
  229. }
  230.  
  231. // add an entry to the tree for the object, at top level, and mark it as a container
  232. // o.treeChildrenNode is set to the treerows under the added object, where children can be added
  233. plugin.addToTreeAsParent = function(o) {
  234. var treeItem = plugin.addToTree(o, plugin.treeChildrenNode);
  235. treeItem.setAttribute("container", "true");
  236. treeItem.setAttribute("open", "true");
  237. var treeChildrenId = treeItem.getAttribute("id") + "-treechildren";
  238. var treeChildren = document.getElementById(treeChildrenId);
  239. if(!treeChildren) {
  240. treeChildren = document.createElement("treechildren");
  241. treeChildren.setAttribute("id", treeChildrenId);
  242. }
  243. treeItem.appendChild(treeChildren);
  244. plugin.tagObject(o, "treeChildrenNode", treeChildren);
  245. return treeItem;
  246. }
  247.  
  248. // returns true if the object's tree item has no child
  249. plugin.hasNoChildrenInTree = function(o) {
  250. var treeChildrenNode = o.treeChildrenNode;
  251. return !treeChildrenNode || !treeChildrenNode.hasChildNodes();
  252. }
  253.  
  254. plugin.viewStates = ["normal",
  255. "superfluous",
  256. "activity",
  257. "attention",
  258. "channel-tree-current"];
  259. // set property for the treecell most directly under the given treeItemNode
  260. plugin.setStateForObject = function(o, state) {
  261. plugin.editPropertiesForObject(o, plugin.viewStates, [state]);
  262. }
  263.  
  264. plugin.editPropertiesForObject = function(o, toRemove, toAdd) {
  265. var treeItem = o.treeItemNode;
  266. var treeRow = treeItem.firstChild;
  267. var treeCell = treeRow.firstChild;
  268. [treeItem, treeRow, treeCell].forEach(function(node) {
  269. var originalProperties = node.getAttribute("properties");
  270. var properties = originalProperties.split(/\s+/);
  271. properties = properties.filter(function(prop) {
  272. return toRemove.indexOf(prop) == -1;
  273. });
  274. toAdd.forEach(function(prop) {
  275. properties.push(toAdd);
  276. });
  277. var newProperties = properties.join(" ");
  278. node.setAttribute("properties", newProperties);
  279. });
  280. }
  281.  
  282. // return parent of an object, in a definition consistent to the tree structure
  283. // IRCNetwork and IRCDCC objects are considered top level
  284. plugin.getTreeParent = function(o) {
  285. // memoized result
  286. if("treeParent" in o) return o.treeParent;
  287. // objects treated as top level, this line might not be necessary
  288. if("IRCNetwork" == o.TYPE) return undefined;
  289.  
  290. var parent = o.parent;
  291. // skip IRCServer and IRCDCC objects and use the network or *client* as parent
  292. if(parent && ["IRCServer", "IRCDCC"].indexOf(parent.TYPE) >= 0)
  293. parent = parent.parent;
  294.  
  295. // memoize the result in o.treeParent;
  296. plugin.tagObject(o, "treeParent", parent);
  297. return parent;
  298. }
  299.  
  300. plugin.objectSelectedInTree = function() {
  301. return plugin.treeView.getItemAtIndex(plugin.tree.currentIndex).object;
  302. }
  303.  
  304. plugin.setCurrentView = function(o) {
  305. var index = plugin.treeView.getIndexOfItem(o.treeItemNode);
  306. plugin.treeView.selection.select(index);
  307. plugin.syncStateForObject(o);
  308. var lastCurrentObject = plugin.lastCurrentObject;
  309. if(lastCurrentObject && lastCurrentObject != o) {
  310. plugin.syncStateForObject(lastCurrentObject);
  311. }
  312. plugin.tagObject(plugin, "lastCurrentObject", o);
  313. }
  314.  
  315. plugin.syncStateForObject = function(o) {
  316. var tb = getTabForObject(o, true);
  317.  
  318. // copy the just set state on tb to treeItemNode's property
  319. state = tb.getAttribute("state");
  320. // we use the property "channel-tree-current" instead of "current", because the
  321. // latter is used by XUL. although in practice the two should have the same
  322. // effect
  323. if(state == "current") {
  324. state = "channel-tree-current";
  325. }
  326. plugin.setStateForObject(o, state);
  327. }
  328.  
  329. // return an unique and consistent ID for the treeitem for the object based on its
  330. // unicodeName and that of its parent. the format is "treeitem[parent][name]", and
  331. // for top level nodes it's "treeitem[][name]"
  332. plugin.getIdForObject = function(o) {
  333. var p = plugin.getTreeParent(o);
  334. var parentName = p ? plugin.getLabelForObject(p) : "";
  335. return "treeitem-" + parentName + "-" + plugin.getLabelForObject(o);
  336. }
  337.  
  338. plugin.getLabelForObject = function(o) {
  339. return getTabForObject(o, true).getAttribute("label");
  340. }
  341.  
  342. plugin.applyShowIconPreference = function() {
  343. if(plugin.prefs["showIcons"] == "true") {
  344. plugin.tree.setAttribute("class", "showIcons");
  345. } else {
  346. plugin.tree.setAttribute("class", "noIcons");
  347. }
  348. }
Add Comment
Please, Sign In to add comment