www

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

collectionTreeRow.js (10865B)


      1 /*
      2     ***** BEGIN LICENSE BLOCK *****
      3     
      4     Copyright © 2015 Center for History and New Media
      5                      George Mason University, Fairfax, Virginia, USA
      6                      http://zotero.org
      7     
      8     This file is part of Zotero.
      9     
     10     Zotero is free software: you can redistribute it and/or modify
     11     it under the terms of the GNU Affero General Public License as published by
     12     the Free Software Foundation, either version 3 of the License, or
     13     (at your option) any later version.
     14     
     15     Zotero is distributed in the hope that it will be useful,
     16     but WITHOUT ANY WARRANTY; without even the implied warranty of
     17     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     18     GNU Affero General Public License for more details.
     19     
     20     You should have received a copy of the GNU Affero General Public License
     21     along with Zotero.  If not, see <http://www.gnu.org/licenses/>.
     22     
     23     ***** END LICENSE BLOCK *****
     24 */
     25 
     26 "use strict";
     27 
     28 Zotero.CollectionTreeRow = function (collectionTreeView, type, ref, level, isOpen) {
     29 	this.view = collectionTreeView;
     30 	this.type = type;
     31 	this.ref = ref;
     32 	this.level = level || 0
     33 	this.isOpen = isOpen || false;
     34 	this.onUnload = null;
     35 }
     36 
     37 
     38 Zotero.CollectionTreeRow.prototype.__defineGetter__('id', function () {
     39 	switch (this.type) {
     40 		case 'library':
     41 		case 'group':
     42 		case 'feed':
     43 			return 'L' + this.ref.libraryID;
     44 		
     45 		case 'collection':
     46 			return 'C' + this.ref.id;
     47 		
     48 		case 'search':
     49 			return 'S' + this.ref.id;
     50 		
     51 		case 'duplicates':
     52 			return 'D' + this.ref.libraryID;
     53 		
     54 		case 'unfiled':
     55 			return 'U' + this.ref.libraryID;
     56 		
     57 		case 'publications':
     58 			return 'P' + this.ref.libraryID;
     59 			
     60 		case 'trash':
     61 			return 'T' + this.ref.libraryID;
     62 		
     63 		case 'header':
     64 			switch (this.ref.id) {
     65 				case 'group-libraries-header':
     66 					return "HG";
     67 				case 'feed-libraries-header':
     68 					return "HF";
     69 			}
     70 			break;
     71 	}
     72 	
     73 	return '';
     74 });
     75 
     76 Zotero.CollectionTreeRow.prototype.isLibrary = function (includeGlobal)
     77 {
     78 	if (includeGlobal) {
     79 		var global = ['library', 'group', 'feed'];
     80 		return global.indexOf(this.type) != -1;
     81 	}
     82 	return this.type == 'library';
     83 }
     84 
     85 Zotero.CollectionTreeRow.prototype.isCollection = function()
     86 {
     87 	return this.type == 'collection';
     88 }
     89 
     90 Zotero.CollectionTreeRow.prototype.isSearch = function()
     91 {
     92 	return this.type == 'search';
     93 }
     94 
     95 Zotero.CollectionTreeRow.prototype.isDuplicates = function () {
     96 	return this.type == 'duplicates';
     97 }
     98 
     99 Zotero.CollectionTreeRow.prototype.isUnfiled = function () {
    100 	return this.type == 'unfiled';
    101 }
    102 
    103 Zotero.CollectionTreeRow.prototype.isTrash = function()
    104 {
    105 	return this.type == 'trash';
    106 }
    107 
    108 Zotero.CollectionTreeRow.prototype.isHeader = function () {
    109 	return this.type == 'header';
    110 }
    111 
    112 Zotero.CollectionTreeRow.prototype.isPublications = function() {
    113 	return this.type == 'publications';
    114 }
    115 
    116 Zotero.CollectionTreeRow.prototype.isGroup = function() {
    117 	return this.type == 'group';
    118 }
    119 
    120 Zotero.CollectionTreeRow.prototype.isFeed = function() {
    121 	return this.type == 'feed';
    122 }
    123 
    124 Zotero.CollectionTreeRow.prototype.isSeparator = function () {
    125 	return this.type == 'separator';
    126 }
    127 
    128 Zotero.CollectionTreeRow.prototype.isBucket = function()
    129 {
    130 	return this.type == 'bucket';
    131 }
    132 
    133 Zotero.CollectionTreeRow.prototype.isShare = function()
    134 {
    135 	return this.type == 'share';
    136 }
    137 
    138 
    139 
    140 // Special
    141 Zotero.CollectionTreeRow.prototype.isWithinGroup = function () {
    142 	return this.ref && !this.isHeader()
    143 		&& Zotero.Libraries.get(this.ref.libraryID).libraryType == 'group';
    144 }
    145 
    146 Zotero.CollectionTreeRow.prototype.isWithinEditableGroup = function () {
    147 	if (!this.isWithinGroup()) {
    148 		return false;
    149 	}
    150 	var groupID = Zotero.Groups.getGroupIDFromLibraryID(this.ref.libraryID);
    151 	return Zotero.Groups.get(groupID).editable;
    152 }
    153 
    154 Zotero.CollectionTreeRow.prototype.__defineGetter__('editable', function () {
    155 	if (this.isTrash() || this.isShare() || this.isBucket()) {
    156 		return false;
    157 	}
    158 	if (this.isGroup() || this.isFeed()) {
    159 		return this.ref.editable;
    160 	}
    161 	if (!this.isWithinGroup() || this.isPublications()) {
    162 		return true;
    163 	}
    164 	var libraryID = this.ref.libraryID;
    165 	if (this.isCollection() || this.isSearch() || this.isDuplicates() || this.isUnfiled()) {
    166 		var type = Zotero.Libraries.get(libraryID).libraryType;
    167 		if (type == 'group') {
    168 			var groupID = Zotero.Groups.getGroupIDFromLibraryID(libraryID);
    169 			var group = Zotero.Groups.get(groupID);
    170 			return group.editable;
    171 		}
    172 		throw ("Unknown library type '" + type + "' in Zotero.CollectionTreeRow.editable");
    173 	}
    174 	return false;
    175 });
    176 
    177 Zotero.CollectionTreeRow.prototype.__defineGetter__('filesEditable', function () {
    178 	if (this.isTrash() || this.isShare() || this.isFeed()) {
    179 		return false;
    180 	}
    181 	if (!this.isWithinGroup() || this.isPublications()) {
    182 		return true;
    183 	}
    184 	var libraryID = this.ref.libraryID;
    185 	if (this.isGroup()) {
    186 		return this.ref.filesEditable;
    187 	}
    188 	if (this.isCollection() || this.isSearch() || this.isDuplicates() || this.isUnfiled()) {
    189 		var type = Zotero.Libraries.get(libraryID).libraryType;
    190 		if (type == 'group') {
    191 			var groupID = Zotero.Groups.getGroupIDFromLibraryID(libraryID);
    192 			var group = Zotero.Groups.get(groupID);
    193 			return group.filesEditable;
    194 		}
    195 		throw ("Unknown library type '" + type + "' in Zotero.CollectionTreeRow.filesEditable");
    196 	}
    197 	return false;
    198 });
    199 
    200 
    201 Zotero.CollectionTreeRow.visibilityGroups = {'feed': 'feed'};
    202 
    203 
    204 Zotero.CollectionTreeRow.prototype.__defineGetter__('visibilityGroup', function() {
    205 	return Zotero.CollectionTreeRow.visibilityGroups[this.type] || 'default';
    206 });
    207 
    208 
    209 Zotero.CollectionTreeRow.prototype.getName = function()
    210 {
    211 	switch (this.type) {
    212 		case 'library':
    213 			return Zotero.getString('pane.collections.library');
    214 		
    215 		case 'publications':
    216 			return Zotero.getString('pane.collections.publications');
    217 		
    218 		case 'trash':
    219 			return Zotero.getString('pane.collections.trash');
    220 		
    221 		case 'header':
    222 			return this.ref.label;
    223 		
    224 		case 'separator':
    225 			return "";
    226 		
    227 		default:
    228 			return this.ref.name;
    229 	}
    230 }
    231 
    232 Zotero.CollectionTreeRow.prototype.getItems = Zotero.Promise.coroutine(function* ()
    233 {
    234 	switch (this.type) {
    235 		// Fake results if this is a shared library
    236 		case 'share':
    237 			return this.ref.getAll();
    238 		
    239 		case 'bucket':
    240 			return this.ref.getItems();
    241 	}
    242 	
    243 	var ids = yield this.getSearchResults();
    244 	
    245 	// Filter out items that exist in the items table (where search results come from) but that haven't
    246 	// yet been registered. This helps prevent unloaded-data crashes when switching collections while
    247 	// items are being added (e.g., during sync).
    248 	var len = ids.length;
    249 	ids = ids.filter(id => Zotero.Items.getLibraryAndKeyFromID(id));
    250 	if (len > ids.length) {
    251 		let diff = len - ids.length;
    252 		Zotero.debug(`Not showing ${diff} unloaded item${diff != 1 ? 's' : ''}`);
    253 	}
    254 	
    255 	if (!ids.length) {
    256 		return []
    257 	}
    258 	
    259 	return Zotero.Items.getAsync(ids);
    260 });
    261 
    262 Zotero.CollectionTreeRow.prototype.getSearchResults = Zotero.Promise.coroutine(function* (asTempTable) {
    263 	if (Zotero.CollectionTreeCache.lastTreeRow && Zotero.CollectionTreeCache.lastTreeRow.id !== this.id) {
    264 		Zotero.CollectionTreeCache.clear();
    265 	}
    266 	
    267 	if(!Zotero.CollectionTreeCache.lastResults) {
    268 		var s = yield this.getSearchObject();
    269 		Zotero.CollectionTreeCache.lastResults = yield s.search();
    270 		Zotero.CollectionTreeCache.lastTreeRow = this;
    271 	}
    272 	
    273 	if(asTempTable) {
    274 		if(!Zotero.CollectionTreeCache.lastTempTable) {
    275 			Zotero.CollectionTreeCache.lastTempTable = yield Zotero.Search.idsToTempTable(Zotero.CollectionTreeCache.lastResults);
    276 		}
    277 		return Zotero.CollectionTreeCache.lastTempTable;
    278 	}
    279 	return Zotero.CollectionTreeCache.lastResults;
    280 });
    281 
    282 /*
    283  * Returns the search object for the currently display
    284  *
    285  * This accounts for the collection, saved search, quicksearch, tags, etc.
    286  */
    287 Zotero.CollectionTreeRow.prototype.getSearchObject = Zotero.Promise.coroutine(function* () {
    288 	if (Zotero.CollectionTreeCache.lastTreeRow && Zotero.CollectionTreeCache.lastTreeRow.id !== this.id) {
    289 		Zotero.CollectionTreeCache.clear();
    290 	}
    291 	
    292 	if(Zotero.CollectionTreeCache.lastSearch) {
    293 		return Zotero.CollectionTreeCache.lastSearch;
    294 	}	
    295 	
    296 	var includeScopeChildren = false;
    297 	
    298 	// Create/load the inner search
    299 	if (this.ref instanceof Zotero.Search) {
    300 		var s = this.ref;
    301 	}
    302 	else if (this.isDuplicates()) {
    303 		var s = yield this.ref.getSearchObject();
    304 		let tmpTable;
    305 		for (let id in s.conditions) {
    306 			let c = s.conditions[id];
    307 			if (c.condition == 'tempTable') {
    308 				tmpTable = c.value;
    309 				break;
    310 			}
    311 		}
    312 		// Called by ItemTreeView::unregister()
    313 		this.onUnload = async function () {
    314 			await Zotero.DB.queryAsync(`DROP TABLE IF EXISTS ${tmpTable}`);
    315 		};
    316 	}
    317 	else {
    318 		var s = new Zotero.Search();
    319 		s.addCondition('libraryID', 'is', this.ref.libraryID);
    320 		// Library root
    321 		if (this.isLibrary(true)) {
    322 			s.addCondition('noChildren', 'true');
    323 			includeScopeChildren = true;
    324 		}
    325 		else if (this.isCollection()) {
    326 			s.addCondition('noChildren', 'true');
    327 			s.addCondition('collectionID', 'is', this.ref.id);
    328 			if (Zotero.Prefs.get('recursiveCollections')) {
    329 				s.addCondition('recursive', 'true');
    330 			}
    331 			includeScopeChildren = true;
    332 		}
    333 		else if (this.isPublications()) {
    334 			s.addCondition('publications', 'true');
    335 		}
    336 		else if (this.isTrash()) {
    337 			s.addCondition('deleted', 'true');
    338 		}
    339 		else {
    340 			throw new Error('Invalid search mode ' + this.type);
    341 		}
    342 	}
    343 	
    344 	// Create the outer (filter) search
    345 	var s2 = new Zotero.Search();
    346 	s2.addCondition('libraryID', 'is', this.ref.libraryID);
    347 	
    348 	if (this.isTrash()) {
    349 		s2.addCondition('deleted', 'true');
    350 	}
    351 	s2.setScope(s, includeScopeChildren);
    352 	
    353 	if (this.searchText) {
    354 		var cond = 'quicksearch-' + Zotero.Prefs.get('search.quicksearch-mode');
    355 		s2.addCondition(cond, 'contains', this.searchText);
    356 	}
    357 	
    358 	if (this.tags){
    359 		for (let tag of this.tags) {
    360 			s2.addCondition('tag', 'is', tag);
    361 		}
    362 	}
    363 	
    364 	Zotero.CollectionTreeCache.lastTreeRow = this;
    365 	Zotero.CollectionTreeCache.lastSearch = s2;
    366 	return s2;
    367 });
    368 
    369 
    370 /**
    371  * Returns all the tags used by items in the current view
    372  *
    373  * @return {Promise<Object[]>}
    374  */
    375 Zotero.CollectionTreeRow.prototype.getChildTags = Zotero.Promise.coroutine(function* () {
    376 	switch (this.type) {
    377 		// TODO: implement?
    378 		case 'share':
    379 			return [];
    380 		
    381 		case 'bucket':
    382 			return [];
    383 	}
    384 	var results = yield this.getSearchResults(true);
    385 	return Zotero.Tags.getAllWithinSearchResults(results);
    386 });
    387 
    388 
    389 Zotero.CollectionTreeRow.prototype.setSearch = function (searchText) {
    390 	Zotero.CollectionTreeCache.clear();
    391 	this.searchText = searchText;
    392 }
    393 
    394 Zotero.CollectionTreeRow.prototype.setTags = function (tags) {
    395 	Zotero.CollectionTreeCache.clear();
    396 	this.tags = tags;
    397 }
    398 
    399 /*
    400  * Returns TRUE if saved search, quicksearch or tag filter
    401  */
    402 Zotero.CollectionTreeRow.prototype.isSearchMode = function() {
    403 	switch (this.type) {
    404 		case 'search':
    405 		case 'publications':
    406 		case 'trash':
    407 			return true;
    408 	}
    409 	
    410 	// Quicksearch
    411 	if (this.searchText != '') {
    412 		return true;
    413 	}
    414 	
    415 	// Tag filter
    416 	if (this.tags && this.tags.size) {
    417 		return true;
    418 	}
    419 }