zotero/chrome/chromeFiles/content/scholar/itemPane.js
Dan Stillman 27f89fac5e Cross-posting to BC for discussion: http://chnm.grouphub.com/projects/310105/msg/cat/2114872/3538662/comments
Changes as per my discussions with Dan:

- Separated snapshot functionality into two individual buttons, Create New Item From Current Page and Take Snapshot of Current page
- Updated schema to support primary, secondary and hidden item types (and future user customizations)
- Reorganized New Item menu, moving secondary items into sub-menu
- Removed ability to create link attachments, since it never really made much sense -- will simply use the webpage item type instead. Underlying functionality still exists for the time being, as people have existing links in their libraries--I think we're gonna have to just warn beta testers and delete them in a transition step, as converting nested links really wouldn't be worth the effort.
- Moved file link/add functions into new item menu and removed attachment drop-down
- Large, prominent View and Locate buttons in edit pane for going to an associated URL and looking up in OpenURL, respectively -- buttons gray out as appropriate
- New Item from Page stores the URL and access date (Item.save() checks for the string "CURRENT_TIMESTAMP" for accessDate and doesn't bind it as a string)
- "Website" to "Web Page" (do we prefer "Webpage"? they both look a bit funky in uppercase)

More coming.


Bugs/Known Issues:

- Since snapshots from the toolbar are now top-level in the current collection, there needs to be a way to drag them into items
- The camera icon for adding snapshots, despite being a famfamfam icon, really doesn't read too well (or perhaps just clashes with the rest of our icons). Anybody have a better one? (It also may be able to just be lightened up a bit.)
- Trying the large View/Locate buttons after discussions with Dan, but this approach may not work -- 1) a large View button for the URL makes a lot less sense when you have a parent item with a child snapshot, since people will end up clicking it all the time when they really want to view the snapshot, and 2) the Locate button is awfully big for something that only applies to certain types of items, may not get used very often when it does, and probably won't work when it is
- The access date is stored in UTC and displayed with toLocaleString() like Date Added and Date Modified, but, unlike those two, it's also user-editable. This is clearly a problem. Probably need to parse to Date on blur() with strToDate() and insert as UTC, discarding anything left over. 
- Item type itself is still "website" -- should probably change that while we still can


Closes #253, OpenURL arrow should provide visual feedback on mouseover and/or look more button-like
Addresses #304, change references to "website" to "web page"
Addresses #207, openurl arrow functionality
2006-09-27 08:12:09 +00:00

1218 lines
31 KiB
JavaScript

/*
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<itemTypes.length; i++)
if(itemTypes[i]['name'] != 'note' && itemTypes[i]['name'] != 'attachment')
_itemTypeMenu.appendItem(Scholar.getString("itemTypes."+itemTypes[i]['name']),itemTypes[i]['id']);
return true;
}
/*
* Loads an item
*/
function viewItem(thisItem)
{
//Scholar.debug('Viewing item');
// Force blur() when clicking off a textbox to another item in middle
// pane, since for some reason it's not being called automatically
if (_itemBeingEdited && _itemBeingEdited!=thisItem)
{
switch (_tabs.selectedIndex)
{
// Info
case 0:
var boxes = _dynamicFields.getElementsByTagName('textbox');
break;
// Tags
case 3:
var boxes = document.getAnonymousNodes(_tagsBox)[0].getElementsByTagName('textbox');
break;
}
if (boxes && boxes.length==1)
{
boxes[0].inputField.blur();
}
}
_itemBeingEdited = thisItem;
_loaded = {};
loadPane(_tabs.selectedIndex);
}
function loadPane(index)
{
//Scholar.debug('Loading item pane ' + index);
// Clear the tab index when switching panes
if (_lastPane!=index)
{
_lastTabIndex = null;
}
_lastPane = index;
if(_loaded[index])
{
return;
}
_loaded[index] = true;
// Info pane
if(index == 0)
{
// Enable/disable "View =>" 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; i<fields.length; i++)
fieldNames.push(Scholar.ItemFields.getName(fields[i]));
fieldNames.push("dateAdded","dateModified");
for(var i = 0; i<fieldNames.length; i++)
{
var editable = (!_itemBeingEdited.isPrimaryField(fieldNames[i]) || _itemBeingEdited.isEditableField(fieldNames[i]));
var val = _itemBeingEdited.getField(fieldNames[i]);
// Convert dates from UTC
if (fieldNames[i]=='dateAdded' || fieldNames[i]=='dateModified'
|| fieldNames[i]=='accessDate'){
var date = Scholar.Date.sqlToDate(val, true);
val = date ? date.toLocaleString() : '';
}
// Start tabindex at 1000 after creators
var tabindex = editable ? (i>0 ? _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(); i<len; i++)
{
var creator = _itemBeingEdited.getCreator(i);
addCreatorRow(creator['firstName'], creator['lastName'], creator['creatorTypeID'], creator['isInstitution']);
}
}
else
{
// Add default row
addCreatorRow('', '', 1, false, true, true);
}
var focusMode = 'info';
var focusBox = _dynamicFields;
}
// Notes pane
else if(index == 1)
{
while(_notesList.hasChildNodes())
_notesList.removeChild(_notesList.firstChild);
var notes = Scholar.Items.get(_itemBeingEdited.getNotes());
if(notes.length)
{
for(var i = 0; i < notes.length; i++)
{
var icon = document.createElement('image');
icon.setAttribute('src','chrome://scholar/skin/treeitem-note.png');
var label = document.createElement('label');
label.setAttribute('value',_noteToTitle(notes[i].getNote()));
label.setAttribute('flex','1'); //so that the long names will flex smaller
label.setAttribute('crop','end');
var box = document.createElement('box');
box.setAttribute('onclick',"ScholarPane.selectItem("+notes[i].getID()+");");
box.setAttribute('class','clicky');
box.appendChild(icon);
box.appendChild(label);
var removeButton = document.createElement('label');
removeButton.setAttribute("value","-");
removeButton.setAttribute("class","clicky");
removeButton.setAttribute("onclick","ScholarItemPane.removeNote("+notes[i].getID()+")");
var row = document.createElement('row');
row.appendChild(box);
row.appendChild(removeButton);
_notesList.appendChild(row);
}
}
_updateNoteCount();
}
// Attachments pane
else if(index == 2)
{
while(_attachmentsList.hasChildNodes())
_attachmentsList.removeChild(_attachmentsList.firstChild);
var attachments = Scholar.Items.get(_itemBeingEdited.getAttachments());
if(attachments.length)
{
for(var i = 0; i < attachments.length; i++)
{
var icon = document.createElement('image');
var linkMode = attachments[i].getAttachmentLinkMode();
if(linkMode == Scholar.Attachments.LINK_MODE_IMPORTED_FILE)
{
itemType = "-file";
}
else if(linkMode == Scholar.Attachments.LINK_MODE_LINKED_FILE)
{
itemType = "-link";
}
else if(linkMode == Scholar.Attachments.LINK_MODE_IMPORTED_URL)
{
itemType = "-snapshot";
}
else if(linkMode == Scholar.Attachments.LINK_MODE_LINKED_URL)
{
itemType = "-web-link";
}
icon.setAttribute('src','chrome://scholar/skin/treeitem-file'+itemType+'.png');
var label = document.createElement('label');
label.setAttribute('value',attachments[i].getField('title'));
label.setAttribute('flex','1'); //so that the long names will flex smaller
label.setAttribute('crop','end');
var box = document.createElement('box');
box.setAttribute('onclick',"ScholarPane.selectItem('"+attachments[i].getID()+"')");
box.setAttribute('class','clicky');
box.appendChild(icon);
box.appendChild(label);
var removeButton = document.createElement('label');
removeButton.setAttribute("value","-");
removeButton.setAttribute("class","clicky");
removeButton.setAttribute("onclick","ScholarItemPane.removeAttachment("+attachments[i].getID()+")");
var row = document.createElement('row');
row.appendChild(box);
row.appendChild(removeButton);
_attachmentsList.appendChild(row);
}
}
_updateAttachmentCount();
}
// Tags pane
else if(index == 3)
{
var focusMode = 'tags';
var focusBox = _tagsBox;
_tagsBox.item = _itemBeingEdited;
}
// Related pane
else if(index == 4)
{
_relatedBox.item = _itemBeingEdited;
}
// Move to next or previous field if (shift-)tab was pressed
if (focusMode && _lastTabIndex && _tabDirection)
{
_focusNextField(focusMode, focusBox, _lastTabIndex, _tabDirection==-1);
}
}
function changeTypeTo(id)
{
if(id != _itemBeingEdited.getType() && confirm(Scholar.getString('pane.item.changeType')))
{
_itemBeingEdited.setType(id);
_itemBeingEdited.save();
loadPane(0);
}
}
function onGoToURLClick()
{
window.loadURI(_itemBeingEdited.getField('url'));
}
function onOpenURLClick()
{
var url = Scholar.OpenURL.resolve(_itemBeingEdited);
if (url)
{
window.loadURI(Scholar.OpenURL.resolve(_itemBeingEdited));
}
}
function addDynamicRow(label, value, beforeElement)
{
var row = document.createElement("row");
row.appendChild(label);
row.appendChild(value);
if(beforeElement)
_dynamicFields.insertBefore(row, _beforeRow);
else
_dynamicFields.appendChild(row);
}
function addCreatorRow(firstName, lastName, typeID, singleField, unsaved, defaultRow)
{
// Disable the "+" button on previous rows
var elems = _dynamicFields.getElementsByAttribute('value', '+');
if (elems.length){
ScholarItemPane.disableButton(elems[elems.length-1]);
}
if (singleField)
{
if (!lastName)
{
lastName = _defaultFullName;
}
}
else
{
if (!firstName)
{
firstName = _defaultFirstName;
}
if (!lastName)
{
lastName = _defaultLastName;
}
}
var label = document.createElement("label");
label.setAttribute("value",Scholar.getString('creatorTypes.'+Scholar.CreatorTypes.getName(typeID))+":");
label.setAttribute("popup","creatorTypeMenu");
label.setAttribute("fieldname",'creator-'+_creatorCount+'-typeID');
label.className = 'clicky';
// getCreatorFields() and switchCreatorMode() may need need to be
// adjusted if this DOM structure changes
var hbox = document.createElement("hbox");
// Name
var firstlast = document.createElement("hbox");
firstlast.setAttribute("flex","1");
var tabindex = _tabIndexMinCreators + (_creatorCount * 2);
firstlast.appendChild(
createValueElement(
lastName,
'creator-' + _creatorCount + '-lastName',
tabindex
)
);
// Comma
var comma = document.createElement('label');
comma.setAttribute('value', ',');
comma.className = 'comma';
firstlast.appendChild(comma);
firstlast.appendChild(
createValueElement(
firstName,
'creator-' + _creatorCount + '-firstName',
tabindex + 1
)
);
if (singleField)
{
firstlast.lastChild.setAttribute('hidden', true);
}
_tabIndexMaxCreators = Math.max(_tabIndexMaxCreators, tabindex);
hbox.appendChild(firstlast);
// Single/double field toggle
var toggleButton = document.createElement('toolbarbutton');
toggleButton.setAttribute('fieldname', 'creator-' + _creatorCount + '-singleField');
toggleButton.className = 'clicky';
hbox.appendChild(toggleButton);
// Minus (-) button
var removeButton = document.createElement('label');
removeButton.setAttribute("value","-");
// If default first row, don't let user remove it
if (defaultRow){
disableButton(removeButton);
}
else {
removeButton.setAttribute("class","clicky");
removeButton.setAttribute("onclick","ScholarItemPane.removeCreator("+_creatorCount+", this.parentNode.parentNode)");
}
hbox.appendChild(removeButton);
// Plus (+) button
var addButton = document.createElement('label');
addButton.setAttribute("value","+");
// If row isn't saved, don't let user add more
if (unsaved)
{
disableButton(addButton);
}
else
{
_enablePlusButton(addButton);
}
hbox.appendChild(addButton);
_creatorCount++;
addDynamicRow(label, hbox, true);
// Set single/double field toggle mode
if (singleField)
{
switchCreatorMode(hbox.parentNode, true, true);
}
else
{
switchCreatorMode(hbox.parentNode, false, true);
}
}
function switchCreatorMode(row, singleField, initial)
{
// Change if button position changes
// row->hbox->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
// <description> 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<MAX_LENGTH)
{
t = t.substring(0, ln);
}
if(t == "")
{
return Scholar.getString('pane.item.notes.untitled');
}
else
{
return t;
}
}
function _updateNoteCount()
{
var c = _notesList.childNodes.length;
_notesLabel.value = Scholar.getString('pane.item.notes.count.'+(c != 1 ? "plural" : "singular")).replace('%1',c) + ":";
}
function _updateAttachmentCount()
{
var c = _attachmentsList.childNodes.length;
_attachmentsLabel.value = Scholar.getString('pane.item.attachments.count.'+(c != 1 ? "plural" : "singular")).replace('%1',c) + ":";
}
function removeAttachment(id)
{
var attachment = Scholar.Items.get(id);
if(attachment)
if(confirm(Scholar.getString('pane.item.attachments.delete.confirm')))
attachment.erase();
}
function addAttachmentFromDialog(link)
{
ScholarPane.addAttachmentFromDialog(link, _itemBeingEdited.getID());
}
function addAttachmentFromPage(link)
{
ScholarPane.addAttachmentFromPage(link, _itemBeingEdited.getID());
}
/*
* Advance the field focus forward or backward
*
* Note: We're basically replicating the built-in tabindex functionality,
* which doesn't work well with the weird label/textbox stuff we're doing.
* (The textbox being tabbed away from is deleted before the blur()
* completes, so it doesn't know where it's supposed to go next.)
*
* Use of the 'tabindex' attribute is arbitrary.
*/
function _focusNextField(mode, box, tabindex, back){
tabindex = parseInt(tabindex);
if (back)
{
if (mode=='info')
{
switch (tabindex)
{
case 1:
//Scholar.debug('At beginning');
return false;
case _tabIndexMinCreators:
var nextIndex = 1;
break;
case _tabIndexMinFields:
var nextIndex = _tabIndexMaxCreators;
break;
default:
var nextIndex = tabindex - 1;
}
}
else if (mode=='tags')
{
switch (tabindex)
{
case 1:
return false;
default:
var nextIndex = tabindex - 1;
}
}
}
else
{
if (mode=='info')
{
switch (tabindex)
{
case 1:
var nextIndex = _tabIndexMinCreators;
break;
case _tabIndexMaxCreators:
var nextIndex = _tabIndexMinFields;
break;
case _tabIndexMaxInfoFields:
//Scholar.debug('At end');
return false;
default:
var nextIndex = tabindex + 1;
}
}
else if (mode=='tags')
{
switch (tabindex)
{
case _tabIndexMaxTagsFields:
// In tags box, keep going to create new row
var nextIndex = tabindex + 1;
break;
default:
var nextIndex = tabindex + 1;
}
}
}
Scholar.debug('Looking for tabindex ' + nextIndex, 4);
switch (mode)
{
case 'info':
var next = box.getElementsByAttribute('tabindex', nextIndex);
if (!next[0])
{
//Scholar.debug("Next field not found");
return _focusNextField(mode, box, nextIndex, back);
}
break;
// Tags pane
case 'tags':
var next = document.getAnonymousNodes(box)[0].
getElementsByAttribute('tabindex', nextIndex);
if (!next[0]){
next[0] = box.addDynamicRow();
}
break;
}
next[0].click();
return true;
}
}
addEventListener("load", function(e) { ScholarItemPane.onLoad(e); }, false);