/* Zotero Copyright (C) 2006 Center for History and New Media, George Mason University, Fairfax, VA http://chnm.gmu.edu/ */ var ScholarItemPane = new function() { var _dynamicFields; var _creatorTypeMenu; var _beforeRow; var _notesList; var _linksBox; var _notesLabel; var _creatorCount; var _lastPane; var _loaded; var _itemBeingEdited; var _lastTabIndex; var _tabDirection; var _tabIndexMinCreators = 10; var _tabIndexMaxCreators = 0; var _tabIndexMinFields = 1000; var _tabIndexMaxInfoFields = 0; var _tabIndexMaxTagsFields = 0; const _defaultFirstName = '(' + Scholar.getString('pane.item.defaultFirstName') + ')'; const _defaultLastName = '(' + Scholar.getString('pane.item.defaultLastName') + ')'; const _defaultFullName = '(' + Scholar.getString('pane.item.defaultFullName') + ')'; this.onLoad = onLoad; this.viewItem = viewItem; this.loadPane = loadPane; this.changeTypeTo = changeTypeTo; this.onGoToURLClick = onGoToURLClick; this.onOpenURLClick = onOpenURLClick; this.addCreatorRow = addCreatorRow; this.switchCreatorMode = switchCreatorMode; this.disableButton = disableButton; this.createValueElement = createValueElement; this.removeCreator = removeCreator; this.showEditor = showEditor; this.handleKeyPress = handleKeyPress; this.hideEditor = hideEditor; this.getCreatorFields = getCreatorFields; this.modifyCreator = modifyCreator; this.removeNote = removeNote; this.addNote = addNote; this.removeAttachment = removeAttachment; this.addAttachmentFromDialog = addAttachmentFromDialog; this.addAttachmentFromPage = addAttachmentFromPage; function onLoad() { _tabs = document.getElementById('scholar-view-tabs'); // Not in item pane, so skip the introductions if (!_tabs) { return false; } _dynamicFields = document.getElementById('editpane-dynamic-fields'); _itemTypeMenu = document.getElementById('editpane-type-menu'); _creatorTypeMenu = document.getElementById('creatorTypeMenu'); _notesList = document.getElementById('editpane-dynamic-notes'); _notesLabel = document.getElementById('editpane-notes-label'); _attachmentsList = document.getElementById('editpane-dynamic-attachments'); _attachmentsLabel = document.getElementById('editpane-attachments-label'); _tagsBox = document.getElementById('editpane-tags'); _relatedBox = document.getElementById('editpane-related'); var creatorTypes = Scholar.CreatorTypes.getTypes(); for(var i = 0; i < creatorTypes.length; i++) { var menuitem = document.createElement("menuitem"); menuitem.setAttribute("label",Scholar.getString('creatorTypes.'+creatorTypes[i]['name'])); menuitem.setAttribute("typeid",creatorTypes[i]['id']); if(creatorTypes[i]['id'] == 0) menuitem.setAttribute("selected",true); _creatorTypeMenu.appendChild(menuitem); } var itemTypes = Scholar.ItemTypes.getTypes(); for(var i = 0; i" button testView: try { var validURI = false; var spec = _itemBeingEdited.getField('url'); if (!spec) { break testView; } var uri = Components.classes["@mozilla.org/network/io-service;1"] .getService(Components.interfaces.nsIIOService) .newURI(spec, null, null); validURI = uri.scheme && uri.host; } catch (e){} document.getElementById('tb-go-to-url').setAttribute('disabled', !validURI); // Enable/disable "Locate =>" (OpenURL) button switch (_itemBeingEdited.getType()) { // DEBUG: handle descendents of these types as well? case Scholar.ItemTypes.getID('book'): case Scholar.ItemTypes.getID('bookSection'): case Scholar.ItemTypes.getID('journalArticle'): case Scholar.ItemTypes.getID('thesis'): var openURL = true; break; default: var openURL = false; } document.getElementById('tb-openurl').setAttribute('disabled', !openURL); while(_dynamicFields.hasChildNodes()) _dynamicFields.removeChild(_dynamicFields.firstChild); for(var i = 0, len = _itemTypeMenu.firstChild.childNodes.length; i < len; i++) if(_itemTypeMenu.firstChild.childNodes[i].value == _itemBeingEdited.getType()) _itemTypeMenu.selectedIndex = i; var fieldNames = new Array("title"); var fields = Scholar.ItemFields.getItemTypeFields(_itemBeingEdited.getField("itemTypeID")); for(var i = 0; i0 ? _tabIndexMinFields + i : 1) : 0; var valueElement = createValueElement( val, editable ? fieldNames[i] : null, tabindex ); _tabIndexMaxInfoFields = Math.max(_tabIndexMaxInfoFields, tabindex); var label = document.createElement("label"); label.setAttribute("value",Scholar.getString("itemFields."+fieldNames[i])+":"); label.setAttribute("onclick","this.nextSibling.blur();"); addDynamicRow(label,valueElement); } //CREATORS: _beforeRow = _dynamicFields.firstChild.nextSibling; _creatorCount = 0; if(_itemBeingEdited.numCreators() > 0) { for(var i = 0, len=_itemBeingEdited.numCreators(); ihbox->label->label->toolbarbutton var button = row.lastChild.lastChild.previousSibling.previousSibling; var hbox = button.previousSibling; var lastName = hbox.firstChild; var comma = hbox.firstChild.nextSibling; var firstName = hbox.lastChild; // Switch to single-field mode if (singleField) { button.setAttribute('image', 'chrome://scholar/skin/textfield-dual.png'); button.setAttribute('tooltiptext', 'Switch to two fields'); lastName.setAttribute('singleField', 'true'); button.setAttribute('onclick', "ScholarItemPane.switchCreatorMode(this.parentNode.parentNode, false)"); // Remove firstname field from tabindex var tab = parseInt(firstName.getAttribute('tabindex')); firstName.setAttribute('tabindex', -1); if (_tabIndexMaxCreators==tab) { _tabIndexMaxCreators--; } // Hide first name field and prepend to last name field firstName.setAttribute('hidden', true); comma.setAttribute('hidden', true); var first = _getFieldValue(firstName); if (first && first != _defaultFirstName) { var last = _getFieldValue(lastName); _setFieldValue(lastName, first + ' ' + last); } if (_getFieldValue(lastName) == _defaultLastName) { _setFieldValue(lastName, _defaultFullName); } } // Switch to two-field mode else { button.setAttribute('image', 'chrome://scholar/skin/textfield-single.png'); button.setAttribute('tooltiptext', 'Switch to single field'); lastName.setAttribute('singleField', 'false'); button.setAttribute('onclick', "ScholarItemPane.switchCreatorMode(this.parentNode.parentNode, true)"); // Add firstname field to tabindex var tab = parseInt(lastName.getAttribute('tabindex')); firstName.setAttribute('tabindex', tab + 1); if (_tabIndexMaxCreators==tab) { _tabIndexMaxCreators++; } // Move all but last word to first name field and show it var last = _getFieldValue(lastName); if (last && last != _defaultFullName) { var lastNameRE = /(.*?)[ ]*([^ ]+[ ]*)$/; var parts = lastNameRE.exec(last); if (parts[2] && parts[2] != last) { _setFieldValue(lastName, parts[2]); _setFieldValue(firstName, parts[1]); } } if (!_getFieldValue(firstName)) { _setFieldValue(firstName, _defaultFirstName); } if (_getFieldValue(lastName) == _defaultFullName) { _setFieldValue(lastName, _defaultLastName); } firstName.setAttribute('hidden', false); comma.setAttribute('hidden', false); } if (!initial) { var [, index, field] = button.getAttribute('fieldname').split('-'); var otherFields = getCreatorFields(row); // row modifyCreator(index, field, !!singleField, otherFields); } } function disableButton(button) { button.setAttribute('disabled', true); button.setAttribute('class', 'unclicky'); button.setAttribute('onclick', false); } function _enablePlusButton(button) { button.setAttribute('disabled', false); button.setAttribute("class","clicky"); button.setAttribute("onclick","ScholarItemPane.disableButton(this); ScholarItemPane.addCreatorRow('','',1,false,true);"); } function createValueElement(valueText, fieldName, tabindex) { if (fieldName=='extra') { var valueElement = document.createElement("vbox"); } else { var valueElement = document.createElement("label"); } if(fieldName) { valueElement.setAttribute('fieldname',fieldName); valueElement.setAttribute('tabindex', tabindex); valueElement.setAttribute('onclick', 'ScholarItemPane.showEditor(this)'); valueElement.className = 'clicky'; if (fieldName=='tag') { _tabIndexMaxTagsFields = Math.max(_tabIndexMaxTagsFields, tabindex); } } var firstSpace; if(typeof valueText == 'string') firstSpace = valueText.indexOf(" "); // To support newlines in 'extra' fields, we use multiple // elements inside a vbox if (fieldName=='extra') { var lines = valueText.split("\n"); for (var i = 0; i < lines.length; i++) { var descriptionNode = document.createElement("description"); var linetext = document.createTextNode(lines[i]); descriptionNode.appendChild(linetext); valueElement.appendChild(descriptionNode); } } else if ((firstSpace == -1 && valueText.length > 29 ) || firstSpace > 29) { valueElement.setAttribute('crop', 'end'); valueElement.setAttribute('value',valueText); } else { // Wrap to multiple lines valueElement.appendChild(document.createTextNode(valueText)); } return valueElement; } function removeCreator(index, labelToDelete) { // If unsaved row, just remove element if (!_itemBeingEdited.hasCreatorAt(index)){ labelToDelete.parentNode.removeChild(labelToDelete); // Enable the "+" button on the previous row var elems = _dynamicFields.getElementsByAttribute('value', '+'); _enablePlusButton(elems[elems.length-1]); _creatorCount--; return; } _itemBeingEdited.removeCreator(index); _itemBeingEdited.save(); loadPane(0); } function showEditor(elem) { //Scholar.debug('Showing editor'); var fieldName = elem.getAttribute('fieldname'); var tabindex = elem.getAttribute('tabindex'); var [field, creatorIndex, creatorField] = fieldName.split('-'); if (field == 'creator') { var c = _itemBeingEdited.getCreator(creatorIndex); var value = c ? c[creatorField] : ''; var itemID = _itemBeingEdited.getID(); } else if (fieldName=='tag') { var tagID = elem.parentNode.getAttribute('id').split('-')[1]; var value = tagID ? Scholar.Tags.getName(tagID) : ''; var itemID = Scholar.getAncestorByTagName(elem, 'tagsbox').item.getID(); } else { var value = _itemBeingEdited.getField(fieldName); var itemID = _itemBeingEdited.getID(); } var t = document.createElement("textbox"); t.setAttribute('value',value); t.setAttribute('fieldname', fieldName); t.setAttribute('tabindex', tabindex); t.setAttribute('flex','1'); if (creatorField=='lastName') { t.setAttribute('singleField', elem.getAttribute('singleField')); } if (fieldName=='extra') { t.setAttribute('multiline', true); t.setAttribute('rows', 8); } // TODO: only have autocomplete on a few fields else { t.setAttribute('type', 'autocomplete'); t.setAttribute('autocompletesearch', 'zotero'); t.setAttribute('autocompletesearchparam', fieldName + '/' + (elem.getAttribute('singleField')=='true' ? '1' : '0') + '-' + (itemID ? itemID : '')); } var box = elem.parentNode; box.replaceChild(t,elem); t.select(); t.setAttribute('onblur',"ScholarItemPane.hideEditor(this, true)"); t.setAttribute('onkeypress',"return ScholarItemPane.handleKeyPress(event)"); _tabDirection = false; _lastTabIndex = tabindex; } function handleKeyPress(event){ var target = document.commandDispatcher.focusedElement; switch (event.keyCode) { case event.DOM_VK_RETURN: // Use shift-enter as the save action for the 'extra' field if (target.parentNode.parentNode.getAttribute('fieldname')=='extra' && !event.shiftKey) { break; } else if (target.parentNode.parentNode. parentNode.getAttribute('fieldname')=='tag') { // If last tag row, create new one var row = target.parentNode.parentNode.parentNode.parentNode; if (row == row.parentNode.lastChild) { _tabDirection = 1; } } target.blur(); return false; case event.DOM_VK_ESCAPE: target.blur(); return false; case event.DOM_VK_TAB: _tabDirection = event.shiftKey ? -1 : 1; // Blur the old manually -- not sure why this is necessary, // but it prevents an immediate blur() on the next tag target.blur(); return false; } return true; } function hideEditor(t, saveChanges) { //Scholar.debug('Hiding editor'); var textbox = Scholar.getAncestorByTagName(t, 'textbox'); if (!textbox){ Scholar.debug('Textbox not found in hideEditor'); return; } var fieldName = textbox.getAttribute('fieldname'); var tabindex = textbox.getAttribute('tabindex'); var value = t.value; var elem; var [field, creatorIndex, creatorField] = fieldName.split('-'); // Creator fields if (field == 'creator') { var row = textbox.parentNode.parentNode.parentNode; var otherFields = getCreatorFields(row); if (saveChanges){ modifyCreator(creatorIndex, creatorField, value, otherFields); } var val = _itemBeingEdited.getCreator(creatorIndex)[creatorField]; if (!val){ // Reset to '(first)'/'(last)'/'(name)' if (creatorField=='lastName') { val = otherFields['singleField'] ? _defaultFullName : _defaultLastName; } else if (creatorField=='firstName') { val = _defaultFirstName; } } elem = createValueElement(val, fieldName, tabindex); // Reset creator mode settings if (otherFields['singleField']) { switchCreatorMode(row, true, true); } else { switchCreatorMode(row, false, true); } } // Tags else if (fieldName=='tag') { var tagsbox = Scholar.getAncestorByTagName(textbox, 'tagsbox'); if (!tagsbox) { Scholar.debug('Tagsbox not found', 1); return; } var row = textbox.parentNode; var rows = row.parentNode; // Tag id encoded as 'tag-1234' var id = row.getAttribute('id').split('-')[1]; if (saveChanges) { if (id) { if (value) { // If trying to replace with another existing tag // (which causes a delete of the row), // clear the tab direction so we don't advance // when the notifier kicks in var existing = Scholar.Tags.getID(value); if (existing && id != existing) { _tabDirection = false; } var changed = tagsbox.replace(id, value); if (changed) { return; } } else { tagsbox.remove(id); return; } } else { var id = tagsbox.add(value); } } if (id) { elem = createValueElement(value, 'tag', tabindex); } else { // Just remove the row var row = rows.removeChild(row); tagsbox.fixPopup(); _tabDirection = false; return; } var focusMode = 'tags'; var focusBox = tagsbox; } // Fields else { if(saveChanges) modifyField(fieldName,value); elem = createValueElement(_itemBeingEdited.getField(fieldName), fieldName, tabindex); } var box = textbox.parentNode; box.replaceChild(elem,textbox); if (_tabDirection) { if (!focusMode) { var focusMode = 'info'; var focusBox = _dynamicFields; } _focusNextField(focusMode, focusBox, _lastTabIndex, _tabDirection==-1); } } function modifyField(field, value) { _itemBeingEdited.setField(field,value); _itemBeingEdited.save(); } function _getFieldValue(field) { return field.firstChild ? field.firstChild.nodeValue : field.value; } function _setFieldValue(field, value) { if (field.firstChild) { field.firstChild.nodeValue = value; } else { field.value = value; } } function getCreatorFields(row){ var type = row.getElementsByTagName('label')[0].getAttribute('value'); var label1 = row.getElementsByTagName('hbox')[0].firstChild.firstChild; var label2 = label1.parentNode.lastChild; return { lastName: label1.firstChild ? label1.firstChild.nodeValue : label1.value, firstName: label2.firstChild ? label2.firstChild.nodeValue : label2.value, typeID: Scholar.CreatorTypes.getID(type.substr(0, type.length-1).toLowerCase()), singleField: label1.getAttribute('singleField') == 'true' } } function modifyCreator(index, field, value, otherFields) { if (otherFields){ var firstName = otherFields.firstName; var lastName = otherFields.lastName; var typeID = otherFields.typeID; var singleField = otherFields.singleField; // Ignore '(first)'/'(last)' or '(name)' if (singleField || firstName == _defaultFirstName){ firstName = ''; } if (lastName==_defaultFullName || lastName == _defaultLastName){ lastName = ''; } } else { var creator = _itemBeingEdited.getCreator(index); var firstName = creator['firstName']; var lastName = creator['lastName']; var typeID = creator['creatorTypeID']; var singleField = creator['isInstitution']; } // Don't save empty creators if (!_itemBeingEdited.hasCreatorAt(index) && !firstName && !lastName){ return; } switch (field){ case 'firstName': firstName = value; break; case 'lastName': lastName = value; break; case 'typeID': typeID = value; break; case 'singleField': singleField = value; break; } _itemBeingEdited.setCreator(index, firstName, lastName, typeID, singleField); _itemBeingEdited.save(); } function removeNote(id) { var note = Scholar.Items.get(id); if(note) if(confirm(Scholar.getString('pane.item.notes.delete.confirm'))) note.erase(); } function addNote() { ScholarPane.openNoteWindow(_itemBeingEdited.getID()); } function _noteToTitle(text) { var MAX_LENGTH = 100; var t = text.substring(0, MAX_LENGTH); var ln = t.indexOf("\n"); if (ln>-1 && ln