www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | Submodules | README | LICENSE

merge.xml (11984B)


      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 		  xmlns:html="http://www.w3.org/1999/xhtml">
     33 	
     34 	<binding id="merge-group">
     35 		<resources>
     36 			<stylesheet src="chrome://zotero/skin/merge.css"/>
     37 		</resources>
     38 		
     39 		<implementation>
     40 			<constructor>
     41 			<![CDATA[
     42 				this._leftpane = this._id('leftpane');
     43 				this._rightpane = this._id('rightpane');
     44 				this._mergepane = this._id('mergepane');
     45 			]]>
     46 			</constructor>
     47 			
     48 			<field name="libraryID"/>
     49 			
     50 			<field name="_data"/>
     51 			<property name="data" onget="return this._data;">
     52 				<setter>
     53 				<![CDATA[
     54 					this._data = val;
     55 					this.refresh();
     56 				]]>
     57 				</setter>
     58 			</property>
     59 			
     60 			<property name="merged" onget="return this._mergepane.data"/>
     61 			
     62 			<field name="_type"/>
     63 			<property name="type" onget="return this._type;">
     64 				<setter>
     65 				<![CDATA[
     66 					switch (val) {
     67 						case 'item':
     68 						case 'attachment':
     69 						case 'note':
     70 						case 'file':
     71 							break;
     72 						
     73 						default:
     74 							throw new Error(`Unsupported merge object type '${type}'`);
     75 					}
     76 					
     77 					this._type = val;
     78 					var hbox = document.getAnonymousNodes(this)[0];
     79 					hbox.setAttribute('mergetype', val);
     80 				]]>
     81 				</setter>
     82 			</property>
     83 			
     84 			<property name="leftCaption" onset="this._leftpane.caption.label = val"/>
     85 			<property name="rightCaption" onset="this._rightpane.caption.label = val"/>
     86 			<property name="mergeCaption" onset="this._mergepane.caption.label = val"/>
     87 			
     88 			<field name="_leftpane"/>
     89 			<property name="leftpane" onget="return this._leftpane"/>
     90 			<field name="_rightpane"/>
     91 			<property name="rightpane" onget="return this._rightpane"/>
     92 			<field name="_mergepane"/>
     93 			<property name="mergepane" onget="return this._mergepane"/>
     94 			
     95 			<property name="onSelectionChange"/>
     96 			
     97 			<method name="refresh">
     98 				<body>
     99 				<![CDATA[
    100 					if (this._data.left.deleted && this._data.right.deleted) {
    101 						throw new Error("'left' and 'right' cannot both be deleted");
    102 					}
    103 					
    104 					// Check for note or attachment
    105 					if (!this.type) {
    106 						this.type = this._getTypeFromObject(
    107 							this._data.left.deleted ?  this._data.right : this._data.left
    108 						);
    109 					}
    110 					
    111 					var showButton = this.type != 'item';
    112 					
    113 					this._leftpane.showButton = showButton;
    114 					this._rightpane.showButton = showButton;
    115 					this._leftpane.libraryID = this.libraryID;
    116 					this._rightpane.libraryID = this.libraryID;
    117 					this._mergepane.libraryID = this.libraryID;
    118 					this._leftpane.data = this._data.left;
    119 					this._rightpane.data = this._data.right;
    120 					this._mergepane.data = this._data.merge;
    121 					
    122 					if (this._data.selected == 'left') {
    123 						this.choosePane(this._leftpane);
    124 					}
    125 					else {
    126 						this.choosePane(this._rightpane);
    127 					}
    128 					
    129 					/*
    130 					
    131 					Code to display only the different values -- not used
    132 					
    133 					var diff = this._leftpane.ref.diff(this._rightpane.ref, true);
    134 					
    135 					var fields = [];
    136 					var diffFields = [];
    137 					for (var field in diff[0].primary) {
    138 						fields.push(field);
    139 						if (diff[0].primary[field] != diff[1].primary[field]) {
    140 							diffFields.push(field);
    141 						}
    142 					}
    143 					for (var field in diff[0].fields) {
    144 						fields.push(field);
    145 						if (diff[0].fields[field] != diff[1].fields[field]) {
    146 							diffFields.push(field);
    147 						}
    148 					}
    149 					
    150 					this._leftpane.objectbox.fieldOrder = fields;
    151 					this._rightpane.objectbox.fieldOrder = fields;
    152 					
    153 					// Display merge pane if item types match
    154 					if (this._leftpane.ref.itemTypeID == this._rightpane.ref.itemTypeID) {
    155 						this._leftpane.objectbox.visibleFields = fields;
    156 						this._rightpane.objectbox.visibleFields = fields;
    157 						
    158 						this._leftpane.objectbox.clickable = false;
    159 						this._rightpane.objectbox.clickable = false;
    160 						this._leftpane.objectbox.clickableFields = diffFields;
    161 						this._rightpane.objectbox.clickableFields = diffFields;
    162 						
    163 						var mergeItem = new Zotero.Item(this._leftpane.ref.itemTypeID);
    164 						this._mergepane.ref = mergeItem;
    165 						this._mergepane.objectbox.visibleFields = fields;
    166 					}
    167 					// Otherwise only allow clicking on item types
    168 					else {
    169 						this._leftpane.objectbox.clickableFields = ['itemType'];
    170 						this._rightpane.objectbox.clickableFields = ['itemType'];
    171 					}
    172 					*/
    173 					
    174 					
    175 					this._mergepane.objectbox.editable = true;
    176 					
    177 					
    178 					/*
    179 					
    180 					No need to refresh if not comparing fields
    181 					
    182 					this._leftpane.objectbox.refresh();
    183 					this._rightpane.objectbox.refresh();
    184 					*/
    185 				]]>
    186 				</body>
    187 			</method>
    188 			
    189 			
    190 			<method name="choosePane">
    191 				<parameter name="pane"/>
    192 				<body>
    193 				<![CDATA[
    194 					if (pane.getAttribute('anonid') == 'leftpane') {
    195 						var position = 'left';
    196 						var otherPane = this._rightpane;
    197 					}
    198 					else {
    199 						var position = 'right';
    200 						var otherPane = this._leftpane;
    201 					}
    202 					
    203 					pane.removeAttribute("selected");
    204 					otherPane.removeAttribute("selected");
    205 					pane.setAttribute("selected", "true");
    206 					
    207 					if (pane.deleted) {
    208 						this._mergepane.deleted = true;
    209 					}
    210 					else {
    211 						this._mergepane.data = pane.data;
    212 					}
    213 					
    214 					if (this.onSelectionChange) {
    215 						this.onSelectionChange();
    216 					}
    217 				]]>
    218 				</body>
    219 			</method>
    220 			
    221 			
    222 			<method name="_getTypeFromObject">
    223 				<parameter name="obj"/>
    224 				<body>
    225 				<![CDATA[
    226 					if (!obj.itemType) {
    227 						Zotero.debug(obj, 1);
    228 						throw new Error("obj is not item JSON");
    229 					}
    230 					if (obj.itemType == 'attachment' || obj.itemType == 'note') {
    231 						return obj.itemType;
    232 					}
    233 					return 'item';
    234 				]]>
    235 				</body>
    236 			</method>
    237 			
    238 			<method name="_id">
    239 				<parameter name="id"/>
    240 				<body>
    241 				<![CDATA[
    242 					return document.getAnonymousNodes(this)[0].getElementsByAttribute('anonid',id)[0];
    243 				]]>
    244 				</body>
    245 			</method>
    246 		</implementation>
    247 		
    248 		<content>
    249 			<xul:hbox id="merge-group" flex="1">
    250 				<xul:zoteromergepane anonid="leftpane" flex="1"/>
    251 				<xul:zoteromergepane anonid="rightpane" flex="1"/>
    252 				<xul:zoteromergepane anonid="mergepane" flex="1"/>
    253 			</xul:hbox>
    254 		</content>
    255 	</binding>
    256 	
    257 	
    258 	<binding id="merge-pane">
    259 		<resources>
    260 			<stylesheet src="chrome://zotero/skin/bindings/merge.css"/>
    261 		</resources>
    262 		
    263 		<implementation>
    264 			<constructor>
    265 			<![CDATA[
    266 				this.parent = document.getBindingParent(this.parentNode);
    267 				this.isMergePane = this.getAttribute('anonid') == 'mergepane';
    268 				
    269 				if (!this.isMergePane) {
    270 					this.pane.onclick = function () {
    271 						this.parent.choosePane(this);
    272 					}.bind(this);
    273 				}
    274 			]]>
    275 			</constructor>
    276 			
    277 			<property name="type" onget="return this.parent.type" readonly="true"/>
    278 			<property name="caption" onget="return this._id('caption')" readonly="true"/>
    279 			<field name="showButton"/>
    280 			<property name="pane" onget="return document.getAnonymousNodes(this)[0]"/>
    281 			<property name="objectbox" onget="return this._id('objectbox')" readonly="true"/>
    282 			
    283 			<field name="_deleted"/>
    284 			<property name="deleted">
    285 				<setter>
    286 				<![CDATA[
    287 					this._deleted = !!val;
    288 					
    289 					var placeholder = this._id('object-placeholder');
    290 					if (placeholder) {
    291 						placeholder.hidden = !!val;
    292 					}
    293 					else {
    294 						this._id('objectbox').hidden = true;
    295 					}
    296 					var deleteBox = this._id('delete-box');
    297 					deleteBox.hidden = !val;
    298 				]]>
    299 				</setter>
    300 			</property>
    301 			
    302 			<field name="libraryID"/>
    303 			
    304 			<field name="_data"/>
    305 			<property name="data" onget="return this._data">
    306 				<setter>
    307 				<![CDATA[
    308 					this._data = val;
    309 					
    310 					var button = this._id('choose-button');
    311 					button.label = Zotero.getString('sync.conflict.chooseThisVersion');
    312 					if (this.showButton) {
    313 						button.onclick = () => this.parent.choosePane(this);
    314 						button.style.visibility = 'visible';
    315 					}
    316 					else {
    317 						button.style.visibility = 'hidden';
    318 					}
    319 					
    320 					if (val.deleted) {
    321 						this.deleted = true;
    322 						return;
    323 					}
    324 					
    325 					this.deleted = false;
    326 					
    327 					// Replace XUL placeholder with XUL object box of given type
    328 					var elementName;
    329 					switch (this.type) {
    330 						case 'item':
    331 							elementName = 'zoteroitembox';
    332 							break;
    333 						
    334 						case 'attachment':
    335 						case 'file':
    336 							elementName = 'zoteroattachmentbox';
    337 							break;
    338 						
    339 						case 'note':
    340 							elementName = 'zoteronoteeditor';
    341 							break;
    342 						
    343 						default:
    344 							throw new Error("Object type '" + this.type + "' not supported");
    345 					}
    346 					
    347 					var objbox = document.createElement(elementName);
    348 					
    349 					var parentRow = this._id('parent-row');
    350 					if (val.parentItem) {
    351 						parentRow.textContent = '';
    352 						
    353 						let label = document.createElement('span');
    354 						label.textContent = Zotero.getString('pane.item.parentItem');
    355 						parentRow.appendChild(label);
    356 						
    357 						let parentItem = Zotero.Items.getByLibraryAndKey(this.libraryID, val.parentItem);
    358 						let text = document.createTextNode(" " + parentItem.getDisplayTitle(true));
    359 						parentRow.appendChild(text);
    360 						
    361 						parentRow.hidden = false;
    362 					}
    363 					else {
    364 						parentRow.hidden = true;
    365 					}
    366 					
    367 					if (this._id('object-placeholder')) {
    368 						var placeholder = this._id('object-placeholder');
    369 						placeholder.parentNode.replaceChild(objbox, placeholder);
    370 					}
    371 					else {
    372 						var oldObjBox = this._id('objectbox');
    373 						oldObjBox.parentNode.replaceChild(objbox, oldObjBox);
    374 					}
    375 					
    376 					objbox.setAttribute("anonid", "objectbox");
    377 					objbox.setAttribute("flex", "1");
    378 					objbox.mode = this.type == 'file' ? 'filemerge' : 'merge';
    379 					
    380 					// Store JSON
    381 					this._data = val;
    382 					
    383 					// Create a copy of the JSON that we can clean for display, since the remote object
    384 					// might reference things that don't exist locally
    385 					var displayJSON = Object.assign({}, val);
    386 					displayJSON.collections = [];
    387 					
    388 					// Create item from JSON for metadata box
    389 					var item = new Zotero.Item(val.itemType);
    390 					item.libraryID = this.libraryID;
    391 					item.fromJSON(displayJSON);
    392 					objbox.item = item;
    393 				]]>
    394 				</setter>
    395 			</property>
    396 			
    397 			<field name="parent"/>
    398 			
    399 			<method name="click">
    400 				<body><![CDATA[
    401 					this.pane.click();
    402 				]]></body>
    403 			</method>
    404 			
    405 			<method name="_id">
    406 				<parameter name="id"/>
    407 				<body>
    408 				<![CDATA[
    409 					var elems = document.getAnonymousNodes(this)[0].getElementsByAttribute('anonid', id);
    410 					return elems.length ? elems[0] : false;
    411 				]]>
    412 				</body>
    413 			</method>
    414 		</implementation>
    415 		
    416 		<content>
    417 			<xul:vbox flex="1">
    418 				<xul:groupbox anonid="merge-pane" flex="1">
    419 					<xul:caption anonid="caption"/>
    420 					<html:div anonid="parent-row" hidden="true"/>
    421 					<xul:box anonid="object-placeholder"/>
    422 					<xul:hbox anonid="delete-box" hidden="true" flex="1">
    423 						<xul:label value="&zotero.merge.deleted;"/>
    424 					</xul:hbox>
    425 				</xul:groupbox>
    426 				<xul:button anonid="choose-button"/>
    427 			</xul:vbox>
    428 		</content>
    429 	</binding>
    430 </bindings>