www

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

report.js (9710B)


      1 /*
      2     ***** BEGIN LICENSE BLOCK *****
      3     
      4     Copyright © 2009 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 
     27 Zotero.Report = {};
     28 
     29 Zotero.Report.HTML = new function () {
     30 	let domParser = Components.classes["@mozilla.org/xmlextras/domparser;1"]
     31 		.createInstance(Components.interfaces.nsIDOMParser);
     32 	
     33 	this.listGenerator = function* (items, combineChildItems) {
     34 		yield '<!DOCTYPE html>\n'
     35 			+ '<html>\n'
     36 			+ '	<head>\n'
     37 			+ '		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />\n'
     38 			+ '		<title>' + Zotero.getString('report.title.default') + '</title>\n'
     39 			+ '		<link rel="stylesheet" type="text/css" href="zotero://report/detail.css"/>\n'
     40 			+ '		<link rel="stylesheet" type="text/css" media="screen,projection" href="zotero://report/detail_screen.css"/>\n'
     41 			+ '		<link rel="stylesheet" type="text/css" media="print" href="zotero://report/detail_print.css"/>\n'
     42 			+ '	</head>\n'
     43 			+ '	<body>\n'
     44 			+ '		<ul class="report' + (combineChildItems ? ' combineChildItems' : '') + '">';
     45 		
     46 		for (let i=0; i<items.length; i++) {
     47 			let obj = items[i];
     48 			
     49 			let content = '\n\t\t\t<li id="item_' + obj.key + '" class="item ' + obj.itemType + '">\n';
     50 			
     51 			if (obj.title) {
     52 				// Top-level item matched search, so display title
     53 				if (obj.reportSearchMatch) {
     54 					content += '\t\t\t<h2>' + escapeXML(obj.title) + '</h2>\n';
     55 				}
     56 				// Non-matching parent, so display "Parent Item: [Title]"
     57 				else {
     58 					content += '\t\t\t<h2 class="parentItem">' + escapeXML(Zotero.getString('report.parentItem'))
     59 						+ ' <span class="title">' + escapeXML(obj.title) + '</span></h2>\n';
     60 				}
     61 			}
     62 			
     63 			// If parent matches search, display parent item metadata table and tags
     64 			if (obj.reportSearchMatch) {
     65 				content += _generateMetadataTable(obj);
     66 				
     67 				content += _generateTagsList(obj);
     68 				
     69 				// Independent note
     70 				if (obj['note']) {
     71 					content += '\n\t\t\t';
     72 					content += getNoteHTML(obj.note);
     73 				}
     74 			}
     75 			
     76 			// Children
     77 			if (obj.reportChildren) {
     78 				// Child notes
     79 				if (obj.reportChildren.notes.length) {
     80 					// Only display "Notes:" header if parent matches search
     81 					if (obj.reportSearchMatch) {
     82 						content += '\t\t\t\t<h3 class="notes">' + escapeXML(Zotero.getString('report.notes')) + '</h3>\n';
     83 					}
     84 					content += '\t\t\t\t<ul class="notes">\n';
     85 					for (let note of obj.reportChildren.notes) {
     86 						content += '\t\t\t\t\t<li id="item_' + note.key + '">\n';
     87 						
     88 						content += getNoteHTML(note.note);
     89 						
     90 						// Child note tags
     91 						content += _generateTagsList(note);
     92 						
     93 						content += '\t\t\t\t\t</li>\n';
     94 					}
     95 					content += '\t\t\t\t</ul>\n';
     96 				}
     97 			
     98 				// Chid attachments
     99 				content += _generateAttachmentsList(obj.reportChildren);
    100 			}
    101 			
    102 			// Related items
    103 			if (obj.reportSearchMatch && Zotero.Relations.relatedItemPredicate in obj.relations) {
    104 				content += '\t\t\t\t<h3 class="related">' + escapeXML(Zotero.getString('itemFields.related')) + '</h3>\n';
    105 				content += '\t\t\t\t<ul class="related">\n';
    106 				var rels = obj.relations[Zotero.Relations.relatedItemPredicate];
    107 				// TEMP
    108 				if (!Array.isArray(rels)) {
    109 					rels = [rels];
    110 				}
    111 				for (let i=0; i<rels.length; i++) {
    112 					let rel = rels[i];
    113 					let relItem = yield Zotero.URI.getURIItem(rel);
    114 					if (relItem) {
    115 						content += '\t\t\t\t\t<li id="item_' + relItem.key + '">';
    116 						content += escapeXML(relItem.getDisplayTitle());
    117 						content += '</li>\n';
    118 					}
    119 				}
    120 				content += '\t\t\t\t</ul>\n';
    121 			}
    122 			
    123 			
    124 			content += '\t\t\t</li>\n\n';
    125 			
    126 			yield content;
    127 		}
    128 		
    129 		yield '\t\t</ul>\n\t</body>\n</html>';
    130 	};
    131 	
    132 	
    133 	function _generateMetadataTable(obj) {
    134 		var table = false;
    135 		var content = '\t\t\t\t<table>\n';
    136 		
    137 		// Item type
    138 		content += '\t\t\t\t\t<tr>\n';
    139 		content += '\t\t\t\t\t\t<th>'
    140 			+ escapeXML(Zotero.getString('itemFields.itemType'))
    141 			+ '</th>\n';
    142 		content += '\t\t\t\t\t\t<td>' + escapeXML(Zotero.ItemTypes.getLocalizedString(obj.itemType)) + '</td>\n';
    143 		content += '\t\t\t\t\t</tr>\n';
    144 		
    145 		// Creators
    146 		if (obj['creators']) {
    147 			table = true;
    148 			var displayText;
    149 			
    150 			for (let creator of obj['creators']) {
    151 				// One field
    152 				if (creator.name !== undefined) {
    153 					displayText = creator.name;
    154 				}
    155 				// Two field
    156 				else {
    157 					displayText = (creator.firstName + ' ' + creator.lastName).trim();
    158 				}
    159 				
    160 				content += '\t\t\t\t\t<tr>\n';
    161 				content += '\t\t\t\t\t\t<th class="' + creator.creatorType + '">'
    162 					+ escapeXML(Zotero.getString('creatorTypes.' + creator.creatorType))
    163 					+ '</th>\n';
    164 				content += '\t\t\t\t\t\t<td>' + escapeXML(displayText) + '</td>\n';
    165 				content += '\t\t\t\t\t</tr>\n';
    166 			}
    167 		}
    168 		
    169 		// Move dateAdded and dateModified to the end of the objay
    170 		var da = obj['dateAdded'];
    171 		var dm = obj['dateModified'];
    172 		delete obj['dateAdded'];
    173 		delete obj['dateModified'];
    174 		obj['dateAdded'] = da;
    175 		obj['dateModified'] = dm;
    176 		
    177 		for (var i in obj) {
    178 			// Skip certain fields
    179 			switch (i) {
    180 				case 'reportSearchMatch':
    181 				case 'reportChildren':
    182 				
    183 				case 'key':
    184 				case 'version':
    185 				case 'itemType':
    186 				case 'title':
    187 				case 'creators':
    188 				case 'note':
    189 				case 'collections':
    190 				case 'relations':
    191 				case 'tags':
    192 				case 'deleted':
    193 				case 'parentItem':
    194 				
    195 				case 'charset':
    196 				case 'contentType':
    197 				case 'linkMode':
    198 				case 'path':
    199 					continue;
    200 			}
    201 			
    202 			try {
    203 				var localizedFieldName = Zotero.ItemFields.getLocalizedString(obj.itemType, i);
    204 			}
    205 			// Skip fields we don't have a localized string for
    206 			catch (e) {
    207 				Zotero.debug('Localized string not available for ' + 'itemFields.' + i, 2);
    208 				continue;
    209 			}
    210 			
    211 			obj[i] = (obj[i] + '').trim();
    212 			
    213 			// Skip empty fields
    214 			if (!obj[i]) {
    215 				continue;
    216 			}
    217 			
    218 			table = true;
    219 			var fieldText;
    220 			
    221 			if (i == 'url' && obj[i].match(/^https?:\/\//)) {
    222 				fieldText = '<a href="' + escapeXML(obj[i]) + '">' + escapeXML(obj[i]) + '</a>';
    223 			}
    224 			// Hyperlink DOI
    225 			else if (i == 'DOI') {
    226 				fieldText = '<a href="' + escapeXML('http://doi.org/' + obj[i]) + '">'
    227 					+ escapeXML(obj[i]) + '</a>';
    228 			}
    229 			// Remove SQL date from multipart dates
    230 			// (e.g. '2006-00-00 Summer 2006' becomes 'Summer 2006')
    231 			else if (i=='date') {
    232 				fieldText = escapeXML(Zotero.Date.multipartToStr(obj[i]));
    233 			}
    234 			// Convert dates to local format
    235 			else if (i=='accessDate' || i=='dateAdded' || i=='dateModified') {
    236 				var date = Zotero.Date.isoToDate(obj[i], true)
    237 				fieldText = escapeXML(date.toLocaleString());
    238 			}
    239 			else {
    240 				fieldText = escapeXML(obj[i]);
    241 			}
    242 			
    243 			content += '\t\t\t\t\t<tr>\n\t\t\t\t\t<th>' + escapeXML(localizedFieldName)
    244 				+ '</th>\n\t\t\t\t\t\t<td>' + fieldText + '</td>\n\t\t\t\t\t</tr>\n';
    245 		}
    246 		
    247 		content += '\t\t\t\t</table>\n';
    248 		
    249 		return table ? content : '';
    250 	}
    251 	
    252 	
    253 	function _generateTagsList(obj) {
    254 		var content = '';
    255 		if (obj.tags && obj.tags.length) {
    256 			var str = Zotero.getString('report.tags');
    257 			content += '\t\t\t\t<h3 class="tags">' + escapeXML(str) + '</h3>\n';
    258 			content += '\t\t\t\t<ul class="tags">\n';
    259 			for (let i=0; i<obj.tags.length; i++) {
    260 				content += '\t\t\t\t\t<li>' + escapeXML(obj.tags[i].tag) + '</li>\n';
    261 			}
    262 			content += '\t\t\t\t</ul>\n';
    263 		}
    264 		return content;
    265 	}
    266 	
    267 	
    268 	function _generateAttachmentsList(obj) {
    269 		var content = '';
    270 		if (obj.attachments && obj.attachments.length) {
    271 			content += '\t\t\t\t<h3 class="attachments">' + escapeXML(Zotero.getString('itemFields.attachments')) + '</h3>\n';
    272 			content += '\t\t\t\t<ul class="attachments">\n';
    273 			for (let i=0; i<obj.attachments.length; i++) {
    274 				let attachment = obj.attachments[i];
    275 				
    276 				content += '\t\t\t\t\t<li id="item_' + attachment.key + '">';
    277 				if (attachment.title !== undefined) {
    278 					content += escapeXML(attachment.title);
    279 				}
    280 				
    281 				// Attachment tags
    282 				content += _generateTagsList(attachment);
    283 				
    284 				// Attachment note
    285 				if (attachment.note) {
    286 					content += '\t\t\t\t\t\t<div class="note">';
    287 					content += getNoteHTML(attachment.note);
    288 					content += '\t\t\t\t\t</div>';
    289 				}
    290 				
    291 				content += '\t\t\t\t\t</li>\n';
    292 			}
    293 			content += '\t\t\t\t</ul>\n';
    294 		}
    295 		return content;
    296 	}
    297 	
    298 	
    299 	function getNoteHTML(note) {
    300 		// If HTML tag or entity, parse as HTML
    301 		if (note.match(/(<(p|ul|ol|div|a|br|b|i|u|strong|em( >))|&[a-z]+;|&#[0-9]+;)/)) {
    302 			let doc = domParser.parseFromString('<div>'
    303 				+ note
    304 					// Strip control characters (for notes that were
    305 					// added before item.setNote() started doing this)
    306 					.replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F]/g, "")
    307 			 + '</div>', "text/html");
    308 			return doc.body.innerHTML + '\n';
    309 		}
    310 		// Otherwise, treat as plain text
    311 		return '<p class="plaintext">' + escapeXML(note) + '</p>\n';
    312 	}
    313 	
    314 	
    315 	var escapeXML = function (str) {
    316 		str = str.replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\ud800-\udfff\ufffe\uffff]/g, '\u2B1A');
    317 		return Zotero.Utilities.htmlSpecialChars(str);
    318 	}
    319 }