relatedbox.xml (9416B)
1 <?xml version="1.0"?> 2 <!-- 3 ***** BEGIN LICENSE BLOCK ***** 4 5 Copyright © 2009 Center for History and New Media 6 George Mason University, Fairfax, Virginia, USA 7 http://zotero.org 8 9 This file is part of Zotero. 10 11 Zotero is free software: you can redistribute it and/or modify 12 it under the terms of the GNU Affero General Public License as published by 13 the Free Software Foundation, either version 3 of the License, or 14 (at your option) any later version. 15 16 Zotero is distributed in the hope that it will be useful, 17 but WITHOUT ANY WARRANTY; without even the implied warranty of 18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 GNU Affero General Public License for more details. 20 21 You should have received a copy of the GNU Affero General Public License 22 along with Zotero. If not, see <http://www.gnu.org/licenses/>. 23 24 ***** END LICENSE BLOCK ***** 25 --> 26 27 <!DOCTYPE bindings SYSTEM "chrome://zotero/locale/zotero.dtd"> 28 29 <bindings xmlns="http://www.mozilla.org/xbl" 30 xmlns:xbl="http://www.mozilla.org/xbl" 31 xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> 32 <binding id="related-box"> 33 <implementation> 34 <!-- Modes are predefined settings groups for particular tasks --> 35 <field name="_mode">"view"</field> 36 <property name="mode" onget="return this._mode;"> 37 <setter> 38 <![CDATA[ 39 this.clickable = false; 40 this.editable = false; 41 42 switch (val) { 43 case 'view': 44 case 'merge': 45 case 'mergeedit': 46 break; 47 48 case 'edit': 49 this.clickable = true; 50 this.editable = true; 51 //this.clickHandler = this.showEditor; 52 //this.blurHandler = this.hideEditor; 53 break; 54 55 default: 56 throw ("Invalid mode '" + val + "' in relatedbox.xml"); 57 } 58 59 this._mode = val; 60 document.getAnonymousNodes(this)[0].setAttribute('mode', val); 61 ]]> 62 </setter> 63 </property> 64 65 <field name="itemRef"/> 66 <property name="item" onget="return this.itemRef;"> 67 <setter> 68 <![CDATA[ 69 this.itemRef = val; 70 this.refresh(); 71 ]]> 72 </setter> 73 </property> 74 <property name="summary"> 75 <getter> 76 <![CDATA[ 77 var r = ""; 78 79 if (this.item) { 80 var keys = this.item.relatedItems; 81 if (keys.length) { 82 for (let key of keys) { 83 let item = Zotero.Items.getByLibraryAndKey(this.item.libraryID, key); 84 if (!item) { 85 Zotero.debug(`Related item ${this.item.libraryID}/${key} not found ` 86 + `for item ${this.item.libraryKey}`, 2); 87 continue; 88 } 89 r = r + item.getDisplayTitle() + ", "; 90 } 91 r = r.substr(0,r.length-2); 92 } 93 } 94 95 return r; 96 ]]> 97 </getter> 98 </property> 99 100 <constructor> 101 <![CDATA[ 102 this._notifierID = Zotero.Notifier.registerObserver(this, ['item'], 'relatedbox'); 103 ]]> 104 </constructor> 105 106 <destructor> 107 <![CDATA[ 108 Zotero.Notifier.unregisterObserver(this._notifierID); 109 ]]> 110 </destructor> 111 112 <!-- TODO: Asyncify --> 113 <method name="notify"> 114 <parameter name="event"/> 115 <parameter name="type"/> 116 <parameter name="ids"/> 117 <parameter name="extraData"/> 118 <body><![CDATA[ 119 if (event != 'modify' || !this.item || !this.item.id) return; 120 for (let i = 0; i < ids.length; i++) { 121 let id = ids[i]; 122 if (id != this.item.id) { 123 continue; 124 } 125 this.refresh(); 126 break; 127 } 128 ]]></body> 129 </method> 130 131 <method name="refresh"> 132 <body><![CDATA[ 133 var addButton = this.id('addButton'); 134 addButton.hidden = !this.editable; 135 136 var rows = this.id('relatedRows'); 137 while(rows.hasChildNodes()) 138 rows.removeChild(rows.firstChild); 139 140 if (this.item) { 141 var relatedKeys = this.item.relatedItems; 142 for (var i = 0; i < relatedKeys.length; i++) { 143 let key = relatedKeys[i]; 144 let relatedItem = Zotero.Items.getByLibraryAndKey( 145 this.item.libraryID, key 146 ); 147 if (!relatedItem) { 148 Zotero.debug(`Related item ${this.item.libraryID}/${key} not found ` 149 + `for item ${this.item.libraryKey}`, 2); 150 continue; 151 } 152 let id = relatedItem.id; 153 let icon = document.createElement("image"); 154 icon.className = "zotero-box-icon"; 155 icon.setAttribute('src', relatedItem.getImageSrc()); 156 157 var label = document.createElement("label"); 158 label.className = "zotero-box-label"; 159 label.setAttribute('value', relatedItem.getDisplayTitle()); 160 label.setAttribute('crop','end'); 161 label.setAttribute('flex','1'); 162 163 var box = document.createElement('box'); 164 box.setAttribute('onclick', 165 "document.getBindingParent(this).showItem(" + id + ")"); 166 box.setAttribute('class','zotero-clicky'); 167 box.setAttribute('flex','1'); 168 box.appendChild(icon); 169 box.appendChild(label); 170 171 if (this.editable) { 172 var remove = document.createElement("label"); 173 remove.setAttribute('value','-'); 174 remove.setAttribute('onclick', 175 "document.getBindingParent(this).remove(" + id + ");"); 176 remove.setAttribute('class','zotero-clicky zotero-clicky-minus'); 177 } 178 179 var row = document.createElement("row"); 180 row.appendChild(box); 181 if (this.editable) { 182 row.appendChild(remove); 183 } 184 rows.appendChild(row); 185 } 186 this.updateCount(rows.childNodes.length); 187 } 188 ]]></body> 189 </method> 190 <method name="add"> 191 <body><![CDATA[ 192 return Zotero.spawn(function* () { 193 var io = {dataIn: null, dataOut: null}; 194 195 window.openDialog('chrome://zotero/content/selectItemsDialog.xul', '', 196 'chrome,dialog=no,modal,centerscreen,resizable=yes', io); 197 198 if (!io.dataOut || !io.dataOut.length) { 199 return; 200 } 201 var relItems = yield Zotero.Items.getAsync(io.dataOut); 202 if (!relItems.length) { 203 return; 204 } 205 206 if (relItems[0].libraryID != this.item.libraryID) { 207 // FIXME 208 var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"] 209 .getService(Components.interfaces.nsIPromptService); 210 ps.alert(null, "", "You cannot relate items in different libraries."); 211 return; 212 } 213 yield Zotero.DB.executeTransaction(function* () { 214 for (let relItem of relItems) { 215 if (this.item.addRelatedItem(relItem)) { 216 yield this.item.save({ 217 skipDateModifiedUpdate: true 218 }); 219 } 220 if (relItem.addRelatedItem(this.item)) { 221 yield relItem.save({ 222 skipDateModifiedUpdate: true 223 }); 224 } 225 } 226 }.bind(this)); 227 }, this); 228 ]]></body> 229 </method> 230 <method name="remove"> 231 <parameter name="id"/> 232 <body><![CDATA[ 233 return Zotero.spawn(function* () { 234 var item = yield Zotero.Items.getAsync(id); 235 if (item) { 236 yield Zotero.DB.executeTransaction(function* () { 237 if (this.item.removeRelatedItem(item)) { 238 yield this.item.save({ 239 skipDateModifiedUpdate: true 240 }); 241 } 242 if (item.removeRelatedItem(this.item)) { 243 yield item.save({ 244 skipDateModifiedUpdate: true 245 }); 246 } 247 }.bind(this)); 248 } 249 }, this); 250 ]]></body> 251 </method> 252 <method name="showItem"> 253 <parameter name="id"/> 254 <body> 255 <![CDATA[ 256 if(id) 257 { 258 var p; 259 if(window.ZoteroPane_Local) 260 { 261 p = window.ZoteroPane_Local; 262 } 263 else 264 { 265 var win; 266 267 if(window.opener && window.opener.ZoteroPane) 268 { 269 win = window.opener; 270 } 271 else 272 { 273 var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"] 274 .getService(Components.interfaces.nsIWindowMediator); 275 win = wm.getMostRecentWindow('navigator:browser'); 276 if(!win) 277 return; 278 } 279 280 p = win.ZoteroPane; 281 } 282 283 p.selectItem(id); 284 } 285 ]]> 286 </body> 287 </method> 288 <method name="updateCount"> 289 <parameter name="count"/> 290 <body> 291 <![CDATA[ 292 if (count == null) { 293 var count = this.item.relatedItems.length; 294 } 295 296 var str = 'pane.item.related.count.'; 297 switch (count){ 298 case 0: 299 str += 'zero'; 300 break; 301 case 1: 302 str += 'singular'; 303 break; 304 default: 305 str += 'plural'; 306 break; 307 } 308 this.id('relatedNum').value = Zotero.getString(str, [count]); 309 ]]> 310 </body> 311 </method> 312 <method name="id"> 313 <parameter name="id"/> 314 <body> 315 <![CDATA[ 316 return document.getAnonymousNodes(this)[0].getElementsByAttribute('id',id)[0]; 317 ]]> 318 </body> 319 </method> 320 </implementation> 321 <content> 322 <xul:vbox xbl:inherits="flex" class="zotero-box"> 323 <xul:hbox align="center"> 324 <xul:label id="relatedNum"/> 325 <xul:button id="addButton" label="&zotero.item.add;" 326 oncommand="this.parentNode.parentNode.parentNode.add();"/> 327 </xul:hbox> 328 <xul:grid flex="1"> 329 <xul:columns> 330 <xul:column flex="1"/> 331 <xul:column/> 332 </xul:columns> 333 <xul:rows id="relatedRows"/> 334 </xul:grid> 335 </xul:vbox> 336 </content> 337 </binding> 338 </bindings>