2.0b3 megacommit
- Support for group libraries - General support for multiple libraries of different types - Streamlined sync support - Using solely libraryID and key rather than itemID, and removed all itemID-changing code - Combined two requests for increased performance and decreased server load - Added warning on user account change - Provide explicit error message on SSL failure - Removed snapshot and link toolbar buttons and changed browser context menu options and drags to create parent items + snapshots - Closes #786, Add numPages field - Fixes #1063, Duplicate item with tags broken in Sync Preview - Added better purging of deleted tags - Added local user key before first sync - Add clientDateModified to all objects for more flexibility in syncing - Added new triples-based Relation object type, currently used to store links between items copied between local and group libraries - Updated zotero.org translator for groups - Additional trigger-based consistency checks - Fixed broken URL drag in Firefox 3.5 - Disabled zeroconf menu option (no longer functional) Developer-specific changes: - Overhauled data layer - Data object constructors no longer take arguments (return to 1.0-like API) - Existing objects can be retrieved by setting id or library/key properties - id/library/key must be set for new objects before other fields - New methods: - ZoteroPane.getSelectedLibraryID() - ZoteroPane.getSelectedGroup(asID) - ZoteroPane.addItemFromDocument(doc, itemType, saveSnapshot) - ZoteroPane.addItemFromURL(url, itemType) - ZoteroPane.canEdit() - Zotero.CollectionTreeView.selectLibrary(libraryID) - New Zotero.URI methods - Changed methods - Many data object methods now take a libraryID - ZoteroPane.addAttachmentFromPage(link, itemID) - Removed saveItem and saveAttachments parameters from Zotero.Translate constructor - translate() now takes a libraryID, null for local library, or false to not save items (previously on constructor) - saveAttachments is now a translate() parameter - Zotero.flattenArguments() better handles passed objects - Zotero.File.getFileHash() (not currently used)
This commit is contained in:
parent
1db1de2257
commit
91459f95f7
55 changed files with 5370 additions and 1816 deletions
|
@ -29,7 +29,14 @@ var ZoteroAdvancedSearch = new function() {
|
|||
var itemGroup = {
|
||||
isSearchMode: function() { return true; },
|
||||
getChildItems: function () {
|
||||
var ids = _searchBox.search.search();
|
||||
var search = _searchBox.search.clone();
|
||||
// FIXME: Hack to exclude group libraries for now
|
||||
var groups = Zotero.Groups.getAll();
|
||||
for each(var group in groups) {
|
||||
search.addCondition('libraryID', 'isNot', group.libraryID);
|
||||
}
|
||||
//var search = _searchBox.search;
|
||||
var ids = search.search();
|
||||
return Zotero.Items.get(ids);
|
||||
},
|
||||
isLibrary: function () { return false; },
|
||||
|
|
|
@ -407,7 +407,7 @@
|
|||
this._tabIndexMaxInfoFields = Math.max(this._tabIndexMaxInfoFields, tabindex);
|
||||
|
||||
if (fieldIsClickable &&
|
||||
!this.item.isPrimaryField(fieldName) &&
|
||||
!Zotero.Items.isPrimaryField(fieldName) &&
|
||||
Zotero.ItemFields.isFieldOfBase(Zotero.ItemFields.getID(fieldName), 'date')) {
|
||||
this.addDateRow(fieldNames[i], this.item.getField(fieldName, true), tabindex);
|
||||
continue;
|
||||
|
@ -1688,7 +1688,7 @@
|
|||
<body>
|
||||
<![CDATA[
|
||||
return !this.clickByRow &&
|
||||
((this.clickable && !this.item.isPrimaryField(fieldName))
|
||||
((this.clickable && !Zotero.Items.isPrimaryField(fieldName))
|
||||
|| this._clickableFields.indexOf(fieldName) != -1);
|
||||
]]>
|
||||
</body>
|
||||
|
@ -1802,6 +1802,7 @@
|
|||
<parameter name="changeGlobally"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
var libraryID = this.item.libraryID;
|
||||
var firstName = fields.firstName;
|
||||
var lastName = fields.lastName;
|
||||
//var shortName = fields.shortName;
|
||||
|
@ -1823,16 +1824,17 @@
|
|||
Zotero.DB.beginTransaction();
|
||||
|
||||
var newCreator = new Zotero.Creator;
|
||||
newCreator.libraryID = libraryID;
|
||||
newCreator.setFields(fields);
|
||||
|
||||
var newLinkedCreators = [];
|
||||
var creatorDataID = Zotero.Creators.getDataID(fields);
|
||||
if (creatorDataID) {
|
||||
newLinkedCreators = Zotero.Creators.getCreatorsWithData(creatorDataID);
|
||||
newLinkedCreators = Zotero.Creators.getCreatorsWithData(creatorDataID, libraryID);
|
||||
}
|
||||
|
||||
if (oldCreator) {
|
||||
if (oldCreator.ref.equals(newCreator)) {
|
||||
if (oldCreator.ref.equals(newCreator) || (oldCreator.ref.libraryID != newCreator.libraryID)) {
|
||||
if (oldCreator.creatorTypeID == creatorTypeID) {
|
||||
Zotero.debug("Creator " + oldCreator.ref.id + " hasn't changed");
|
||||
}
|
||||
|
@ -1913,7 +1915,15 @@
|
|||
|
||||
this.item.setCreator(index, creator, creatorTypeID);
|
||||
if (this.saveOnEdit) {
|
||||
this.item.save();
|
||||
try {
|
||||
this.item.save();
|
||||
}
|
||||
catch (e) {
|
||||
// DEBUG: Errors aren't being logged in Fx3.1b4pre without this
|
||||
Zotero.debug(e);
|
||||
Components.utils.reportError(e);
|
||||
throw (e);
|
||||
}
|
||||
}
|
||||
|
||||
Zotero.DB.commitTransaction();
|
||||
|
|
|
@ -193,7 +193,7 @@
|
|||
this._leftpane.objectbox.clickableFields = diffFields;
|
||||
this._rightpane.objectbox.clickableFields = diffFields;
|
||||
|
||||
var mergeItem = new Zotero.Item(false, this._leftpane.ref.itemTypeID);
|
||||
var mergeItem = new Zotero.Item(this._leftpane.ref.itemTypeID);
|
||||
this._mergepane.ref = mergeItem;
|
||||
this._mergepane.objectbox.visibleFields = fields;
|
||||
}
|
||||
|
@ -428,7 +428,7 @@
|
|||
value = row.lastChild.getAttribute('itemTypeID');
|
||||
|
||||
if (!mergepane.ref) {
|
||||
mergepane.ref = new Zotero.Item(false, value);
|
||||
mergepane.ref = new Zotero.Item(value);
|
||||
}
|
||||
else {
|
||||
mergepane.objectbox.changeTypeTo(value, true);
|
||||
|
|
|
@ -222,7 +222,10 @@
|
|||
}
|
||||
|
||||
// Create new note
|
||||
var item = new Zotero.Item(false, 'note');
|
||||
var item = new Zotero.Item('note');
|
||||
if (this.parent) {
|
||||
item.libraryID = this.parent.libraryID;
|
||||
}
|
||||
item.setNote(noteField.value);
|
||||
if (this.parent) {
|
||||
item.setSource(this.parent.id);
|
||||
|
@ -230,7 +233,7 @@
|
|||
if (this.saveOnEdit) {
|
||||
var id = item.save();
|
||||
|
||||
if (this.parent && this.collection) {
|
||||
if (!this.parent && this.collection) {
|
||||
this.collection.addItem(id);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -137,10 +137,18 @@
|
|||
window.openDialog('chrome://zotero/content/selectItemsDialog.xul', '',
|
||||
'chrome,dialog=no,modal,centerscreen,resizable=yes', io);
|
||||
|
||||
if(io.dataOut && this.item)
|
||||
{
|
||||
for(var i = 0; i < io.dataOut.length; i++)
|
||||
{
|
||||
if(io.dataOut) {
|
||||
if (io.dataOut.length) {
|
||||
var relItem = Zotero.Items.get(io.dataOut[0]);
|
||||
if (relItem.libraryID != this.item.libraryID) {
|
||||
// FIXME
|
||||
var prompt = Components.classes["@mozilla.org/network/default-prompt;1"]
|
||||
.getService(Components.interfaces.nsIPrompt);
|
||||
prompt.alert("", "You cannot relate items in different libraries in this Zotero release.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
for(var i = 0; i < io.dataOut.length; i++) {
|
||||
this.item.addRelatedItem(io.dataOut[i]);
|
||||
}
|
||||
this.item.save();
|
||||
|
|
|
@ -39,6 +39,19 @@
|
|||
<field name="_dirty">null</field>
|
||||
<field name="_empty">null</field>
|
||||
<field name="selection"/>
|
||||
|
||||
<field name="_libraryID"/>
|
||||
<property name="libraryID" onget="return this._libraryID">
|
||||
<setter>
|
||||
<![CDATA[
|
||||
if (this._libraryID != val) {
|
||||
this._dirty = true;
|
||||
}
|
||||
this._libraryID = val;
|
||||
]]>
|
||||
</setter>
|
||||
</property>
|
||||
|
||||
<property name="showAutomatic" onget="return this.getAttribute('showAutomatic') != 'false'"/>
|
||||
<property name="_types">
|
||||
<getter>
|
||||
|
@ -170,7 +183,7 @@
|
|||
var tagsToggleBox = this.id('tags-toggle');
|
||||
|
||||
if (fetch || this._dirty) {
|
||||
this._tags = Zotero.Tags.getAll(this._types);
|
||||
this._tags = Zotero.Tags.getAll(this._types, this.libraryID);
|
||||
|
||||
// Remove children
|
||||
while (tagsToggleBox.hasChildNodes()){
|
||||
|
@ -414,7 +427,7 @@
|
|||
<![CDATA[
|
||||
// If a selected tag no longer exists, deselect it
|
||||
if (event == 'delete') {
|
||||
this._tags = Zotero.Tags.getAll(this._types);
|
||||
this._tags = Zotero.Tags.getAll(this._types, this.libraryID);
|
||||
|
||||
for (var tag in this.selection) {
|
||||
for each(var tag2 in this._tags) {
|
||||
|
@ -658,6 +671,17 @@
|
|||
|
||||
|
||||
function onDragOver(event, flavour, session) {
|
||||
/*
|
||||
// TODO: get drop data
|
||||
var ids = dropData.data.split(',');
|
||||
var items = Zotero.Items.get(ids);
|
||||
for (var i=0; i<items.length; i++) {
|
||||
if (!Zotero.Items.isEditable(items[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
event.target.setAttribute('draggedOver', true);
|
||||
return true;
|
||||
}
|
||||
|
@ -716,7 +740,9 @@
|
|||
|
||||
<xul:hbox>
|
||||
<xul:hbox pack="start">
|
||||
<xul:checkbox id="display-all-tags" label="&zotero.tagSelector.displayAll;"
|
||||
<!-- TODO: localize or change -->
|
||||
<!-- <xul:checkbox id="display-all-tags" label="&zotero.tagSelector.displayAll;"-->
|
||||
<xul:checkbox id="display-all-tags" label="Display all tags in this library"
|
||||
oncommand="var ts = document.getBindingParent(this); ts.filterToScope = !this.checked; event.stopPropagation();">
|
||||
</xul:checkbox>
|
||||
</xul:hbox>
|
||||
|
|
|
@ -112,11 +112,14 @@ var Zotero_Browser = new function() {
|
|||
function(e) { Zotero_Browser.chromeUnload(e) }, false);
|
||||
}
|
||||
|
||||
/*
|
||||
* Scrapes a page (called when the capture icon is clicked); takes a collection
|
||||
* ID as the argument
|
||||
/**
|
||||
* Scrapes a page (called when the capture icon is clicked)
|
||||
*
|
||||
* @param {Integer} libraryID
|
||||
* @param {Integer} collectionID
|
||||
* @return void
|
||||
*/
|
||||
function scrapeThisPage(saveLocation) {
|
||||
function scrapeThisPage(libraryID, collectionID) {
|
||||
if (!Zotero.stateCheck()) {
|
||||
Zotero_Browser.progress.changeHeadline(Zotero.getString("ingester.scrapeError"));
|
||||
var desc = Zotero.getString("ingester.scrapeError.transactionInProgress.previousError")
|
||||
|
@ -126,7 +129,7 @@ var Zotero_Browser = new function() {
|
|||
Zotero_Browser.progress.startCloseTimer(8000);
|
||||
return;
|
||||
}
|
||||
_getTabObject(this.tabbrowser.selectedBrowser).translate(saveLocation);
|
||||
_getTabObject(this.tabbrowser.selectedBrowser).translate(libraryID, collectionID);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -192,6 +195,8 @@ var Zotero_Browser = new function() {
|
|||
|
||||
/*
|
||||
* called to show the collection selection popup
|
||||
*
|
||||
* not currently used
|
||||
*/
|
||||
function showPopup(collectionID, parentElement) {
|
||||
if(_scrapePopupShowing && parentElement.hasChildNodes()) {
|
||||
|
@ -676,19 +681,18 @@ Zotero_Browser.Tab.prototype._attemptLocalFileImport = function(doc) {
|
|||
}
|
||||
|
||||
/*
|
||||
* translate a page, saving in saveLocation
|
||||
* translate a page
|
||||
*
|
||||
* @param {Integer} libraryID
|
||||
* @param {Integer} collectionID
|
||||
*/
|
||||
Zotero_Browser.Tab.prototype.translate = function(saveLocation) {
|
||||
Zotero_Browser.Tab.prototype.translate = function(libraryID, collectionID) {
|
||||
if(this.page.translators && this.page.translators.length) {
|
||||
Zotero_Browser.progress.show();
|
||||
Zotero_Browser.isScraping = true;
|
||||
|
||||
if(saveLocation) {
|
||||
saveLocation = Zotero.Collections.get(saveLocation);
|
||||
} else { // save to currently selected collection, if a collection is selected
|
||||
try {
|
||||
saveLocation = ZoteroPane.getSelectedCollection();
|
||||
} catch(e) {}
|
||||
if(collectionID) {
|
||||
collection = Zotero.Collections.get(collectionID);
|
||||
}
|
||||
|
||||
var me = this;
|
||||
|
@ -701,9 +705,9 @@ Zotero_Browser.Tab.prototype.translate = function(saveLocation) {
|
|||
this.page.hasBeenTranslated = true;
|
||||
}
|
||||
this.page.translate.clearHandlers("itemDone");
|
||||
this.page.translate.setHandler("itemDone", function(obj, item) { Zotero_Browser.itemDone(obj, item, saveLocation) });
|
||||
this.page.translate.setHandler("itemDone", function(obj, item) { Zotero_Browser.itemDone(obj, item, collection) });
|
||||
|
||||
this.page.translate.translate();
|
||||
this.page.translate.translate(libraryID);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -330,7 +330,8 @@ var Zotero_File_Interface = new function() {
|
|||
} else {
|
||||
var searchRef = ZoteroPane.getSelectedSavedSearch();
|
||||
if(searchRef) {
|
||||
var search = new Zotero.Search(searchRef.id);
|
||||
var search = new Zotero.Search();
|
||||
search.id = searchRef.id;
|
||||
name = search.name;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ const Zotero_Lookup = new function () {
|
|||
}
|
||||
}
|
||||
|
||||
var translate = new Zotero.Translate("search", true, false);
|
||||
var translate = new Zotero.Translate("search");
|
||||
translate.setSearch(item);
|
||||
|
||||
// be lenient about translators
|
||||
|
@ -38,15 +38,17 @@ const Zotero_Lookup = new function () {
|
|||
}
|
||||
});
|
||||
|
||||
var saveLocation = false;
|
||||
var libraryID = null;
|
||||
var collection = false;
|
||||
try {
|
||||
saveLocation = window.opener.ZoteroPane.getSelectedCollection();
|
||||
libraryID = window.opener.ZoteroPane.getSelectedLibraryID();
|
||||
collection = window.opener.ZoteroPane.getSelectedCollection();
|
||||
} catch(e) {}
|
||||
translate.setHandler("itemDone", function(obj, item) {
|
||||
if(saveLocation) saveLocation.addItem(item.getID());
|
||||
if(collection) collection.addItem(item.id);
|
||||
});
|
||||
|
||||
translate.translate();
|
||||
translate.translate(libraryID);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,7 +66,6 @@ var ZoteroPane = new function()
|
|||
this.getSortedItems = getSortedItems;
|
||||
this.getSortField = getSortField;
|
||||
this.getSortDirection = getSortDirection;
|
||||
this.buildCollectionContextMenu = buildCollectionContextMenu;
|
||||
this.buildItemContextMenu = buildItemContextMenu;
|
||||
this.onDoubleClick = onDoubleClick;
|
||||
this.loadURI = loadURI;
|
||||
|
@ -74,11 +73,8 @@ var ZoteroPane = new function()
|
|||
this.clearItemsPaneMessage = clearItemsPaneMessage;
|
||||
this.contextPopupShowing = contextPopupShowing;
|
||||
this.openNoteWindow = openNoteWindow;
|
||||
this.newNote = newNote;
|
||||
this.addTextToNote = addTextToNote;
|
||||
this.addItemFromPage = addItemFromPage;
|
||||
this.addAttachmentFromDialog = addAttachmentFromDialog;
|
||||
this.addAttachmentFromPage = addAttachmentFromPage;
|
||||
this.viewAttachment = viewAttachment;
|
||||
this.viewSelectedAttachment = viewSelectedAttachment;
|
||||
this.showAttachmentNotFoundDialog = showAttachmentNotFoundDialog;
|
||||
|
@ -92,6 +88,9 @@ var ZoteroPane = new function()
|
|||
var self = this;
|
||||
var titlebarcolorState, toolbarCollapseState, titleState;
|
||||
|
||||
// Also needs to be changed in collectionTreeView.js
|
||||
var _lastViewedFolderRE = /^(?:(C|S|G)([0-9]+)|L)$/;
|
||||
|
||||
/*
|
||||
* Called when the window is open
|
||||
*/
|
||||
|
@ -136,7 +135,7 @@ var ZoteroPane = new function()
|
|||
Zotero.setFontSize(document.getElementById('zotero-pane'))
|
||||
|
||||
if (Zotero.isMac) {
|
||||
document.getElementById('zotero-tb-actions-zeroconf-update').setAttribute('hidden', false);
|
||||
//document.getElementById('zotero-tb-actions-zeroconf-update').setAttribute('hidden', false);
|
||||
document.getElementById('zotero-pane').setAttribute('platform', 'mac');
|
||||
} else if(Zotero.isWin) {
|
||||
document.getElementById('zotero-pane').setAttribute('platform', 'win');
|
||||
|
@ -180,11 +179,6 @@ var ZoteroPane = new function()
|
|||
|
||||
Zotero.Keys.windowInit(document);
|
||||
|
||||
// If the database was initialized and Zotero hasn't been run before
|
||||
// in this profile, display the Quick Start Guide -- this way the guide
|
||||
// won't be displayed when they sync their DB to another profile or if
|
||||
// they the DB is initialized erroneously (e.g. while switching data
|
||||
// directory locations)
|
||||
if (Zotero.restoreFromServer) {
|
||||
Zotero.restoreFromServer = false;
|
||||
|
||||
|
@ -213,6 +207,11 @@ var ZoteroPane = new function()
|
|||
}
|
||||
}, 1000);
|
||||
}
|
||||
// If the database was initialized and Zotero hasn't been run before
|
||||
// in this profile, display the Quick Start Guide -- this way the guide
|
||||
// won't be displayed when they sync their DB to another profile or if
|
||||
// they the DB is initialized erroneously (e.g. while switching data
|
||||
// directory locations)
|
||||
else if (Zotero.Schema.dbInitialized && Zotero.Prefs.get('firstRun')) {
|
||||
setTimeout(function () {
|
||||
gBrowser.selectedTab = gBrowser.addTab(ZOTERO_CONFIG.FIRST_RUN_URL);
|
||||
|
@ -629,29 +628,42 @@ var ZoteroPane = new function()
|
|||
return false;
|
||||
}
|
||||
|
||||
var item = new Zotero.Item(false, typeID);
|
||||
|
||||
for (var i in data)
|
||||
{
|
||||
item.setField(i, data[i]);
|
||||
if (!this.canEdit()) {
|
||||
this.displayCannotEditLibraryMessage();
|
||||
return;
|
||||
}
|
||||
|
||||
item.save();
|
||||
var item = new Zotero.Item(typeID);
|
||||
item.libraryID = this.getSelectedLibraryID();
|
||||
for (var i in data) {
|
||||
item.setField(i, data[i]);
|
||||
}
|
||||
var itemID = item.save();
|
||||
|
||||
if (this.itemsView && this.itemsView._itemGroup.isCollection()) {
|
||||
this.itemsView._itemGroup.ref.addItem(item.id);
|
||||
this.itemsView._itemGroup.ref.addItem(itemID);
|
||||
}
|
||||
|
||||
//set to Info tab
|
||||
document.getElementById('zotero-view-item').selectedIndex = 0;
|
||||
|
||||
this.selectItem(item.id);
|
||||
this.selectItem(itemID);
|
||||
|
||||
return item;
|
||||
return Zotero.Items.get(itemID);
|
||||
}
|
||||
|
||||
function newCollection(parent)
|
||||
{
|
||||
if (!Zotero.stateCheck()) {
|
||||
this.displayErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.canEdit()) {
|
||||
this.displayCannotEditLibraryMessage();
|
||||
return;
|
||||
}
|
||||
|
||||
var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
|
||||
.getService(Components.interfaces.nsIPromptService);
|
||||
|
||||
|
@ -674,13 +686,29 @@ var ZoteroPane = new function()
|
|||
}
|
||||
|
||||
var collection = new Zotero.Collection;
|
||||
collection.libraryID = this.getSelectedLibraryID();
|
||||
collection.name = newName.value;
|
||||
collection.parent = parent;
|
||||
collection.save();
|
||||
}
|
||||
|
||||
|
||||
this.newGroup = function () {
|
||||
if (this.isFullScreen()) {
|
||||
this.toggleDisplay();
|
||||
}
|
||||
|
||||
window.loadURI(Zotero.Groups.addGroupURL);
|
||||
}
|
||||
|
||||
|
||||
function newSearch()
|
||||
{
|
||||
if (!Zotero.stateCheck()) {
|
||||
this.displayErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
var s = new Zotero.Search();
|
||||
s.addCondition('title', 'contains', '');
|
||||
|
||||
|
@ -692,6 +720,21 @@ var ZoteroPane = new function()
|
|||
}
|
||||
|
||||
|
||||
this.openLookupWindow = function () {
|
||||
if (!Zotero.stateCheck()) {
|
||||
this.displayErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.canEdit()) {
|
||||
this.displayCannotEditLibraryMessage();
|
||||
return;
|
||||
}
|
||||
|
||||
window.openDialog('chrome://zotero/content/lookup.xul', 'zotero-lookup', 'chrome,modal');
|
||||
}
|
||||
|
||||
|
||||
function openAdvancedSearchWindow() {
|
||||
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
|
||||
.getService(Components.interfaces.nsIWindowMediator);
|
||||
|
@ -825,13 +868,13 @@ var ZoteroPane = new function()
|
|||
* Passed to the items tree to trigger on changes
|
||||
*/
|
||||
function _setTagScope() {
|
||||
var itemgroup = self.collectionsView.
|
||||
_getItemAtRow(self.collectionsView.selection.currentIndex);
|
||||
var itemGroup = self.collectionsView._getItemAtRow(self.collectionsView.selection.currentIndex);
|
||||
var tagSelector = document.getElementById('zotero-tag-selector');
|
||||
if (!tagSelector.getAttribute('collapsed') ||
|
||||
tagSelector.getAttribute('collapsed') == 'false') {
|
||||
Zotero.debug('Updating tag selector with current tags');
|
||||
tagSelector.scope = itemgroup.getChildTags();
|
||||
tagSelector.libraryID = itemGroup.ref.libraryID;
|
||||
tagSelector.scope = itemGroup.getChildTags();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -841,45 +884,59 @@ var ZoteroPane = new function()
|
|||
if (this.itemsView)
|
||||
{
|
||||
this.itemsView.unregister();
|
||||
document.getElementById('zotero-items-tree').removeEventListener(
|
||||
'keypress', this.itemsView.wrappedJSObject.listener, false
|
||||
);
|
||||
if (this.itemsView.wrappedJSObject.listener) {
|
||||
document.getElementById('zotero-items-tree').removeEventListener(
|
||||
'keypress', this.itemsView.wrappedJSObject.listener, false
|
||||
);
|
||||
}
|
||||
this.itemsView.wrappedJSObject.listener = null;
|
||||
document.getElementById('zotero-items-tree').view = this.itemsView = null;
|
||||
}
|
||||
|
||||
document.getElementById('zotero-tb-search').value = "";
|
||||
|
||||
if (this.collectionsView.selection.count == 1 && this.collectionsView.selection.currentIndex != -1) {
|
||||
var itemgroup = this.collectionsView._getItemAtRow(this.collectionsView.selection.currentIndex);
|
||||
itemgroup.setSearch('');
|
||||
itemgroup.setTags(getTagSelection());
|
||||
itemgroup.showDuplicates = false;
|
||||
|
||||
try {
|
||||
Zotero.UnresponsiveScriptIndicator.disable();
|
||||
this.itemsView = new Zotero.ItemTreeView(itemgroup);
|
||||
this.itemsView.addCallback(_setTagScope);
|
||||
document.getElementById('zotero-items-tree').view = this.itemsView;
|
||||
this.itemsView.selection.clearSelection();
|
||||
}
|
||||
finally {
|
||||
Zotero.UnresponsiveScriptIndicator.enable();
|
||||
}
|
||||
|
||||
if (itemgroup.isLibrary()) {
|
||||
Zotero.Prefs.set('lastViewedFolder', 'L');
|
||||
}
|
||||
if (itemgroup.isCollection()) {
|
||||
Zotero.Prefs.set('lastViewedFolder', 'C' + itemgroup.ref.id);
|
||||
}
|
||||
else if (itemgroup.isSearch()) {
|
||||
Zotero.Prefs.set('lastViewedFolder', 'S' + itemgroup.ref.id);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.collectionsView.selection.count != 1) {
|
||||
document.getElementById('zotero-items-tree').view = this.itemsView = null;
|
||||
return;
|
||||
}
|
||||
|
||||
// this.collectionsView.selection.currentIndex != -1
|
||||
|
||||
var itemgroup = this.collectionsView._getItemAtRow(this.collectionsView.selection.currentIndex);
|
||||
|
||||
/*
|
||||
if (itemgroup.isSeparator()) {
|
||||
document.getElementById('zotero-items-tree').view = this.itemsView = null;
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
itemgroup.setSearch('');
|
||||
itemgroup.setTags(getTagSelection());
|
||||
itemgroup.showDuplicates = false;
|
||||
|
||||
try {
|
||||
Zotero.UnresponsiveScriptIndicator.disable();
|
||||
this.itemsView = new Zotero.ItemTreeView(itemgroup);
|
||||
this.itemsView.addCallback(_setTagScope);
|
||||
document.getElementById('zotero-items-tree').view = this.itemsView;
|
||||
this.itemsView.selection.clearSelection();
|
||||
}
|
||||
finally {
|
||||
Zotero.UnresponsiveScriptIndicator.enable();
|
||||
}
|
||||
|
||||
if (itemgroup.isLibrary()) {
|
||||
Zotero.Prefs.set('lastViewedFolder', 'L');
|
||||
}
|
||||
if (itemgroup.isCollection()) {
|
||||
Zotero.Prefs.set('lastViewedFolder', 'C' + itemgroup.ref.id);
|
||||
}
|
||||
else if (itemgroup.isSearch()) {
|
||||
Zotero.Prefs.set('lastViewedFolder', 'S' + itemgroup.ref.id);
|
||||
}
|
||||
else if (itemgroup.isGroup()) {
|
||||
Zotero.Prefs.set('lastViewedFolder', 'G' + itemgroup.ref.id);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -928,7 +985,7 @@ var ZoteroPane = new function()
|
|||
tabs.hidden = true;
|
||||
|
||||
var noteEditor = document.getElementById('zotero-note-editor');
|
||||
noteEditor.mode = this.itemsView.readOnly ? 'view' : 'edit';
|
||||
noteEditor.mode = this.collectionsView.editable ? 'edit' : 'view';
|
||||
|
||||
// If loading new or different note, disable undo while we repopulate the text field
|
||||
// so Undo doesn't end up clearing the field. This also ensures that Undo doesn't
|
||||
|
@ -942,10 +999,7 @@ var ZoteroPane = new function()
|
|||
noteEditor.enableUndo();
|
||||
|
||||
var viewButton = document.getElementById('zotero-view-note-button');
|
||||
if (this.itemsView.readOnly) {
|
||||
viewButton.hidden = true;
|
||||
}
|
||||
else {
|
||||
if (this.collectionsView.editable) {
|
||||
viewButton.hidden = false;
|
||||
viewButton.setAttribute('noteID', item.ref.id);
|
||||
if (item.ref.getSource()) {
|
||||
|
@ -955,6 +1009,9 @@ var ZoteroPane = new function()
|
|||
viewButton.removeAttribute('sourceID');
|
||||
}
|
||||
}
|
||||
else {
|
||||
viewButton.hidden = true;
|
||||
}
|
||||
|
||||
document.getElementById('zotero-item-pane-content').selectedIndex = 2;
|
||||
}
|
||||
|
@ -963,7 +1020,7 @@ var ZoteroPane = new function()
|
|||
tabs.hidden = true;
|
||||
|
||||
var attachmentBox = document.getElementById('zotero-attachment-box');
|
||||
attachmentBox.mode = this.itemsView.readOnly ? 'view' : 'edit';
|
||||
attachmentBox.mode = this.collectionsView.editable ? 'edit' : 'view';
|
||||
attachmentBox.item = item.ref;
|
||||
|
||||
document.getElementById('zotero-item-pane-content').selectedIndex = 3;
|
||||
|
@ -973,16 +1030,16 @@ var ZoteroPane = new function()
|
|||
else
|
||||
{
|
||||
document.getElementById('zotero-item-pane-content').selectedIndex = 1;
|
||||
if (this.itemsView.readOnly) {
|
||||
document.getElementById('zotero-view-item').selectedIndex = 0;
|
||||
ZoteroItemPane.viewItem(item.ref, 'view');
|
||||
tabs.hidden = true;
|
||||
}
|
||||
else {
|
||||
if (this.collectionsView.editable) {
|
||||
ZoteroItemPane.viewItem(item.ref);
|
||||
tabs.selectedIndex = document.getElementById('zotero-view-item').selectedIndex;
|
||||
tabs.hidden = false;
|
||||
}
|
||||
else {
|
||||
document.getElementById('zotero-view-item').selectedIndex = 0;
|
||||
ZoteroItemPane.viewItem(item.ref, 'view');
|
||||
tabs.hidden = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1041,21 +1098,26 @@ var ZoteroPane = new function()
|
|||
|
||||
|
||||
function duplicateSelectedItem() {
|
||||
var item = this.getSelectedItems()[0];
|
||||
if (item.getTags()) {
|
||||
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
|
||||
.getService(Components.interfaces.nsIPromptService);
|
||||
ps.alert(null, "Error", "Duplication of tagged items is not available in this Zotero release.");
|
||||
if (!this.canEdit()) {
|
||||
this.displayCannotEditLibraryMessage();
|
||||
return;
|
||||
}
|
||||
|
||||
var newItem = this.getSelectedItems()[0].clone();
|
||||
var newItemID = newItem.save()
|
||||
var newItem = Zotero.Items.get(newItemID);
|
||||
var item = this.getSelectedItems()[0];
|
||||
|
||||
// Create new unsaved clone item in target library
|
||||
var newItem = new Zotero.Item(item.itemTypeID);
|
||||
newItem.libraryID = item.libraryID;
|
||||
// DEBUG: save here because clone() doesn't currently work on unsaved tagged items
|
||||
var id = newItem.save();
|
||||
|
||||
var newItem = Zotero.Items.get(id);
|
||||
item.clone(false, newItem);
|
||||
newItem.save();
|
||||
|
||||
if (this.itemsView._itemGroup.isCollection()) {
|
||||
this.itemsView._itemGroup.ref.addItem(newItem.id);
|
||||
this.selectItem(newItemID);
|
||||
this.selectItem(newItem.id);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1070,17 +1132,23 @@ var ZoteroPane = new function()
|
|||
*/
|
||||
this.deleteSelectedItems = function (force) {
|
||||
if (this.itemsView && this.itemsView.selection.count > 0) {
|
||||
var itemGroup = this.itemsView._itemGroup;
|
||||
|
||||
if (!itemGroup.isTrash() && !this.canEdit()) {
|
||||
this.displayCannotEditLibraryMessage();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!force){
|
||||
if (this.itemsView._itemGroup.isCollection()) {
|
||||
if (itemGroup.isCollection()) {
|
||||
var noPrompt = true;
|
||||
}
|
||||
// Do nothing in search and share views
|
||||
else if (this.itemsView._itemGroup.isSearch() ||
|
||||
this.itemsView._itemGroup.isShare()) {
|
||||
else if (itemGroup.isSearch() || itemGroup.isShare()) {
|
||||
return;
|
||||
}
|
||||
// Do nothing in trash view if any non-deleted items are selected
|
||||
else if (this.itemsView._itemGroup.isTrash()) {
|
||||
else if (itemGroup.isTrash()) {
|
||||
var start = {};
|
||||
var end = {};
|
||||
for (var i=0, len=this.itemsView.selection.getRangeCount(); i<len; i++) {
|
||||
|
@ -1127,6 +1195,11 @@ var ZoteroPane = new function()
|
|||
|
||||
function deleteSelectedCollection()
|
||||
{
|
||||
if (!this.canEdit()) {
|
||||
this.displayCannotEditLibraryMessage();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.collectionsView.selection.count == 1) {
|
||||
var row =
|
||||
this.collectionsView._getItemAtRow(this.collectionsView.selection.currentIndex);
|
||||
|
@ -1179,6 +1252,11 @@ var ZoteroPane = new function()
|
|||
|
||||
function editSelectedCollection()
|
||||
{
|
||||
if (!this.canEdit()) {
|
||||
this.displayCannotEditLibraryMessage();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.collectionsView.selection.count > 0) {
|
||||
var row = this.collectionsView._getItemAtRow(this.collectionsView.selection.currentIndex);
|
||||
|
||||
|
@ -1196,7 +1274,8 @@ var ZoteroPane = new function()
|
|||
}
|
||||
}
|
||||
else {
|
||||
var s = new Zotero.Search(row.ref.id);
|
||||
var s = new Zotero.Search();
|
||||
s.id = row.ref.id;
|
||||
var io = {dataIn: {search: s, name: row.getName()}, dataOut: null};
|
||||
window.openDialog('chrome://zotero/content/searchDialog.xul','','chrome,modal',io);
|
||||
if (io.dataOut) {
|
||||
|
@ -1310,24 +1389,55 @@ var ZoteroPane = new function()
|
|||
function selectItem(itemID, inLibrary, expand)
|
||||
{
|
||||
if (!itemID) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.itemsView) {
|
||||
if (!this.itemsView._itemGroup.isLibrary() && inLibrary) {
|
||||
this.collectionsView.selection.select(0);
|
||||
}
|
||||
|
||||
var selected = this.itemsView.selectItem(itemID, expand);
|
||||
if (!selected) {
|
||||
this.collectionsView.selection.select(0);
|
||||
this.itemsView.selectItem(itemID, expand);
|
||||
}
|
||||
var item = Zotero.Items.get(itemID);
|
||||
if (!item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.itemsView) {
|
||||
Components.utils.reportError("Items view not set in ZoteroPane.selectItem()");
|
||||
return false;
|
||||
}
|
||||
|
||||
var currentLibraryID = this.getSelectedLibraryID();
|
||||
// If in a different library
|
||||
if (item.libraryID != currentLibraryID) {
|
||||
this.collectionsView.selectLibrary(item.libraryID);
|
||||
}
|
||||
// Force switch to library view
|
||||
else if (!this.itemsView._itemGroup.isLibrary() && inLibrary) {
|
||||
this.collectionsView.selectLibrary(item.libraryID);
|
||||
}
|
||||
|
||||
var selected = this.itemsView.selectItem(itemID, expand);
|
||||
if (!selected) {
|
||||
this.collectionsView.selectLibrary(item.libraryID);
|
||||
this.itemsView.selectItem(itemID, expand);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
this.getSelectedLibraryID = function () {
|
||||
var group = this.getSelectedGroup();
|
||||
if (group) {
|
||||
return group.libraryID;
|
||||
}
|
||||
var collection = this.getSelectedCollection();
|
||||
if (collection) {
|
||||
return collection.libraryID;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
function getSelectedCollection(asID) {
|
||||
if (this.collectionsView.selection
|
||||
if (this.collectionsView
|
||||
&& this.collectionsView.selection
|
||||
&& this.collectionsView.selection.count > 0
|
||||
&& this.collectionsView.selection.currentIndex != -1) {
|
||||
var collection = this.collectionsView._getItemAtRow(this.collectionsView.selection.currentIndex);
|
||||
|
@ -1335,20 +1445,10 @@ var ZoteroPane = new function()
|
|||
return asID ? collection.ref.id : collection.ref;
|
||||
}
|
||||
}
|
||||
// If the Zotero pane hasn't yet been opened, use the lastViewedFolder pref
|
||||
else {
|
||||
var lastViewedFolder = Zotero.Prefs.get('lastViewedFolder');
|
||||
var matches = lastViewedFolder.match(/^(?:(C|S)([0-9]+)|L)$/);
|
||||
if (matches && matches[1] == 'C') {
|
||||
var col = Zotero.Collections.get(matches[2]);
|
||||
if (col) {
|
||||
return asID ? col.id : col;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
function getSelectedSavedSearch(asID)
|
||||
{
|
||||
if (this.collectionsView.selection.count > 0 && this.collectionsView.selection.currentIndex != -1) {
|
||||
|
@ -1357,20 +1457,10 @@ var ZoteroPane = new function()
|
|||
return asID ? collection.ref.id : collection.ref;
|
||||
}
|
||||
}
|
||||
// If the Zotero pane hasn't yet been opened, use the lastViewedFolder pref
|
||||
else {
|
||||
var lastViewedFolder = Zotero.Prefs.get('lastViewedFolder');
|
||||
var matches = lastViewedFolder.match(/^(?:(C|S)([0-9]+)|L)$/);
|
||||
if (matches && matches[1] == 'S') {
|
||||
var search = Zotero.Search.get(matches[2]);
|
||||
if (search) {
|
||||
return asID ? search.id : search;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return an array of Item objects for selected items
|
||||
*
|
||||
|
@ -1386,6 +1476,19 @@ var ZoteroPane = new function()
|
|||
}
|
||||
|
||||
|
||||
this.getSelectedGroup = function (asID) {
|
||||
if (this.collectionsView.selection
|
||||
&& this.collectionsView.selection.count > 0
|
||||
&& this.collectionsView.selection.currentIndex != -1) {
|
||||
var itemGroup = this.collectionsView._getItemAtRow(this.collectionsView.selection.currentIndex);
|
||||
if (itemGroup && itemGroup.isGroup()) {
|
||||
return asID ? itemGroup.ref.id : itemGroup.ref;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Returns an array of Zotero.Item objects of visible items in current sort order
|
||||
*
|
||||
|
@ -1418,10 +1521,9 @@ var ZoteroPane = new function()
|
|||
}
|
||||
|
||||
|
||||
function buildCollectionContextMenu()
|
||||
this.buildCollectionContextMenu = function buildCollectionContextMenu()
|
||||
{
|
||||
var menu = document.getElementById('zotero-collectionmenu');
|
||||
|
||||
var m = {
|
||||
newCollection: 0,
|
||||
newSavedSearch: 1,
|
||||
|
@ -1437,22 +1539,32 @@ var ZoteroPane = new function()
|
|||
emptyTrash: 11
|
||||
};
|
||||
|
||||
var itemGroup = this.collectionsView._getItemAtRow(this.collectionsView.selection.currentIndex);
|
||||
|
||||
var enable = [], disable = [], show = [];
|
||||
|
||||
// Collection
|
||||
if (this.collectionsView.selection.count == 1 &&
|
||||
this.collectionsView._getItemAtRow(this.collectionsView.selection.currentIndex).isCollection())
|
||||
{
|
||||
var show = [m.newSubcollection, m.sep1, m.editSelectedCollection, m.removeCollection,
|
||||
m.sep2, m.exportCollection, m.createBibCollection, m.loadReport];
|
||||
if (itemGroup.isCollection()) {
|
||||
show = [
|
||||
m.newSubcollection,
|
||||
m.sep1,
|
||||
m.editSelectedCollection,
|
||||
m.removeCollection,
|
||||
m.sep2,
|
||||
m.exportCollection,
|
||||
m.createBibCollection,
|
||||
m.loadReport
|
||||
];
|
||||
var s = [m.exportCollection, m.createBibCollection, m.loadReport];
|
||||
if (this.itemsView.rowCount>0) {
|
||||
var enable = [m.exportCollection, m.createBibCollection, m.loadReport];
|
||||
enable = s;
|
||||
}
|
||||
else if (!this.collectionsView.isContainerEmpty(this.collectionsView.selection.currentIndex)) {
|
||||
var enable = [m.exportCollection];
|
||||
var disable = [m.createBibCollection, m.loadReport];
|
||||
enable = [m.exportCollection];
|
||||
disable = [m.createBibCollection, m.loadReport];
|
||||
}
|
||||
else
|
||||
{
|
||||
var disable = [m.exportCollection, m.createBibCollection, m.loadReport];
|
||||
else {
|
||||
disable = s;
|
||||
}
|
||||
|
||||
// Adjust labels
|
||||
|
@ -1463,17 +1575,22 @@ var ZoteroPane = new function()
|
|||
menu.childNodes[m.loadReport].setAttribute('label', Zotero.getString('pane.collections.menu.generateReport.collection'));
|
||||
}
|
||||
// Saved Search
|
||||
else if (this.collectionsView.selection.count == 1 &&
|
||||
this.collectionsView._getItemAtRow(this.collectionsView.selection.currentIndex).isSearch()) {
|
||||
var show = [m.editSelectedCollection, m.removeCollection, m.sep2, m.exportCollection,
|
||||
m.createBibCollection, m.loadReport];
|
||||
else if (itemGroup.isSearch()) {
|
||||
show = [
|
||||
m.editSelectedCollection,
|
||||
m.removeCollection,
|
||||
m.sep2,
|
||||
m.exportCollection,
|
||||
m.createBibCollection,
|
||||
m.loadReport
|
||||
];
|
||||
|
||||
var s = [m.exportCollection, m.createBibCollection, m.loadReport];
|
||||
if (this.itemsView.rowCount>0) {
|
||||
var enable = [m.exportCollection, m.createBibCollection, m.loadReport];
|
||||
enable = s;
|
||||
}
|
||||
else
|
||||
{
|
||||
var disable = [m.exportCollection, m.createBibCollection, m.loadReport];
|
||||
else {
|
||||
disable = s;
|
||||
}
|
||||
|
||||
// Adjust labels
|
||||
|
@ -1484,14 +1601,30 @@ var ZoteroPane = new function()
|
|||
menu.childNodes[m.loadReport].setAttribute('label', Zotero.getString('pane.collections.menu.generateReport.savedSearch'));
|
||||
}
|
||||
// Trash
|
||||
else if (this.collectionsView.selection.count == 1 &&
|
||||
this.collectionsView._getItemAtRow(this.collectionsView.selection.currentIndex).isTrash()) {
|
||||
var show = [m.emptyTrash];
|
||||
else if (itemGroup.isTrash()) {
|
||||
show = [m.emptyTrash];
|
||||
}
|
||||
// Header
|
||||
else if (itemGroup.isHeader()) {
|
||||
|
||||
}
|
||||
// Group
|
||||
else if (itemGroup.isGroup()) {
|
||||
show = [m.newCollection];
|
||||
}
|
||||
// Library
|
||||
else
|
||||
{
|
||||
var show = [m.newCollection, m.newSavedSearch, m.sep1, m.exportFile];
|
||||
show = [m.newCollection, m.newSavedSearch, m.sep1, m.exportFile];
|
||||
}
|
||||
|
||||
// Disable some actions if user doesn't have write access
|
||||
var s = [m.editSelectedCollection, m.removeCollection, m.newCollection, m.newSavedSearch];
|
||||
if (itemGroup.isGroup() && !itemGroup.ref.editable) {
|
||||
disable = disable.concat(s);
|
||||
}
|
||||
else {
|
||||
enable = enable.concat(s);
|
||||
}
|
||||
|
||||
for (var i in disable)
|
||||
|
@ -1541,7 +1674,7 @@ var ZoteroPane = new function()
|
|||
var enable = [], disable = [], show = [], hide = [], multiple = '';
|
||||
|
||||
// TODO: implement menu for remote items
|
||||
if (this.itemsView.readOnly) {
|
||||
if (!this.collectionsView.editable) {
|
||||
for each(var pos in m) {
|
||||
disable.push(pos);
|
||||
}
|
||||
|
@ -1725,13 +1858,23 @@ var ZoteroPane = new function()
|
|||
}
|
||||
|
||||
if (tree.id == 'zotero-collections-tree') {
|
||||
var s = this.getSelectedSavedSearch();
|
||||
if (s) {
|
||||
var itemGroup = this.collectionsView._getItemAtRow(this.collectionsView.selection.currentIndex);
|
||||
if (itemGroup.isSearch()) {
|
||||
this.editSelectedCollection();
|
||||
}
|
||||
else if (itemGroup.isGroup()) {
|
||||
var uri = Zotero.URI.getGroupURI(itemGroup.ref, true);
|
||||
window.loadURI(uri);
|
||||
}
|
||||
else if (itemGroup.isHeader()) {
|
||||
if (itemGroup.ref.id == 'group-libraries-header') {
|
||||
var uri = Zotero.URI.getGroupsURL();
|
||||
window.loadURI(uri);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (tree.id == 'zotero-items-tree') {
|
||||
if (this.itemsView.readOnly) {
|
||||
if (!this.collectionsView.editable) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1893,7 +2036,7 @@ var ZoteroPane = new function()
|
|||
}
|
||||
}
|
||||
|
||||
var menuitem = document.getElementById("zotero-context-save-link-as-snapshot");
|
||||
var menuitem = document.getElementById("zotero-context-save-link-as-item");
|
||||
if (menuitem) {
|
||||
if (window.gContextMenu.onLink) {
|
||||
menuitem.hidden = false;
|
||||
|
@ -1904,7 +2047,7 @@ var ZoteroPane = new function()
|
|||
}
|
||||
}
|
||||
|
||||
var menuitem = document.getElementById("zotero-context-save-image-as-snapshot");
|
||||
var menuitem = document.getElementById("zotero-context-save-image-as-item");
|
||||
if (menuitem) {
|
||||
// Not using window.gContextMenu.hasBGImage -- if the user wants it,
|
||||
// they can use the Firefox option to view and then import from there
|
||||
|
@ -1922,26 +2065,32 @@ var ZoteroPane = new function()
|
|||
}
|
||||
|
||||
|
||||
function newNote(popup, parent, text) {
|
||||
this.newNote = function (popup, parent, text) {
|
||||
if (!Zotero.stateCheck()) {
|
||||
this.displayErrorMessage(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.canEdit()) {
|
||||
this.displayCannotEditLibraryMessage();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!popup) {
|
||||
if (!text) {
|
||||
text = '';
|
||||
}
|
||||
text = Zotero.Utilities.prototype.trim(text);
|
||||
|
||||
var item = new Zotero.Item(false, 'note');
|
||||
var item = new Zotero.Item('note');
|
||||
item.libraryID = this.getSelectedLibraryID();
|
||||
item.setNote(text);
|
||||
if (parent) {
|
||||
item.setSource(parent);
|
||||
}
|
||||
var itemID = item.save();
|
||||
|
||||
if (this.itemsView && this.itemsView._itemGroup.isCollection()) {
|
||||
if (!parent && this.itemsView && this.itemsView._itemGroup.isCollection()) {
|
||||
this.itemsView._itemGroup.ref.addItem(itemID);
|
||||
}
|
||||
|
||||
|
@ -1964,6 +2113,11 @@ var ZoteroPane = new function()
|
|||
|
||||
function addTextToNote(text)
|
||||
{
|
||||
if (!this.canEdit()) {
|
||||
this.displayCannotEditLibraryMessage();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// trim
|
||||
text = text.replace(/^[\xA0\r\n\s]*(.*)[\xA0\r\n\s]*$/m, "$1");
|
||||
|
@ -1996,6 +2150,11 @@ var ZoteroPane = new function()
|
|||
|
||||
function openNoteWindow(itemID, col, parentItemID)
|
||||
{
|
||||
if (!this.canEdit()) {
|
||||
this.displayCannotEditLibraryMessage();
|
||||
return;
|
||||
}
|
||||
|
||||
var name = null;
|
||||
|
||||
if (itemID) {
|
||||
|
@ -2026,6 +2185,20 @@ var ZoteroPane = new function()
|
|||
|
||||
function addAttachmentFromDialog(link, id)
|
||||
{
|
||||
if (!this.canEdit()) {
|
||||
this.displayCannotEditLibraryMessage();
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: temporarily disable file attachment options for groups
|
||||
var itemGroup = this.collectionsView._getItemAtRow(this.collectionsView.selection.currentIndex);
|
||||
if (itemGroup.isWithinGroup()) {
|
||||
var pr = Components.classes["@mozilla.org/network/default-prompt;1"]
|
||||
.getService(Components.interfaces.nsIPrompt);
|
||||
pr.alert("", "Files cannot currently be added to group libraries.");
|
||||
return;
|
||||
}
|
||||
|
||||
var nsIFilePicker = Components.interfaces.nsIFilePicker;
|
||||
var fp = Components.classes["@mozilla.org/filepicker;1"]
|
||||
.createInstance(nsIFilePicker);
|
||||
|
@ -2055,80 +2228,120 @@ var ZoteroPane = new function()
|
|||
}
|
||||
|
||||
|
||||
function addItemFromPage() {
|
||||
this.addItemFromPage = function (itemType) {
|
||||
return this.addItemFromDocument(window.content.document, itemType);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {Document} doc
|
||||
* @param {String|Integer} [itemType='webpage'] Item type id or name
|
||||
* @param {Boolean} [saveSnapshot] Force saving of a snapshot,
|
||||
* regardless of automaticSnapshots pref
|
||||
*/
|
||||
this.addItemFromDocument = function (doc, itemType, saveSnapshot) {
|
||||
if (!Zotero.stateCheck()) {
|
||||
this.displayErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.canEdit()) {
|
||||
this.displayCannotEditLibraryMessage();
|
||||
return;
|
||||
}
|
||||
|
||||
var progressWin = new Zotero.ProgressWindow();
|
||||
progressWin.changeHeadline(Zotero.getString('ingester.scraping'));
|
||||
var icon = 'chrome://zotero/skin/treeitem-webpage.png';
|
||||
progressWin.addLines(window.content.document.title, icon)
|
||||
progressWin.addLines(doc.title, icon)
|
||||
progressWin.show();
|
||||
progressWin.startCloseTimer();
|
||||
|
||||
var data = {
|
||||
title: window.content.document.title,
|
||||
url: window.content.document.location.href,
|
||||
title: doc.title,
|
||||
url: doc.location.href,
|
||||
accessDate: "CURRENT_TIMESTAMP"
|
||||
}
|
||||
|
||||
var item = this.newItem(Zotero.ItemTypes.getID('webpage'), data);
|
||||
// Save web page item by default
|
||||
if (!itemType) {
|
||||
itemType = 'webpage';
|
||||
}
|
||||
itemType = Zotero.ItemTypes.getID(itemType);
|
||||
var item = this.newItem(itemType, data);
|
||||
|
||||
// Automatically save snapshot if pref set
|
||||
if (item.id && Zotero.Prefs.get('automaticSnapshots'))
|
||||
{
|
||||
var f = function() {
|
||||
// We set |noParent|, since child items don't belong to collections
|
||||
ZoteroPane.addAttachmentFromPage(false, item.id, true);
|
||||
var filesEditable = false;
|
||||
if (item.libraryID) {
|
||||
var group = Zotero.Groups.getByLibraryID(item.libraryID);
|
||||
filesEditable = group.filesEditable;
|
||||
}
|
||||
|
||||
// Save snapshot if explicitly enabled or automatically pref is set and not explicitly disabled
|
||||
if (saveSnapshot || (saveSnapshot !== false && Zotero.Prefs.get('automaticSnapshots'))) {
|
||||
var link = false;
|
||||
|
||||
if (link) {
|
||||
Zotero.Attachments.linkFromDocument(doc, item.id);
|
||||
}
|
||||
else if (filesEditable) {
|
||||
Zotero.Attachments.importFromDocument(doc, item.id);
|
||||
}
|
||||
// Give progress window time to appear
|
||||
setTimeout(f, 300);
|
||||
}
|
||||
|
||||
return item.id;
|
||||
}
|
||||
|
||||
|
||||
this.addItemFromURL = function (url, itemType) {
|
||||
if (url == window.content.document.location.href) {
|
||||
return this.addItemFromPage(itemType);
|
||||
}
|
||||
|
||||
var processor = function (doc) {
|
||||
ZoteroPane.addItemFromDocument(doc, itemType);
|
||||
};
|
||||
|
||||
var done = function () {}
|
||||
|
||||
var exception = function (e) {
|
||||
Zotero.debug(e);
|
||||
}
|
||||
|
||||
Zotero.Utilities.HTTP.processDocuments([url], processor, done, exception);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Create an attachment from the current page
|
||||
*
|
||||
* |link| -- create web link instead of snapshot
|
||||
* |itemID| -- itemID of parent item
|
||||
* |noParent| -- don't add to current collection
|
||||
* |link| -- create web link instead of snapshot
|
||||
*/
|
||||
function addAttachmentFromPage(link, itemID, noParent)
|
||||
this.addAttachmentFromPage = function (link, itemID)
|
||||
{
|
||||
if (!Zotero.stateCheck()) {
|
||||
this.displayErrorMessage(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!noParent) {
|
||||
var progressWin = new Zotero.ProgressWindow();
|
||||
progressWin.changeHeadline(Zotero.getString('save.' + (link ? 'link' : 'attachment')));
|
||||
var type = link ? 'web-link' : 'snapshot';
|
||||
var icon = 'chrome://zotero/skin/treeitem-attachment-' + type + '.png';
|
||||
progressWin.addLines(window.content.document.title, icon)
|
||||
progressWin.show();
|
||||
progressWin.startCloseTimer();
|
||||
|
||||
if (this.itemsView && this.itemsView._itemGroup.isCollection()) {
|
||||
var parentCollectionID = this.itemsView._itemGroup.ref.id;
|
||||
}
|
||||
if (typeof itemID != 'number') {
|
||||
throw ("itemID must be an integer in ZoteroPane.addAttachmentFromPage()");
|
||||
}
|
||||
|
||||
var f = function() {
|
||||
if (link) {
|
||||
Zotero.Attachments.linkFromDocument(window.content.document, itemID, parentCollectionID);
|
||||
}
|
||||
else {
|
||||
Zotero.Attachments.importFromDocument(window.content.document, itemID, false, parentCollectionID);
|
||||
}
|
||||
var progressWin = new Zotero.ProgressWindow();
|
||||
progressWin.changeHeadline(Zotero.getString('save.' + (link ? 'link' : 'attachment')));
|
||||
var type = link ? 'web-link' : 'snapshot';
|
||||
var icon = 'chrome://zotero/skin/treeitem-attachment-' + type + '.png';
|
||||
progressWin.addLines(window.content.document.title, icon)
|
||||
progressWin.show();
|
||||
progressWin.startCloseTimer();
|
||||
|
||||
if (link) {
|
||||
Zotero.Attachments.linkFromDocument(window.content.document, itemID);
|
||||
}
|
||||
else {
|
||||
Zotero.Attachments.importFromDocument(window.content.document, itemID);
|
||||
}
|
||||
// Give progress window time to appear
|
||||
setTimeout(f, 100);
|
||||
}
|
||||
|
||||
|
||||
|
@ -2225,6 +2438,28 @@ var ZoteroPane = new function()
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test if the user can edit the currently selected library/collection,
|
||||
* and display an error if not
|
||||
*
|
||||
* @return {Boolean} TRUE if user can edit, FALSE if not
|
||||
*/
|
||||
this.canEdit = function () {
|
||||
var itemGroup = this.collectionsView._getItemAtRow(this.collectionsView.selection.currentIndex);
|
||||
return itemGroup.isEditable();
|
||||
}
|
||||
|
||||
|
||||
this.displayCannotEditLibraryMessage = function () {
|
||||
var pr = Components.classes["@mozilla.org/network/default-prompt;1"]
|
||||
.getService(Components.interfaces.nsIPrompt);
|
||||
pr.alert(
|
||||
Zotero.getString('general.accessDenied'),
|
||||
"You cannot make changes to the currently selected library."
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
function showAttachmentNotFoundDialog(itemID, noLocate) {
|
||||
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].
|
||||
createInstance(Components.interfaces.nsIPromptService);
|
||||
|
@ -2254,6 +2489,11 @@ var ZoteroPane = new function()
|
|||
|
||||
|
||||
function relinkAttachment(itemID) {
|
||||
if (!this.canEdit()) {
|
||||
this.displayCannotEditLibraryMessage();
|
||||
return;
|
||||
}
|
||||
|
||||
var item = Zotero.Items.get(itemID);
|
||||
if (!item) {
|
||||
throw('Item ' + itemID + ' not found in ZoteroPane.relinkAttachment()');
|
||||
|
|
|
@ -60,12 +60,13 @@
|
|||
<menuitem id="zotero-context-add-to-new-note" class="menu-iconic"
|
||||
label="&zotero.contextMenu.addTextToNewNote;" hidden="true"
|
||||
oncommand="var str = event.currentTarget.ownerDocument.popupNode.ownerDocument.defaultView.getSelection().toString(); var itemID = ZoteroPane.addItemFromPage(); ZoteroPane.newNote(false, itemID, str)"/>
|
||||
<menuitem id="zotero-context-save-link-as-snapshot" class="menu-iconic"
|
||||
label="&zotero.contextMenu.saveLinkAsSnapshot;" hidden="true"
|
||||
oncommand="Zotero.Attachments.importFromURL(window.gContextMenu.linkURL, false, false, false, ZoteroPane.getSelectedCollection(true))"/>
|
||||
<menuitem id="zotero-context-save-image-as-snapshot" class="menu-iconic"
|
||||
label="&zotero.contextMenu.saveImageAsSnapshot;" hidden="true"
|
||||
oncommand="Zotero.Attachments.importFromURL(window.gContextMenu.onImage ? window.gContextMenu.imageURL : window.gContextMenu.bgImageURL, false, false, false, ZoteroPane.getSelectedCollection(true))"/>
|
||||
<!-- TODO: localize and remove zotero.contextMenu.saveLinkAsItem/saveImageAsSnapshot -->
|
||||
<menuitem id="zotero-context-save-link-as-item" class="menu-iconic"
|
||||
label="Save Link as Zotero Item" hidden="true"
|
||||
oncommand="ZoteroPane.addItemFromURL(window.gContextMenu.linkURL)"/>
|
||||
<menuitem id="zotero-context-save-image-as-item" class="menu-iconic"
|
||||
label="Save Image as Zotero Item" hidden="true"
|
||||
oncommand="ZoteroPane.addItemFromURL(window.gContextMenu.onImage ? (window.gContextMenu.mediaURL ? window.gContextMenu.mediaURL : window.gContextMenu.imageURL) : window.gContextMenu.bgImageURL, 'artwork')"/>
|
||||
</popup>
|
||||
|
||||
<vbox id="appcontent">
|
||||
|
@ -96,8 +97,8 @@
|
|||
<menuitem label="&zotero.items.menu.showInLibrary;" oncommand="ZoteroPane.selectItem(this.parentNode.getAttribute('itemID'), true)"/>
|
||||
<menuseparator/>
|
||||
<menuitem label="&zotero.items.menu.attach.note;" oncommand="ZoteroPane.newNote(false, this.parentNode.getAttribute('itemID'))"/>
|
||||
<menuitem label="&zotero.items.menu.attach.snapshot;" oncommand="ZoteroPane.addAttachmentFromPage(false, this.parentNode.getAttribute('itemID'));"/>
|
||||
<menuitem label="&zotero.items.menu.attach.link;" oncommand="ZoteroPane.addAttachmentFromPage(true, this.parentNode.getAttribute('itemID'));"/>
|
||||
<menuitem label="&zotero.items.menu.attach.snapshot;" oncommand="ZoteroPane.addAttachmentFromPage(false, parseInt(this.parentNode.getAttribute('itemID')))"/>
|
||||
<menuitem label="&zotero.items.menu.attach.link;" oncommand="ZoteroPane.addAttachmentFromPage(true, parseInt(this.parentNode.getAttribute('itemID')))"/>
|
||||
<menuseparator/>
|
||||
<menuitem label="&zotero.items.menu.duplicateItem;" oncommand="ZoteroPane.duplicateSelectedItem();"/>
|
||||
<menuitem oncommand="ZoteroPane.deleteSelectedItems();"/>
|
||||
|
@ -118,6 +119,7 @@
|
|||
<vbox flex="1">
|
||||
<hbox class="toolbar">
|
||||
<toolbarbutton id="zotero-tb-collection-add" tooltiptext="&zotero.toolbar.newCollection.label;" oncommand="ZoteroPane.newCollection()"/>
|
||||
<toolbarbutton id="zotero-tb-group-add" tooltiptext="&zotero.toolbar.newGroup;" oncommand="ZoteroPane.newGroup()"/>
|
||||
<spacer flex="1"/>
|
||||
<toolbarbutton id="zotero-tb-tag-selector" tooltiptext="&zotero.toolbar.tagSelector.label;" oncommand="ZoteroPane.toggleTagSelector()"/>
|
||||
<toolbarbutton id="zotero-tb-actions-menu" tooltiptext="&zotero.toolbar.actions.label;" type="menu">
|
||||
|
@ -154,7 +156,7 @@
|
|||
onmouseover="ZoteroPane.collectionsView.setHighlightedRows();"
|
||||
ondblclick="ZoteroPane.onDoubleClick(event, this);"
|
||||
onkeypress="ZoteroPane.handleKeyPress(event, this.id)"
|
||||
onselect="ZoteroPane.onCollectionSelected();" seltype="single"
|
||||
onselect="ZoteroPane.onCollectionSelected();" seltype="cell"
|
||||
ondraggesture="if (event.target.localName == 'treechildren') { ZoteroPane.startDrag(event, ZoteroPane.collectionsView); }"
|
||||
ondragenter="return ZoteroPane.dragEnter(event, ZoteroPane.collectionsView)"
|
||||
ondragover="return ZoteroPane.dragOver(event, ZoteroPane.collectionsView)"
|
||||
|
@ -192,10 +194,12 @@
|
|||
</menupopup>
|
||||
</toolbarbutton>
|
||||
<toolbarbutton id="zotero-tb-item-from-page" tooltiptext="&zotero.toolbar.newItemFromPage.label;" oncommand="ZoteroPane.addItemFromPage()"/>
|
||||
<toolbarbutton id="zotero-tb-lookup" tooltiptext="&zotero.toolbar.lookup.label;" oncommand="window.openDialog('chrome://zotero/content/lookup.xul', 'lookup', 'chrome,modal')"/>
|
||||
<toolbarbutton id="zotero-tb-lookup" tooltiptext="&zotero.toolbar.lookup.label;" oncommand="ZoteroPane.openLookupWindow()"/>
|
||||
<!--
|
||||
<toolbarseparator/>
|
||||
<toolbarbutton id="zotero-tb-link-page" tooltiptext="&zotero.toolbar.attachment.weblink;" oncommand="ZoteroPane.addAttachmentFromPage(true)"/>
|
||||
<toolbarbutton id="zotero-tb-snapshot-page" tooltiptext="&zotero.toolbar.attachment.snapshot;" oncommand="ZoteroPane.addAttachmentFromPage()"/>
|
||||
-->
|
||||
<toolbarbutton id="zotero-tb-note-add" tooltiptext="&zotero.toolbar.note.standalone;" oncommand="ZoteroPane.newNote(event.shiftKey);"/>
|
||||
<toolbarseparator/>
|
||||
<toolbarbutton id="zotero-tb-advanced-search" tooltiptext="&zotero.toolbar.advancedSearch;" oncommand="ZoteroPane.openAdvancedSearchWindow()"/>
|
||||
|
@ -406,7 +410,7 @@
|
|||
|
||||
<!-- Scrape Code -->
|
||||
<hbox id="urlbar-icons">
|
||||
<image src="chrome://zotero/skin/treeitem-book.png" id="zotero-status-image" onclick="Zotero_Browser.scrapeThisPage()" position="1" hidden="true"/>
|
||||
<image src="chrome://zotero/skin/treeitem-book.png" id="zotero-status-image" onclick="Zotero_Browser.scrapeThisPage(ZoteroPane.getSelectedLibraryID(), ZoteroPane.getSelectedCollection(true))" position="1" hidden="true"/>
|
||||
</hbox>
|
||||
|
||||
<statusbar id="status-bar">
|
||||
|
|
|
@ -329,8 +329,7 @@ function handleSyncReset(action) {
|
|||
|
||||
var appStartup = Components.classes["@mozilla.org/toolkit/app-startup;1"]
|
||||
.getService(Components.interfaces.nsIAppStartup);
|
||||
appStartup.quit(Components.interfaces.nsIAppStartup.eRestart);
|
||||
appStartup.quit(Components.interfaces.nsIAppStartup.eAttemptQuit);
|
||||
appStartup.quit(Components.interfaces.nsIAppStartup.eRestart | Components.interfaces.nsIAppStartup.eAttemptQuit);
|
||||
};
|
||||
|
||||
// TODO: better way of checking for an active session?
|
||||
|
|
|
@ -244,11 +244,10 @@ To add a new preference:
|
|||
<groupbox>
|
||||
<caption label="Storage Server"/>
|
||||
|
||||
<hbox>
|
||||
<checkbox label="Enable file syncing" preference="pref-storage-enabled"/>
|
||||
</hbox>
|
||||
|
||||
<separator class="thin"/>
|
||||
<label value="Please note: Attachment files in group libraries are not currently synced."/>
|
||||
|
||||
<separator/>
|
||||
|
||||
<grid id="storage-settings">
|
||||
<columns>
|
||||
|
@ -714,8 +713,8 @@ To add a new preference:
|
|||
|
||||
<!-- These mess up the prefwindow (more) if they come before the prefpanes
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=296418 -->
|
||||
<script src="chrome://zotero/content/include.js"/>
|
||||
<script src="chrome://zotero/content/charsetMenu.js"/>
|
||||
<script src="chrome://zotero/content/include.js"></script>
|
||||
<script src="chrome://zotero/content/charsetMenu.js"></script>
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
var observerService = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
|
||||
|
|
|
@ -53,7 +53,7 @@
|
|||
|
||||
<hbox flex="1">
|
||||
<tree id="zotero-collections-tree"
|
||||
style="width: 200px;" hidecolumnpicker="true" seltype="single"
|
||||
style="width: 200px;" hidecolumnpicker="true" seltype="cell"
|
||||
onselect="onCollectionSelected();">
|
||||
<treecols>
|
||||
<treecol
|
||||
|
|
|
@ -56,7 +56,11 @@ Zotero.Attachments = new function(){
|
|||
|
||||
try {
|
||||
// Create a new attachment
|
||||
var attachmentItem = new Zotero.Item(false, 'attachment');
|
||||
var attachmentItem = new Zotero.Item('attachment');
|
||||
if (sourceItemID) {
|
||||
var parentItem = Zotero.Items.get(sourceItemID);
|
||||
attachmentItem.libraryID = parentItem.libraryID;
|
||||
}
|
||||
attachmentItem.setField('title', title);
|
||||
attachmentItem.setSource(sourceItemID);
|
||||
attachmentItem.attachmentLinkMode = this.LINK_MODE_IMPORTED_FILE;
|
||||
|
@ -128,7 +132,11 @@ Zotero.Attachments = new function(){
|
|||
|
||||
try {
|
||||
// Create a new attachment
|
||||
var attachmentItem = new Zotero.Item(false, 'attachment');
|
||||
var attachmentItem = new Zotero.Item('attachment');
|
||||
if (sourceItemID) {
|
||||
var parentItem = Zotero.Items.get(sourceItemID);
|
||||
attachmentItem.libraryID = parentItem.libraryID;
|
||||
}
|
||||
attachmentItem.setField('title', title);
|
||||
attachmentItem.setField('url', url);
|
||||
attachmentItem.setSource(sourceItemID);
|
||||
|
@ -182,6 +190,13 @@ Zotero.Attachments = new function(){
|
|||
function importFromURL(url, sourceItemID, forceTitle, forceFileBaseName, parentCollectionIDs){
|
||||
Zotero.debug('Importing attachment from URL');
|
||||
|
||||
if (sourceItemID && parentCollectionIDs) {
|
||||
var msg = "parentCollectionIDs is ignored when sourceItemID is set in Zotero.Attachments.importFromURL()";
|
||||
Zotero.debug(msg, 2);
|
||||
Components.utils.reportError(msg);
|
||||
parentCollectionIDs = undefined;
|
||||
}
|
||||
|
||||
// Throw error on invalid URLs
|
||||
//
|
||||
// TODO: allow other schemes
|
||||
|
@ -264,7 +279,11 @@ Zotero.Attachments = new function(){
|
|||
|
||||
try {
|
||||
// Create a new attachment
|
||||
var attachmentItem = new Zotero.Item(false, 'attachment');
|
||||
var attachmentItem = new Zotero.Item('attachment');
|
||||
if (sourceItemID) {
|
||||
var parentItem = Zotero.Items.get(sourceItemID);
|
||||
attachmentItem.libraryID = parentItem.libraryID;
|
||||
}
|
||||
attachmentItem.setField('title', title);
|
||||
attachmentItem.setField('url', url);
|
||||
attachmentItem.setField('accessDate', "CURRENT_TIMESTAMP");
|
||||
|
@ -292,6 +311,7 @@ Zotero.Attachments = new function(){
|
|||
wbp.progressListener = new Zotero.WebProgressFinishListener(function(){
|
||||
try {
|
||||
var str = Zotero.File.getSample(file);
|
||||
|
||||
if (mimeType == 'application/pdf' &&
|
||||
Zotero.MIME.sniffForMIMEType(str) != 'application/pdf') {
|
||||
Zotero.debug("Downloaded PDF did not have MIME type "
|
||||
|
@ -432,6 +452,13 @@ Zotero.Attachments = new function(){
|
|||
function linkFromDocument(document, sourceItemID, parentCollectionIDs){
|
||||
Zotero.debug('Linking attachment from document');
|
||||
|
||||
if (sourceItemID && parentCollectionIDs) {
|
||||
var msg = "parentCollectionIDs is ignored when sourceItemID is set in Zotero.Attachments.linkFromDocument()";
|
||||
Zotero.debug(msg, 2);
|
||||
Components.utils.reportError(msg);
|
||||
parentCollectionIDs = undefined;
|
||||
}
|
||||
|
||||
var url = document.location.href;
|
||||
var title = document.title; // TODO: don't use Mozilla-generated title for images, etc.
|
||||
var mimeType = document.contentType;
|
||||
|
@ -475,6 +502,13 @@ Zotero.Attachments = new function(){
|
|||
function importFromDocument(document, sourceItemID, forceTitle, parentCollectionIDs, callback) {
|
||||
Zotero.debug('Importing attachment from document');
|
||||
|
||||
if (sourceItemID && parentCollectionIDs) {
|
||||
var msg = "parentCollectionIDs is ignored when sourceItemID is set in Zotero.Attachments.importFromDocument()";
|
||||
Zotero.debug(msg, 2);
|
||||
Components.utils.reportError(msg);
|
||||
parentCollectionIDs = undefined;
|
||||
}
|
||||
|
||||
var url = document.location.href;
|
||||
var title = forceTitle ? forceTitle : document.title;
|
||||
var mimeType = document.contentType;
|
||||
|
@ -496,7 +530,11 @@ Zotero.Attachments = new function(){
|
|||
|
||||
try {
|
||||
// Create a new attachment
|
||||
var attachmentItem = new Zotero.Item(false, 'attachment');
|
||||
var attachmentItem = new Zotero.Item('attachment');
|
||||
if (sourceItemID) {
|
||||
var parentItem = Zotero.Items.get(sourceItemID);
|
||||
attachmentItem.libraryID = parentItem.libraryID;
|
||||
}
|
||||
attachmentItem.setField('title', title);
|
||||
attachmentItem.setField('url', url);
|
||||
attachmentItem.setField('accessDate', "CURRENT_TIMESTAMP");
|
||||
|
@ -679,7 +717,7 @@ Zotero.Attachments = new function(){
|
|||
|
||||
try {
|
||||
// Create a new attachment
|
||||
var attachmentItem = new Zotero.Item(false, 'attachment');
|
||||
var attachmentItem = new Zotero.Item('attachment');
|
||||
attachmentItem.setField('title', title);
|
||||
attachmentItem.setField('url', url);
|
||||
attachmentItem.setField('accessDate', "CURRENT_TIMESTAMP");
|
||||
|
@ -1118,7 +1156,14 @@ Zotero.Attachments = new function(){
|
|||
function _addToDB(file, url, title, linkMode, mimeType, charsetID, sourceItemID) {
|
||||
Zotero.DB.beginTransaction();
|
||||
|
||||
var attachmentItem = new Zotero.Item(false, 'attachment');
|
||||
var attachmentItem = new Zotero.Item('attachment');
|
||||
if (sourceItemID) {
|
||||
var parentItem = Zotero.Items.get(sourceItemID);
|
||||
if (parentItem.libraryID && linkMode == Zotero.Attachments.LINK_MODE_LINKED_FILE) {
|
||||
throw ("Cannot save linked file in non-local library");
|
||||
}
|
||||
attachmentItem.libraryID = parentItem.libraryID;
|
||||
}
|
||||
attachmentItem.setField('title', title);
|
||||
if (linkMode == self.LINK_MODE_IMPORTED_URL
|
||||
|| linkMode == self.LINK_MODE_LINKED_URL) {
|
||||
|
|
|
@ -36,7 +36,7 @@ Zotero.CollectionTreeView = function()
|
|||
this._treebox = null;
|
||||
this.itemToSelect = null;
|
||||
this._highlightedRows = {};
|
||||
this._unregisterID = Zotero.Notifier.registerObserver(this, ['collection', 'search', 'share']);
|
||||
this._unregisterID = Zotero.Notifier.registerObserver(this, ['collection', 'search', 'share', 'group']);
|
||||
this.showDuplicates = false;
|
||||
}
|
||||
|
||||
|
@ -72,7 +72,7 @@ Zotero.CollectionTreeView.prototype.setTree = function(treebox)
|
|||
|
||||
// Select the last-viewed collection
|
||||
var lastViewedFolder = Zotero.Prefs.get('lastViewedFolder');
|
||||
var matches = lastViewedFolder.match(/^(?:(C|S)([0-9]+)|L)$/);
|
||||
var matches = lastViewedFolder.match(/^(?:(C|S|G)([0-9]+)|L)$/);
|
||||
var select = 0;
|
||||
if (matches) {
|
||||
if (matches[1] == 'C') {
|
||||
|
@ -131,7 +131,12 @@ Zotero.CollectionTreeView.prototype.setTree = function(treebox)
|
|||
else if (matches[1] == 'S' && this._searchRowMap[matches[2]]) {
|
||||
select = this._searchRowMap[matches[2]];
|
||||
}
|
||||
else if (matches[1] == 'G' && this._groupRowMap[matches[2]]) {
|
||||
select = this._groupRowMap[matches[2]];
|
||||
}
|
||||
}
|
||||
|
||||
this.selection.currentColumn = this._treebox.columns.getFirstColumn();
|
||||
this.selection.select(select);
|
||||
}
|
||||
|
||||
|
@ -145,32 +150,67 @@ Zotero.CollectionTreeView.prototype.refresh = function()
|
|||
var oldCount = this.rowCount;
|
||||
this._dataItems = [];
|
||||
this.rowCount = 0;
|
||||
this._showItem(new Zotero.ItemGroup('library',null),0,1);
|
||||
this._showItem(new Zotero.ItemGroup('library', { id: null, libraryID: null }), 0, 1, 1); // itemgroup ref, level, beforeRow, startOpen
|
||||
|
||||
var newRows = Zotero.getCollections();
|
||||
for(var i = 0; i < newRows.length; i++)
|
||||
this._showItem(new Zotero.ItemGroup('collection',newRows[i]), 0, this._dataItems.length); //itemgroup ref, level, beforeRow
|
||||
var collections = Zotero.getCollections();
|
||||
for (var i=0; i<collections.length; i++) {
|
||||
// Skip group collections
|
||||
if (collections[i].libraryID) {
|
||||
continue;
|
||||
}
|
||||
this._showItem(new Zotero.ItemGroup('collection', collections[i]), 1);
|
||||
}
|
||||
|
||||
var savedSearches = Zotero.Searches.getAll();
|
||||
if (savedSearches) {
|
||||
for (var i=0; i<savedSearches.length; i++) {
|
||||
this._showItem(new Zotero.ItemGroup('search',savedSearches[i]), 0, this._dataItems.length); //itemgroup ref, level, beforeRow
|
||||
}
|
||||
}
|
||||
|
||||
var shares = Zotero.Zeroconf.instances;
|
||||
if (shares) {
|
||||
for each(var share in shares) {
|
||||
this._showItem(new Zotero.ItemGroup('share', share), 0, this._dataItems.length); //itemgroup ref, level, beforeRow
|
||||
this._showItem(new Zotero.ItemGroup('search', savedSearches[i]), 1);
|
||||
}
|
||||
}
|
||||
|
||||
var deletedItems = Zotero.Items.getDeleted();
|
||||
if (deletedItems || Zotero.Prefs.get("showTrashWhenEmpty")) {
|
||||
this._showItem(new Zotero.ItemGroup('trash', null), 0, this._dataItems.length);
|
||||
this._showItem(new Zotero.ItemGroup('trash', false), 1);
|
||||
}
|
||||
this.trashNotEmpty = !!deletedItems;
|
||||
|
||||
var groups = Zotero.Groups.getAll();
|
||||
if (groups.length) {
|
||||
this._showItem(new Zotero.ItemGroup('separator', false));
|
||||
var self = this;
|
||||
var header = {
|
||||
id: "group-libraries-header",
|
||||
label: "Group Libraries", // TODO: localize
|
||||
expand: function (groups) {
|
||||
if (!groups) {
|
||||
var groups = Zotero.Groups.getAll();
|
||||
}
|
||||
|
||||
for (var i=0; i<groups.length; i++) {
|
||||
var startOpen = groups[i].hasCollections();
|
||||
|
||||
self._showItem(new Zotero.ItemGroup('group', groups[i]), 1, null, startOpen);
|
||||
|
||||
// Add group collections
|
||||
var collections = groups[i].getCollections();
|
||||
for (var j=0; j<collections.length; j++) {
|
||||
self._showItem(new Zotero.ItemGroup('collection', collections[j]), 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
this._showItem(new Zotero.ItemGroup('header', header), null, null, true);
|
||||
header.expand(groups);
|
||||
}
|
||||
|
||||
var shares = Zotero.Zeroconf.instances;
|
||||
if (shares.length) {
|
||||
this._showItem(new Zotero.ItemGroup('separator', false));
|
||||
for each(var share in shares) {
|
||||
this._showItem(new Zotero.ItemGroup('share', share));
|
||||
}
|
||||
}
|
||||
|
||||
this._refreshHashMap();
|
||||
|
||||
// Update the treebox's row count
|
||||
|
@ -248,6 +288,12 @@ Zotero.CollectionTreeView.prototype.notify = function(action, type, ids)
|
|||
rows.push(this._searchRowMap[ids[i]]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'group':
|
||||
if (this._groupRowMap[ids[i]] != null) {
|
||||
rows.push(this._groupRowMap[ids[i]]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -303,13 +349,27 @@ Zotero.CollectionTreeView.prototype.notify = function(action, type, ids)
|
|||
}
|
||||
|
||||
this.reload();
|
||||
if (Zotero.Sync.Server.syncInProgress) {
|
||||
this.rememberSelection(savedSelection);
|
||||
break;
|
||||
}
|
||||
this.selection.select(this._collectionRowMap[collectionID]);
|
||||
break;
|
||||
|
||||
case 'search':
|
||||
this.reload();
|
||||
if (Zotero.Sync.Server.syncInProgress) {
|
||||
this.rememberSelection(savedSelection);
|
||||
break;
|
||||
}
|
||||
this.selection.select(this._searchRowMap[ids]);
|
||||
break;
|
||||
|
||||
case 'group':
|
||||
this.reload();
|
||||
// Groups can only be created during sync
|
||||
this.rememberSelection(savedSelection);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -318,7 +378,7 @@ Zotero.CollectionTreeView.prototype.notify = function(action, type, ids)
|
|||
|
||||
|
||||
/*
|
||||
* Set the rows that should be highlighted -- actually highlighting is done
|
||||
* Set the rows that should be highlighted -- actual highlighting is done
|
||||
* by getRowProperties based on the array set here
|
||||
*/
|
||||
Zotero.CollectionTreeView.prototype.setHighlightedRows = function (ids) {
|
||||
|
@ -376,16 +436,36 @@ Zotero.CollectionTreeView.prototype.getCellText = function(row, column)
|
|||
|
||||
Zotero.CollectionTreeView.prototype.getImageSrc = function(row, col)
|
||||
{
|
||||
var collectionType = this._getItemAtRow(row).type;
|
||||
if (collectionType == 'trash' && this.trashNotEmpty) {
|
||||
collectionType += "-full";
|
||||
var source = this._getItemAtRow(row);
|
||||
var collectionType = source.type;
|
||||
switch (collectionType) {
|
||||
case 'trash':
|
||||
if (this.trashNotEmpty) {
|
||||
collectionType += '-full';
|
||||
}
|
||||
break;
|
||||
|
||||
case 'collection':
|
||||
// TODO: group collection
|
||||
break;
|
||||
|
||||
case 'header':
|
||||
if (source.ref.id == 'group-libraries-header') {
|
||||
collectionType = 'groups';
|
||||
}
|
||||
break;
|
||||
|
||||
case 'group':
|
||||
collectionType = 'library';
|
||||
break;
|
||||
}
|
||||
return "chrome://zotero/skin/treesource-" + collectionType + ".png";
|
||||
}
|
||||
|
||||
Zotero.CollectionTreeView.prototype.isContainer = function(row)
|
||||
{
|
||||
return this._getItemAtRow(row).isCollection();
|
||||
var itemGroup = this._getItemAtRow(row);
|
||||
return itemGroup.isLibrary(true) || itemGroup.isCollection() || itemGroup.isHeader();
|
||||
}
|
||||
|
||||
Zotero.CollectionTreeView.prototype.isContainerOpen = function(row)
|
||||
|
@ -399,6 +479,15 @@ Zotero.CollectionTreeView.prototype.isContainerOpen = function(row)
|
|||
Zotero.CollectionTreeView.prototype.isContainerEmpty = function(row)
|
||||
{
|
||||
var itemGroup = this._getItemAtRow(row);
|
||||
if (itemGroup.isLibrary()) {
|
||||
return false;
|
||||
}
|
||||
if (itemGroup.isHeader()) {
|
||||
return false;
|
||||
}
|
||||
if (itemGroup.isGroup()) {
|
||||
return !itemGroup.ref.hasCollections();
|
||||
}
|
||||
if (itemGroup.isCollection()) {
|
||||
return !itemGroup.ref.hasChildCollections();
|
||||
}
|
||||
|
@ -440,22 +529,30 @@ Zotero.CollectionTreeView.prototype.toggleOpenState = function(row)
|
|||
var thisLevel = this.getLevel(row);
|
||||
|
||||
this._treebox.beginUpdateBatch();
|
||||
if(this.isContainerOpen(row))
|
||||
{
|
||||
if (this.isContainerOpen(row)) {
|
||||
while((row + 1 < this._dataItems.length) && (this.getLevel(row + 1) > thisLevel))
|
||||
{
|
||||
this._hideItem(row+1);
|
||||
count--; //count is negative when closing a container because we are removing rows
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var newRows = Zotero.getCollections(this._getItemAtRow(row).ref.id); //Get children
|
||||
else {
|
||||
var itemGroup = this._getItemAtRow(row);
|
||||
|
||||
for(var i = 0; i < newRows.length; i++)
|
||||
{
|
||||
count++;
|
||||
this._showItem(new Zotero.ItemGroup('collection',newRows[i]), thisLevel+1, row+i+1); //insert new row
|
||||
if (itemGroup.type == 'header') {
|
||||
itemGroup.ref.expand();
|
||||
}
|
||||
else {
|
||||
if (itemGroup.isGroup()) {
|
||||
var collections = itemGroup.ref.getCollections(); // Get child collections
|
||||
}
|
||||
else {
|
||||
var collections = Zotero.getCollections(itemGroup.ref.id); // Get child collections
|
||||
}
|
||||
for (var i=0; i<collections.length; i++) {
|
||||
count++;
|
||||
this._showItem(new Zotero.ItemGroup('collection', collections[i]), thisLevel+1, row+i+1); //insert new row
|
||||
}
|
||||
}
|
||||
}
|
||||
this._dataItems[row][1] = !this._dataItems[row][1]; //toggle container open value
|
||||
|
@ -467,6 +564,21 @@ Zotero.CollectionTreeView.prototype.toggleOpenState = function(row)
|
|||
}
|
||||
|
||||
|
||||
Zotero.CollectionTreeView.prototype.isSelectable = function (row, col) {
|
||||
var itemGroup = this._getItemAtRow(row);
|
||||
switch (itemGroup.type) {
|
||||
case 'separator':
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Zotero.CollectionTreeView.prototype.__defineGetter__('editable', function () {
|
||||
return this._getItemAtRow(this.selection.currentIndex).isEditable();
|
||||
});
|
||||
|
||||
|
||||
Zotero.CollectionTreeView.prototype.expandAllRows = function(treebox) {
|
||||
var view = treebox.view;
|
||||
treebox.beginUpdateBatch();
|
||||
|
@ -522,6 +634,39 @@ Zotero.CollectionTreeView.prototype.collapseAllRows = function(treebox) {
|
|||
/// Additional functions for managing data in the tree
|
||||
///
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* @param {Integer|null} libraryID Library to select, or null for local library
|
||||
*/
|
||||
Zotero.CollectionTreeView.prototype.selectLibrary = function (libraryID) {
|
||||
if (Zotero.Sync.Server.syncInProgress) {
|
||||
Zotero.debug("Sync in progress -- not changing library selection");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Select local library
|
||||
if (!libraryID) {
|
||||
this.selection.select(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Already selected
|
||||
var itemGroup = this._getItemAtRow(this.selection.currentIndex);
|
||||
if (itemGroup.ref.libraryID == libraryID) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Find library
|
||||
for (var i=0, rows=this.rowCount; i<rows.length; i++) {
|
||||
var itemGroup = this._getItemAtRow(this.selection.currentIndex);
|
||||
if (itemGroup.ref && itemGroup.ref.libraryID == libraryID) {
|
||||
this.selection.select(i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Delete the selection
|
||||
|
@ -579,9 +724,21 @@ Zotero.CollectionTreeView.prototype.deleteSelection = function()
|
|||
* level: the indent level of the row
|
||||
* beforeRow: row index to insert new row before
|
||||
*/
|
||||
Zotero.CollectionTreeView.prototype._showItem = function(itemGroup, level, beforeRow)
|
||||
Zotero.CollectionTreeView.prototype._showItem = function(itemGroup, level, beforeRow, startOpen)
|
||||
{
|
||||
this._dataItems.splice(beforeRow, 0, [itemGroup, false, level]);
|
||||
if (!level) {
|
||||
level = 0;
|
||||
}
|
||||
|
||||
if (!beforeRow) {
|
||||
beforeRow = this._dataItems.length;
|
||||
}
|
||||
|
||||
if (!startOpen) {
|
||||
startOpen = false;
|
||||
}
|
||||
|
||||
this._dataItems.splice(beforeRow, 0, [itemGroup, startOpen, level]);
|
||||
this.rowCount++;
|
||||
}
|
||||
|
||||
|
@ -609,18 +766,22 @@ Zotero.CollectionTreeView.prototype.saveSelection = function()
|
|||
{
|
||||
for (var i=0, len=this.rowCount; i<len; i++) {
|
||||
if (this.selection.isSelected(i)) {
|
||||
if (this._getItemAtRow(i).isLibrary()) {
|
||||
var itemGroup = this._getItemAtRow(i);
|
||||
if (itemGroup.isLibrary()) {
|
||||
return 'L';
|
||||
}
|
||||
else if (this._getItemAtRow(i).isCollection()) {
|
||||
return 'C' + this._getItemAtRow(i).ref.id;
|
||||
else if (itemGroup.isCollection()) {
|
||||
return 'C' + itemGroup.ref.id;
|
||||
}
|
||||
else if (this._getItemAtRow(i).isSearch()) {
|
||||
return 'S' + this._getItemAtRow(i).ref.id;
|
||||
else if (itemGroup.isSearch()) {
|
||||
return 'S' + itemGroup.ref.id;
|
||||
}
|
||||
else if (this._getItemAtRow(i).isTrash()) {
|
||||
else if (itemGroup.isTrash()) {
|
||||
return 'T';
|
||||
}
|
||||
else if (itemGroup.isGroup()) {
|
||||
return 'G' + itemGroup.ref.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
@ -658,6 +819,7 @@ Zotero.CollectionTreeView.prototype.rememberSelection = function(selection)
|
|||
}
|
||||
break;
|
||||
|
||||
// Trash
|
||||
case 'T':
|
||||
if (this._getItemAtRow(this.rowCount-1).isTrash()){
|
||||
this.selection.select(this.rowCount-1);
|
||||
|
@ -666,6 +828,13 @@ Zotero.CollectionTreeView.prototype.rememberSelection = function(selection)
|
|||
this.selection.select(0);
|
||||
}
|
||||
break;
|
||||
|
||||
// Group
|
||||
case 'G':
|
||||
if (this._groupRowMap[id] != undefined) {
|
||||
this.selection.select(this._groupRowMap[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -679,12 +848,17 @@ Zotero.CollectionTreeView.prototype._refreshHashMap = function()
|
|||
{
|
||||
this._collectionRowMap = [];
|
||||
this._searchRowMap = [];
|
||||
this._groupRowMap = [];
|
||||
for(var i=0; i < this.rowCount; i++){
|
||||
if (this.isCollection(i)){
|
||||
this._collectionRowMap[this._getItemAtRow(i).ref.id] = i;
|
||||
var itemGroup = this._getItemAtRow(i);
|
||||
if (itemGroup.isCollection(i)) {
|
||||
this._collectionRowMap[itemGroup.ref.id] = i;
|
||||
}
|
||||
else if (this.isSearch(i)){
|
||||
this._searchRowMap[this._getItemAtRow(i).ref.id] = i;
|
||||
else if (itemGroup.isSearch(i)) {
|
||||
this._searchRowMap[itemGroup.ref.id] = i;
|
||||
}
|
||||
else if (itemGroup.isGroup(i)) {
|
||||
this._groupRowMap[itemGroup.ref.id] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -730,7 +904,11 @@ Zotero.CollectionTreeCommandController.prototype.onEvent = function(evt)
|
|||
* Start a drag using nsDragAndDrop.js or HTML 5 Drag and Drop
|
||||
*/
|
||||
Zotero.CollectionTreeView.prototype.onDragStart = function(event, transferData, action) {
|
||||
var collectionID = this._getItemAtRow(this.selection.currentIndex).ref.id;
|
||||
var itemGroup = this._getItemAtRow(this.selection.currentIndex);
|
||||
if (!itemGroup.isCollection()) {
|
||||
return false;
|
||||
}
|
||||
var collectionID = itemGroup.ref.id;
|
||||
|
||||
// Use nsDragAndDrop.js interface for Firefox 2 and Firefox 3.0
|
||||
var oldMethod = Zotero.isFx2 || Zotero.isFx30;
|
||||
|
@ -789,23 +967,57 @@ Zotero.CollectionTreeView.prototype.canDrop = function(row, orient, dragData)
|
|||
}
|
||||
else if(orient == 0) //directly on a row...
|
||||
{
|
||||
var rowCollection = this._getItemAtRow(row).ref; //the collection we are dragging over
|
||||
var itemGroup = this._getItemAtRow(row); //the collection we are dragging over
|
||||
|
||||
if (!itemGroup.isEditable()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dataType == 'zotero/item') {
|
||||
var ids = data;
|
||||
for each(var id in ids)
|
||||
{
|
||||
var item = Zotero.Items.get(id);
|
||||
// Can only drag top-level items into collections
|
||||
if (item.isRegularItem() || !item.getSource())
|
||||
{
|
||||
// Make sure there's at least one item that's not already
|
||||
// in this collection
|
||||
if (!rowCollection.hasItem(id))
|
||||
{
|
||||
return true;
|
||||
var items = Zotero.Items.get(ids);
|
||||
for each(var item in items) {
|
||||
// Can only drag top-level items
|
||||
if (!(item.isRegularItem() || !item.getSource())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO: for now, only allow regular items to be dragged to groups
|
||||
if (itemGroup.isWithinGroup() && itemGroup.ref.libraryID != item.libraryID
|
||||
&& !item.isRegularItem()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: for now, skip items that are already linked
|
||||
if (itemGroup.isWithinGroup() && itemGroup.ref.libraryID != item.libraryID) {
|
||||
if (item.getLinkedItem(itemGroup.ref.libraryID)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (itemGroup.isGroup()) {
|
||||
// Don't allow drag onto library of same group
|
||||
if (itemGroup.ref.libraryID == item.libraryID) {
|
||||
continue;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Allow drag of group items to library
|
||||
if (item.libraryID && (itemGroup.isLibrary()
|
||||
|| itemGroup.isCollection() && !itemGroup.isWithinGroup())) {
|
||||
// TODO: for now, skip items that are already linked
|
||||
if (item.getLinkedItem()) {
|
||||
continue;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Make sure there's at least one item that's not already
|
||||
// in this collection
|
||||
if (itemGroup.isCollection() && !itemGroup.ref.hasItem(item.id)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -819,9 +1031,8 @@ Zotero.CollectionTreeView.prototype.canDrop = function(row, orient, dragData)
|
|||
}
|
||||
return false;
|
||||
}
|
||||
else if (dataType == 'text/x-moz-url'
|
||||
|| dataType == 'application/x-moz-file') {
|
||||
if (this._getItemAtRow(row).isSearch()) {
|
||||
else if (dataType == 'text/x-moz-url' || dataType == 'application/x-moz-file') {
|
||||
if (itemGroup.isSearch()) {
|
||||
return false;
|
||||
}
|
||||
// Don't allow folder drag
|
||||
|
@ -830,10 +1041,30 @@ Zotero.CollectionTreeView.prototype.canDrop = function(row, orient, dragData)
|
|||
}
|
||||
return true;
|
||||
}
|
||||
else if (dataType == 'zotero/collection'
|
||||
// Collections cannot be dropped on themselves, nor in their children
|
||||
&& data[0] != rowCollection.id
|
||||
&& !Zotero.Collections.get(data[0]).hasDescendent('collection', rowCollection.id)) {
|
||||
else if (dataType == 'zotero/collection') {
|
||||
// Collections cannot be dropped on themselves
|
||||
if (data[0] == itemGroup.ref.id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Nor in their children
|
||||
if (Zotero.Collections.get(data[0]).hasDescendent('collection', itemGroup.ref.id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var col = Zotero.Collections.get(data[0]);
|
||||
|
||||
// Nor, at least for now, on another group
|
||||
if (itemGroup.isWithinGroup()) {
|
||||
if (itemGroup.ref.libraryID != col.libraryID) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Nor from a group library to the local library
|
||||
else if (col.libraryID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -853,12 +1084,14 @@ Zotero.CollectionTreeView.prototype.drop = function(row, orient)
|
|||
|
||||
var dataType = dragData.dataType;
|
||||
var data = dragData.data;
|
||||
var itemGroup = this._getItemAtRow(row);
|
||||
|
||||
if(dataType == 'zotero/collection')
|
||||
{
|
||||
var targetCollectionID;
|
||||
if(this._getItemAtRow(row).isCollection())
|
||||
targetCollectionID = this._getItemAtRow(row).ref.id;
|
||||
if (itemGroup.isCollection()) {
|
||||
targetCollectionID = itemGroup.ref.id;
|
||||
}
|
||||
var droppedCollection = Zotero.Collections.get(data[0]);
|
||||
droppedCollection.parent = targetCollectionID;
|
||||
droppedCollection.save();
|
||||
|
@ -869,18 +1102,150 @@ Zotero.CollectionTreeView.prototype.drop = function(row, orient)
|
|||
return;
|
||||
}
|
||||
|
||||
var toAdd = [];
|
||||
for (var i=0; i<ids.length; i++) {
|
||||
var item = Zotero.Items.get(ids[i]);
|
||||
// Only accept top-level items
|
||||
if (item.isRegularItem() || !item.getSource()) {
|
||||
toAdd.push(ids[i]);
|
||||
if (itemGroup.isWithinGroup()) {
|
||||
var targetLibraryID = itemGroup.ref.libraryID;
|
||||
}
|
||||
else {
|
||||
var targetLibraryID = null;
|
||||
}
|
||||
|
||||
Zotero.DB.beginTransaction();
|
||||
|
||||
var items = Zotero.Items.get(ids);
|
||||
if (!items) {
|
||||
return;
|
||||
}
|
||||
|
||||
var newItems = [];
|
||||
var newIDs = [];
|
||||
// DEBUG: support items coming from different sources?
|
||||
if (items[0].libraryID == targetLibraryID) {
|
||||
var sameLibrary = true;
|
||||
}
|
||||
else {
|
||||
var sameLibrary = false;
|
||||
}
|
||||
|
||||
for each(var item in items) {
|
||||
if (!(item.isRegularItem() || !item.getSource())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sameLibrary) {
|
||||
newIDs.push(item.id);
|
||||
}
|
||||
else {
|
||||
newItems.push(item);
|
||||
}
|
||||
}
|
||||
|
||||
if (toAdd.length > 0) {
|
||||
this._getItemAtRow(row).ref.addItems(toAdd);
|
||||
if (!sameLibrary) {
|
||||
var toReconcile = [];
|
||||
|
||||
for each(var item in newItems) {
|
||||
// Check if there's already a copy of this item in the library
|
||||
var linkedItem = item.getLinkedItem(targetLibraryID);
|
||||
if (linkedItem) {
|
||||
Zotero.debug("Linked item already exists -- skipping");
|
||||
continue;
|
||||
|
||||
/*
|
||||
// TODO: support tags, related, attachments, etc.
|
||||
|
||||
// Overlay source item fields on unsaved clone of linked item
|
||||
var newItem = item.clone(false, linkedItem.clone(true));
|
||||
newItem.setField('dateAdded', item.dateAdded);
|
||||
newItem.setField('dateModified', item.dateModified);
|
||||
|
||||
var diff = newItem.diff(linkedItem, false, ["dateAdded", "dateModified"]);
|
||||
if (!diff) {
|
||||
// Check if creators changed
|
||||
var creatorsChanged = false;
|
||||
|
||||
var creators = item.getCreators();
|
||||
var linkedCreators = linkedItem.getCreators();
|
||||
if (creators.length != linkedCreators.length) {
|
||||
Zotero.debug('Creators have changed');
|
||||
creatorsChanged = true;
|
||||
}
|
||||
else {
|
||||
for (var i=0; i<creators.length; i++) {
|
||||
if (!creators[i].ref.equals(linkedCreators[i].ref)) {
|
||||
Zotero.debug('changed');
|
||||
creatorsChanged = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!creatorsChanged) {
|
||||
Zotero.debug("Linked item hasn't changed -- skipping conflict resolution");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
toReconcile.push([newItem, linkedItem]);
|
||||
continue;
|
||||
*/
|
||||
}
|
||||
|
||||
// Create new unsaved clone item in target library
|
||||
var newItem = new Zotero.Item(item.itemTypeID);
|
||||
newItem.libraryID = targetLibraryID;
|
||||
// DEBUG: save here because clone() doesn't currently work on unsaved tagged items
|
||||
var id = newItem.save();
|
||||
var newItem = Zotero.Items.get(id);
|
||||
item.clone(false, newItem);
|
||||
newItem.save();
|
||||
//var id = newItem.save();
|
||||
//var newItem = Zotero.Items.get(id);
|
||||
|
||||
// Record link
|
||||
item.addLinkedItem(newItem);
|
||||
newIDs.push(id);
|
||||
}
|
||||
|
||||
if (toReconcile.length) {
|
||||
var sourceName = items[0].libraryID ? Zotero.Libraries.getName(items[0].libraryID)
|
||||
: Zotero.getString('pane.collections.library');
|
||||
var targetName = targetLibraryID ? Zotero.Libraries.getName(libraryID)
|
||||
: Zotero.getString('pane.collections.library');
|
||||
|
||||
var io = {
|
||||
dataIn: {
|
||||
type: "item",
|
||||
captions: [
|
||||
// TODO: localize
|
||||
sourceName,
|
||||
targetName,
|
||||
"Merged Item"
|
||||
],
|
||||
objects: toReconcile
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
if (type == 'item') {
|
||||
if (!Zotero.Utilities.prototype.isEmpty(changedCreators)) {
|
||||
io.dataIn.changedCreators = changedCreators;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
|
||||
.getService(Components.interfaces.nsIWindowMediator);
|
||||
var lastWin = wm.getMostRecentWindow("navigator:browser");
|
||||
lastWin.openDialog('chrome://zotero/content/merge.xul', '', 'chrome,modal,centerscreen', io);
|
||||
|
||||
for each(var obj in io.dataOut) {
|
||||
obj.ref.save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (newIDs.length && itemGroup.isCollection()) {
|
||||
itemGroup.ref.addItems(newIDs);
|
||||
}
|
||||
|
||||
Zotero.DB.commitTransaction();
|
||||
}
|
||||
else if (dataType == 'zotero/item-xml') {
|
||||
Zotero.DB.beginTransaction();
|
||||
|
@ -901,8 +1266,16 @@ Zotero.CollectionTreeView.prototype.drop = function(row, orient)
|
|||
return;
|
||||
}
|
||||
else if (dataType == 'text/x-moz-url' || dataType == 'application/x-moz-file') {
|
||||
if (this._getItemAtRow(row).isCollection()) {
|
||||
var parentCollectionID = this._getItemAtRow(row).ref.id;
|
||||
// FIXME: temporarily disable dragging in of files
|
||||
if (dataType == 'application/x-moz-file' && itemGroup.isWithinGroup()) {
|
||||
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
|
||||
.getService(Components.interfaces.nsIPromptService);
|
||||
ps.alert(null, "", "Files cannot currently be added to group libraries.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (itemGroup.isCollection()) {
|
||||
var parentCollectionID = itemGroup.ref.id;
|
||||
}
|
||||
else {
|
||||
var parentCollectionID = false;
|
||||
|
@ -972,7 +1345,7 @@ Zotero.CollectionTreeView.prototype.drop = function(row, orient)
|
|||
* Called by HTML 5 Drag and Drop when dragging over the tree
|
||||
*/
|
||||
Zotero.CollectionTreeView.prototype.onDragEnter = function (event) {
|
||||
Zotero.debug("Storing current drag data");
|
||||
//Zotero.debug("Storing current drag data");
|
||||
Zotero.DragDrop.currentDataTransfer = event.dataTransfer;
|
||||
}
|
||||
|
||||
|
@ -993,7 +1366,7 @@ Zotero.CollectionTreeView.prototype.onDrop = function (event, dropdata, session)
|
|||
}
|
||||
|
||||
Zotero.CollectionTreeView.prototype.onDragExit = function (event) {
|
||||
Zotero.debug("Clearing drag data");
|
||||
//Zotero.debug("Clearing drag data");
|
||||
Zotero.DragDrop.currentDataTransfer = null;
|
||||
}
|
||||
|
||||
|
@ -1007,7 +1380,6 @@ Zotero.CollectionTreeView.prototype.onDragExit = function (event) {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Zotero.CollectionTreeView.prototype.isSorted = function() { return false; }
|
||||
Zotero.CollectionTreeView.prototype.isSeparator = function(row) { return false; }
|
||||
Zotero.CollectionTreeView.prototype.isEditable = function(row, idx) { return false; }
|
||||
|
||||
/* Set 'highlighted' property on rows set by setHighlightedRows */
|
||||
|
@ -1021,6 +1393,10 @@ Zotero.CollectionTreeView.prototype.getRowProperties = function(row, props) {
|
|||
|
||||
Zotero.CollectionTreeView.prototype.getColumnProperties = function(col, prop) { }
|
||||
Zotero.CollectionTreeView.prototype.getCellProperties = function(row, col, prop) { }
|
||||
Zotero.CollectionTreeView.prototype.isSeparator = function(index) {
|
||||
var source = this._getItemAtRow(index);
|
||||
return source.type == 'separator';
|
||||
}
|
||||
Zotero.CollectionTreeView.prototype.performAction = function(action) { }
|
||||
Zotero.CollectionTreeView.prototype.performActionOnCell = function(action, row, col) { }
|
||||
Zotero.CollectionTreeView.prototype.getProgressMode = function(row, col) { }
|
||||
|
@ -1039,8 +1415,11 @@ Zotero.ItemGroup = function(type, ref)
|
|||
this.ref = ref;
|
||||
}
|
||||
|
||||
Zotero.ItemGroup.prototype.isLibrary = function()
|
||||
Zotero.ItemGroup.prototype.isLibrary = function(includeGlobal)
|
||||
{
|
||||
if (includeGlobal) {
|
||||
return this.type == 'library' || this.type == 'group';
|
||||
}
|
||||
return this.type == 'library';
|
||||
}
|
||||
|
||||
|
@ -1064,37 +1443,100 @@ Zotero.ItemGroup.prototype.isTrash = function()
|
|||
return this.type == 'trash';
|
||||
}
|
||||
|
||||
Zotero.ItemGroup.prototype.isGroup = function() {
|
||||
return this.type == 'group';
|
||||
}
|
||||
|
||||
Zotero.ItemGroup.prototype.isHeader = function () {
|
||||
return this.type == 'header';
|
||||
}
|
||||
|
||||
Zotero.ItemGroup.prototype.isSeparator = function () {
|
||||
return this.type == 'separator';
|
||||
}
|
||||
|
||||
|
||||
// Special
|
||||
Zotero.ItemGroup.prototype.isWithinGroup = function () {
|
||||
return this.ref && !!this.ref.libraryID;
|
||||
}
|
||||
|
||||
Zotero.ItemGroup.prototype.isEditable = function () {
|
||||
if (this.isTrash() || this.isShare()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.isWithinGroup()) {
|
||||
return true;
|
||||
}
|
||||
var libraryID = this.ref.libraryID;
|
||||
if (this.isGroup()) {
|
||||
return this.ref.editable;
|
||||
}
|
||||
if (this.isCollection()) {
|
||||
var type = Zotero.Libraries.getType(libraryID);
|
||||
if (type == 'group') {
|
||||
var groupID = Zotero.Groups.getGroupIDFromLibraryID(libraryID);
|
||||
var group = Zotero.Groups.get(groupID);
|
||||
return group.editable;
|
||||
}
|
||||
else {
|
||||
throw ("Unknown library type '" + type + "' in Zotero.ItemGroup.isEditable()");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Zotero.ItemGroup.prototype.getName = function()
|
||||
{
|
||||
if (this.isCollection()) {
|
||||
return this.ref.name;
|
||||
}
|
||||
else if (this.isLibrary()) {
|
||||
return Zotero.getString('pane.collections.library');
|
||||
}
|
||||
else if (this.isSearch()) {
|
||||
return this.ref.name;
|
||||
}
|
||||
else if (this.isShare()) {
|
||||
return this.ref.name;
|
||||
}
|
||||
else if (this.isTrash()) {
|
||||
return Zotero.getString('pane.collections.trash');
|
||||
}
|
||||
else {
|
||||
return "";
|
||||
switch (this.type) {
|
||||
case 'collection':
|
||||
return this.ref.name;
|
||||
|
||||
case 'library':
|
||||
return Zotero.getString('pane.collections.library');
|
||||
|
||||
case 'search':
|
||||
return this.ref.name;
|
||||
|
||||
case 'share':
|
||||
return this.ref.name;
|
||||
|
||||
case 'trash':
|
||||
return Zotero.getString('pane.collections.trash');
|
||||
|
||||
case 'group':
|
||||
return this.ref.name;
|
||||
|
||||
case 'header':
|
||||
return this.ref.label;
|
||||
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
Zotero.ItemGroup.prototype.getChildItems = function()
|
||||
{
|
||||
// Fake results if this is a shared library
|
||||
if (this.isShare()) {
|
||||
return this.ref.getAll();
|
||||
switch (this.type) {
|
||||
// Fake results if this is a shared library
|
||||
case 'share':
|
||||
return this.ref.getAll();
|
||||
|
||||
case 'header':
|
||||
return [];
|
||||
}
|
||||
|
||||
var s = this.getSearchObject();
|
||||
|
||||
// FIXME: Hack to exclude group libraries for now
|
||||
if (this.isSearch()) {
|
||||
var groups = Zotero.Groups.getAll();
|
||||
for each(var group in groups) {
|
||||
s.addCondition('libraryID', 'isNot', group.libraryID);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
var ids;
|
||||
if (this.showDuplicates) {
|
||||
|
@ -1125,8 +1567,14 @@ Zotero.ItemGroup.prototype.getSearchObject = function() {
|
|||
var includeScopeChildren = false;
|
||||
|
||||
// Create/load the inner search
|
||||
var s = new Zotero.Search(this.isSearch() ? this.ref.id : null);
|
||||
var s = new Zotero.Search();
|
||||
if (this.isLibrary()) {
|
||||
s.addCondition('libraryID', 'is', null);
|
||||
s.addCondition('noChildren', 'true');
|
||||
includeScopeChildren = true;
|
||||
}
|
||||
else if (this.isGroup()) {
|
||||
s.addCondition('libraryID', 'is', this.ref.libraryID);
|
||||
s.addCondition('noChildren', 'true');
|
||||
includeScopeChildren = true;
|
||||
}
|
||||
|
@ -1141,7 +1589,10 @@ Zotero.ItemGroup.prototype.getSearchObject = function() {
|
|||
else if (this.isTrash()) {
|
||||
s.addCondition('deleted', 'true');
|
||||
}
|
||||
else if (!this.isSearch()) {
|
||||
else if (this.isSearch()) {
|
||||
s.id = this.ref.id;
|
||||
}
|
||||
else {
|
||||
throw ('Invalid search mode in Zotero.ItemGroup.getSearchObject()');
|
||||
}
|
||||
|
||||
|
@ -1172,10 +1623,15 @@ Zotero.ItemGroup.prototype.getSearchObject = function() {
|
|||
* Returns all the tags used by items in the current view
|
||||
*/
|
||||
Zotero.ItemGroup.prototype.getChildTags = function() {
|
||||
// TODO: implement?
|
||||
if (this.isShare()) {
|
||||
return false;
|
||||
switch (this.type) {
|
||||
// TODO: implement?
|
||||
case 'share':
|
||||
return false;
|
||||
|
||||
case 'header':
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
var s = this.getSearchObject();
|
||||
return Zotero.Tags.getAllWithinSearch(s);
|
||||
|
@ -1196,8 +1652,10 @@ Zotero.ItemGroup.prototype.setTags = function(tags)
|
|||
* Returns TRUE if saved search, quicksearch or tag filter
|
||||
*/
|
||||
Zotero.ItemGroup.prototype.isSearchMode = function() {
|
||||
if (this.isSearch() || this.isTrash()) {
|
||||
return true;
|
||||
switch (this.type) {
|
||||
case 'search':
|
||||
case 'trash':
|
||||
return true;
|
||||
}
|
||||
|
||||
// Quicksearch
|
||||
|
|
|
@ -21,18 +21,23 @@
|
|||
*/
|
||||
|
||||
|
||||
Zotero.Collection = function(collectionID) {
|
||||
this._collectionID = collectionID ? collectionID : null;
|
||||
Zotero.Collection = function() {
|
||||
if (arguments[0]) {
|
||||
throw ("Zotero.Collection constructor doesn't take any parameters");
|
||||
}
|
||||
|
||||
this._init();
|
||||
}
|
||||
|
||||
Zotero.Collection.prototype._init = function () {
|
||||
// Public members for access by public methods -- do not access directly
|
||||
this._id = null;
|
||||
this._libraryID = null
|
||||
this._key = null;
|
||||
this._name = null;
|
||||
this._parent = null;
|
||||
this._parent = false;
|
||||
this._dateAdded = null;
|
||||
this._dateModified = null;
|
||||
this._key = null;
|
||||
|
||||
this._loaded = false;
|
||||
this._changed = false;
|
||||
|
@ -50,44 +55,66 @@ Zotero.Collection.prototype._init = function () {
|
|||
}
|
||||
|
||||
|
||||
Zotero.Collection.prototype.__defineGetter__('id', function () { return this._collectionID; });
|
||||
|
||||
Zotero.Collection.prototype.__defineSetter__('collectionID', function (val) { this._set('collectionID', val); });
|
||||
Zotero.Collection.prototype.__defineGetter__('objectType', function () { return 'collection'; });
|
||||
Zotero.Collection.prototype.__defineGetter__('id', function () { return this._get('id'); });
|
||||
Zotero.Collection.prototype.__defineSetter__('id', function (val) { this._set('id', val); });
|
||||
Zotero.Collection.prototype.__defineGetter__('libraryID', function () { return this._get('libraryID'); });
|
||||
Zotero.Collection.prototype.__defineSetter__('libraryID', function (val) { return this._set('libraryID', val); });
|
||||
Zotero.Collection.prototype.__defineGetter__('key', function () { return this._get('key'); });
|
||||
Zotero.Collection.prototype.__defineSetter__('key', function (val) { this._set('key', val) });
|
||||
Zotero.Collection.prototype.__defineGetter__('name', function () { return this._get('name'); });
|
||||
Zotero.Collection.prototype.__defineSetter__('name', function (val) { this._set('name', val); });
|
||||
Zotero.Collection.prototype.__defineGetter__('parent', function () { return this._get('parent'); });
|
||||
Zotero.Collection.prototype.__defineSetter__('parent', function (val) { this._set('parent', val); });
|
||||
Zotero.Collection.prototype.__defineGetter__('parentKey', function () { return this._get('parentKey'); });
|
||||
Zotero.Collection.prototype.__defineSetter__('parentKey', function (val) { this._set('parentKey', val); });
|
||||
Zotero.Collection.prototype.__defineGetter__('dateAdded', function () { return this._get('dateAdded'); });
|
||||
Zotero.Collection.prototype.__defineSetter__('dateAdded', function (val) { this._set('dateAdded', val); });
|
||||
Zotero.Collection.prototype.__defineGetter__('dateModified', function () { return this._get('dateModified'); });
|
||||
Zotero.Collection.prototype.__defineSetter__('dateModified', function (val) { this._set('dateModified', val); });
|
||||
Zotero.Collection.prototype.__defineGetter__('key', function () { return this._get('key'); });
|
||||
Zotero.Collection.prototype.__defineSetter__('key', function (val) { this._set('key', val); });
|
||||
|
||||
//Zotero.Collection.prototype.__defineSetter__('childCollections', function (arr) { this._setChildCollections(arr); });
|
||||
Zotero.Collection.prototype.__defineSetter__('childItems', function (arr) { this._setChildItems(arr); });
|
||||
|
||||
|
||||
Zotero.Collection.prototype._get = function (field) {
|
||||
if (this.id && !this._loaded) {
|
||||
if ((this._id || this._key) && !this._loaded) {
|
||||
this.load();
|
||||
}
|
||||
|
||||
switch (field) {
|
||||
case 'parent':
|
||||
return this._getParent();
|
||||
|
||||
case 'parentKey':
|
||||
return this._getParentKey();
|
||||
}
|
||||
|
||||
return this['_' + field];
|
||||
}
|
||||
|
||||
|
||||
Zotero.Collection.prototype._set = function (field, val) {
|
||||
if (field == 'name') {
|
||||
val = Zotero.Utilities.prototype.trim(val);
|
||||
}
|
||||
|
||||
switch (field) {
|
||||
case 'id': // set using constructor
|
||||
//case 'collectionID': // set using constructor
|
||||
throw ("Invalid field '" + field + "' in Zotero.Collection.set()");
|
||||
case 'id':
|
||||
case 'libraryID':
|
||||
case 'key':
|
||||
if (val == this['_' + field]) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._loaded) {
|
||||
throw ("Cannot set " + field + " after object is already loaded in Zotero.Collection._set()");
|
||||
}
|
||||
//this._checkValue(field, val);
|
||||
this['_' + field] = val;
|
||||
return;
|
||||
|
||||
case 'name':
|
||||
val = Zotero.Utilities.prototype.trim(val);
|
||||
break;
|
||||
}
|
||||
|
||||
if (this.id) {
|
||||
if (this.id || this.key) {
|
||||
if (!this._loaded) {
|
||||
this.load();
|
||||
}
|
||||
|
@ -96,6 +123,16 @@ Zotero.Collection.prototype._set = function (field, val) {
|
|||
this._loaded = true;
|
||||
}
|
||||
|
||||
switch (field) {
|
||||
case 'parent':
|
||||
this._setParent(val);
|
||||
return;
|
||||
|
||||
case 'parentKey':
|
||||
this._setParentKey(val);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this['_' + field] != val) {
|
||||
this._prepFieldChange(field);
|
||||
|
||||
|
@ -126,16 +163,35 @@ Zotero.Collection.prototype.getParent = function() {
|
|||
* Build collection from database
|
||||
*/
|
||||
Zotero.Collection.prototype.load = function() {
|
||||
var id = this._id;
|
||||
var key = this._key;
|
||||
var libraryID = this._libraryID;
|
||||
//var desc = id ? id : libraryID + "/" + key;
|
||||
|
||||
// Should be same as query in Zotero.Collections, just with collectionID
|
||||
var sql = "SELECT C.*, "
|
||||
+ "(SELECT COUNT(*) FROM collections WHERE "
|
||||
+ "parentCollectionID=C.collectionID)!=0 AS hasChildCollections, "
|
||||
+ "(SELECT COUNT(*) FROM collectionItems WHERE "
|
||||
+ "collectionID=C.collectionID)!=0 AS hasChildItems "
|
||||
+ "FROM collections C WHERE collectionID=?";
|
||||
var data = Zotero.DB.rowQuery(sql, this.id);
|
||||
+ "FROM collections C WHERE ";
|
||||
if (id) {
|
||||
sql += "collectionID=?";
|
||||
var params = id;
|
||||
}
|
||||
else {
|
||||
sql += "key=?";
|
||||
var params = [key];
|
||||
if (libraryID) {
|
||||
sql += " AND libraryID=?";
|
||||
params.push(libraryID);
|
||||
}
|
||||
else {
|
||||
sql += " AND libraryID IS NULL";
|
||||
}
|
||||
}
|
||||
var data = Zotero.DB.rowQuery(sql, params);
|
||||
|
||||
this._init();
|
||||
this._loaded = true;
|
||||
|
||||
if (!data) {
|
||||
|
@ -154,13 +210,16 @@ Zotero.Collection.prototype.loadFromRow = function(row) {
|
|||
this._changed = false;
|
||||
this._previousData = false;
|
||||
|
||||
this._collectionID = row.collectionID;
|
||||
this._id = row.collectionID;
|
||||
this._libraryID = row.libraryID;
|
||||
this._key = row.key;
|
||||
this._name = row.collectionName;
|
||||
this._parent = row.parentCollectionID;
|
||||
this._dateAdded = row.dateAdded;
|
||||
this._dateModified = row.dateModified;
|
||||
this._key = row.key;
|
||||
this._childCollectionsLoaded = false;
|
||||
this._hasChildCollections = !!row.hasChildCollections;
|
||||
this._childItemsLoaded = false;
|
||||
this._hasChildItems = !!row.hasChildItems;
|
||||
this._loadChildItems();
|
||||
}
|
||||
|
@ -288,6 +347,8 @@ Zotero.Collection.prototype.unlockDateModified = function () {
|
|||
|
||||
|
||||
Zotero.Collection.prototype.save = function () {
|
||||
Zotero.Collections.editCheck(this);
|
||||
|
||||
if (!this.name) {
|
||||
throw ('Collection name is empty in Zotero.Collection.save()');
|
||||
}
|
||||
|
@ -297,54 +358,8 @@ Zotero.Collection.prototype.save = function () {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (this._changed.parent && this.parent) {
|
||||
if (!Zotero.Collections.get(this.parent)) {
|
||||
throw ('Cannot set parent of collection ' + this.id
|
||||
+ ' to invalid parent ' + this.parent);
|
||||
}
|
||||
|
||||
if (this.parent == this.id) {
|
||||
throw ('Cannot move collection into itself!');
|
||||
}
|
||||
|
||||
if (this.id && this.hasDescendent('collection', this.parent)) {
|
||||
throw ('Cannot move collection into one of its own descendents!', 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Zotero.DB.beginTransaction();
|
||||
|
||||
// ID change
|
||||
if (this._changed['collectionID']) {
|
||||
var oldID = this._previousData.primary.collectionID;
|
||||
var params = [this.id, oldID];
|
||||
|
||||
Zotero.debug("Changing collectionID " + oldID + " to " + this.id);
|
||||
|
||||
var row = Zotero.DB.rowQuery("SELECT * FROM collections WHERE collectionID=?", oldID);
|
||||
// Add a new row so we can update the old rows despite FK checks
|
||||
// Use temp key due to UNIQUE constraint on key column
|
||||
Zotero.DB.query("INSERT INTO collections VALUES (?, ?, ?, ?, ?, ?)",
|
||||
[this.id, row.collectionName, row.parentCollectionID,
|
||||
row.dateAdded, row.dateModified, 'TEMPKEY']);
|
||||
|
||||
Zotero.DB.query("UPDATE collectionItems SET collectionID=? WHERE collectionID=?", params);
|
||||
Zotero.DB.query("UPDATE collections SET parentCollectionID=? WHERE parentCollectionID=?", params);
|
||||
|
||||
Zotero.DB.query("DELETE FROM collections WHERE collectionID=?", oldID);
|
||||
Zotero.DB.query("UPDATE collections SET key=? WHERE collectionID=?", [row.key, this.id]);
|
||||
|
||||
Zotero.Notifier.trigger('id-change', 'collection', oldID + '-' + this.id);
|
||||
|
||||
// Update child collections that have cached the previous id
|
||||
var sql = "SELECT collectionID FROM collections WHERE parentCollectionID=?";
|
||||
var children = Zotero.DB.columnQuery(sql, this.id);
|
||||
if (children) {
|
||||
Zotero.Collections.refreshParents(children);
|
||||
}
|
||||
}
|
||||
|
||||
var isNew = !this.id || !this.exists();
|
||||
|
||||
try {
|
||||
|
@ -356,20 +371,55 @@ Zotero.Collection.prototype.save = function () {
|
|||
|
||||
var key = this.key ? this.key : this._generateKey();
|
||||
|
||||
// Verify parent
|
||||
if (this._parent) {
|
||||
if (typeof this._parent == 'number') {
|
||||
var newParent = Zotero.Collections.get(this._parent);
|
||||
}
|
||||
else {
|
||||
var newParent = Zotero.Collections.getByLibraryAndKey(this.libraryID, this._parent);
|
||||
}
|
||||
|
||||
if (!newParent) {
|
||||
throw("Cannot set parent to invalid collection " + this._parent + " in Zotero.Collection.save()");
|
||||
}
|
||||
|
||||
if (newParent.id == this.id) {
|
||||
throw ('Cannot move collection into itself!');
|
||||
}
|
||||
|
||||
if (this.id && this.hasDescendent('collection', newParent.id)) {
|
||||
throw ('Cannot move collection into one of its own descendents!', 2);
|
||||
}
|
||||
|
||||
var parent = newParent.id;
|
||||
}
|
||||
else {
|
||||
var parent = null;
|
||||
}
|
||||
|
||||
var columns = [
|
||||
'collectionID', 'collectionName', 'parentCollectionID',
|
||||
'dateAdded', 'dateModified', 'key'
|
||||
'collectionID',
|
||||
'collectionName',
|
||||
'parentCollectionID',
|
||||
'dateAdded',
|
||||
'dateModified',
|
||||
'clientDateModified',
|
||||
'libraryID',
|
||||
'key'
|
||||
];
|
||||
var placeholders = ['?', '?', '?', '?', '?', '?'];
|
||||
var placeholders = ['?', '?', '?', '?', '?', '?', '?', '?'];
|
||||
var sqlValues = [
|
||||
collectionID ? { int: collectionID } : null,
|
||||
{ string: this.name },
|
||||
this.parent ? { int: this.parent } : null,
|
||||
parent ? parent : null,
|
||||
// If date added isn't set, use current timestamp
|
||||
this.dateAdded ? this.dateAdded : Zotero.DB.transactionDateTime,
|
||||
// If date modified hasn't changed, use current timestamp
|
||||
this._changed.dateModified ?
|
||||
this.dateModified : Zotero.DB.transactionDateTime,
|
||||
Zotero.DB.transactionDateTime,
|
||||
this.libraryID ? this.libraryID : null,
|
||||
key
|
||||
];
|
||||
|
||||
|
@ -380,20 +430,19 @@ Zotero.Collection.prototype.save = function () {
|
|||
collectionID = insertID;
|
||||
}
|
||||
|
||||
|
||||
if (this._changed.parent) {
|
||||
var parentIDs = [];
|
||||
if (this._previousData.parent) {
|
||||
if (this.id && this._previousData.parent) {
|
||||
parentIDs.push(this._previousData.parent);
|
||||
}
|
||||
if (this.parent) {
|
||||
parentIDs.push(this.parent);
|
||||
}
|
||||
|
||||
Zotero.Notifier.trigger('move', 'collection', this.id);
|
||||
if (this.id) {
|
||||
Zotero.Notifier.trigger('move', 'collection', this.id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// Subcollections
|
||||
if (this._changed.childCollections) {
|
||||
|
@ -502,6 +551,12 @@ Zotero.Collection.prototype.save = function () {
|
|||
insertStatement.execute();
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.debug('=======');
|
||||
Zotero.debug(collectionID);
|
||||
Zotero.debug(itemID);
|
||||
Zotero.debug(orderIndex);
|
||||
Zotero.debug(Zotero.DB.query("SELECT * FROM collections"));
|
||||
Zotero.debug(Zotero.DB.query("SELECT * FROM collectionItems"));
|
||||
throw (e + ' [ERROR: ' + Zotero.DB.getLastErrorString() + ']');
|
||||
}
|
||||
}
|
||||
|
@ -510,6 +565,11 @@ Zotero.Collection.prototype.save = function () {
|
|||
//Zotero.Notifier.trigger('add', 'collection-item', this.id + '-' + itemID);
|
||||
}
|
||||
|
||||
if (this._changed.libraryID) {
|
||||
var groupID = Zotero.Libraries.getGroupIDFromLibraryID(this.libraryID);
|
||||
var group = Zotero.Groups.get(groupID);
|
||||
group.clearCollectionsCache();
|
||||
}
|
||||
Zotero.DB.commitTransaction();
|
||||
}
|
||||
catch (e) {
|
||||
|
@ -519,7 +579,7 @@ Zotero.Collection.prototype.save = function () {
|
|||
|
||||
// If successful, set values in object
|
||||
if (!this.id) {
|
||||
this._collectionID = collectionID;
|
||||
this._id = collectionID;
|
||||
}
|
||||
|
||||
if (!this.key) {
|
||||
|
@ -537,7 +597,7 @@ Zotero.Collection.prototype.save = function () {
|
|||
|
||||
// Invalidate cached child collections
|
||||
if (parentIDs) {
|
||||
Zotero.Collections.refreshChildCollections(parentIDs)
|
||||
Zotero.Collections.refreshChildCollections(parentIDs);
|
||||
}
|
||||
|
||||
return this.id;
|
||||
|
@ -569,8 +629,8 @@ Zotero.Collection.prototype.addItem = function(itemID) {
|
|||
sql = "INSERT OR IGNORE INTO collectionItems VALUES (?,?,?)";
|
||||
Zotero.DB.query(sql, [this.id, itemID, nextOrderIndex]);
|
||||
|
||||
sql = "UPDATE collections SET dateModified=? WHERE collectionID=?";
|
||||
Zotero.DB.query(sql, [Zotero.DB.transactionDateTime, this.id]);
|
||||
sql = "UPDATE collections SET dateModified=?, clientDateModified=? WHERE collectionID=?";
|
||||
Zotero.DB.query(sql, [Zotero.DB.transactionDateTime, Zotero.DB.transactionDateTime, this.id]);
|
||||
|
||||
Zotero.DB.commitTransaction();
|
||||
|
||||
|
@ -618,8 +678,8 @@ Zotero.Collection.prototype.removeItem = function(itemID) {
|
|||
Zotero.DB.query(sql, [this.id, itemID]);
|
||||
|
||||
if (!this._dateModifiedLocked) {
|
||||
sql = "UPDATE collections SET dateModified=? WHERE collectionID=?";
|
||||
Zotero.DB.query(sql, [Zotero.DB.transactionDateTime, this.id])
|
||||
sql = "UPDATE collections SET dateModified=?, clientDateModified=? WHERE collectionID=?";
|
||||
Zotero.DB.query(sql, [Zotero.DB.transactionDateTime, Zotero.DB.transactionDateTime, this.id])
|
||||
}
|
||||
|
||||
Zotero.DB.commitTransaction();
|
||||
|
@ -812,9 +872,10 @@ Zotero.Collection.prototype.serialize = function(nested) {
|
|||
var obj = {
|
||||
primary: {
|
||||
collectionID: this.id,
|
||||
libraryID: this.libraryID,
|
||||
key: this.key,
|
||||
dateAdded: this.dateAdded,
|
||||
dateModified: this.dateModified,
|
||||
key: this.key
|
||||
dateModified: this.dateModified
|
||||
},
|
||||
fields: {
|
||||
name: this.name,
|
||||
|
@ -835,7 +896,7 @@ Zotero.Collection.prototype.serialize = function(nested) {
|
|||
* @param bool nested Return multidimensional array with 'children'
|
||||
* nodes instead of flat array
|
||||
* @param string type 'item', 'collection', or FALSE for both
|
||||
* @return {Object[]} Array of objects with 'id',
|
||||
* @return {Object[]} Array of objects with 'id', 'key',
|
||||
* 'type' ('item' or 'collection'), 'parent',
|
||||
* and, if collection, 'name' and the nesting 'level'
|
||||
*/
|
||||
|
@ -853,10 +914,10 @@ Zotero.Collection.prototype.getChildren = function(recursive, nested, type, leve
|
|||
// 0 == collection
|
||||
// 1 == item
|
||||
var children = Zotero.DB.query('SELECT collectionID AS id, '
|
||||
+ "0 AS type, collectionName AS collectionName "
|
||||
+ "0 AS type, collectionName AS collectionName, key "
|
||||
+ 'FROM collections WHERE parentCollectionID=?1'
|
||||
+ ' UNION SELECT itemID AS id, 1 AS type, NULL AS collectionName '
|
||||
+ 'FROM collectionItems WHERE collectionID=?1', this.id);
|
||||
+ ' UNION SELECT itemID AS id, 1 AS type, NULL AS collectionName, key '
|
||||
+ 'FROM collectionItems JOIN items USING (itemID) WHERE collectionID=?1', this.id);
|
||||
|
||||
if (type) {
|
||||
switch (type) {
|
||||
|
@ -879,6 +940,7 @@ Zotero.Collection.prototype.getChildren = function(recursive, nested, type, leve
|
|||
toReturn.push({
|
||||
id: children[i].id,
|
||||
name: children[i].collectionName,
|
||||
key: children[i].key,
|
||||
type: 'collection',
|
||||
level: level,
|
||||
parent: this.id
|
||||
|
@ -905,6 +967,7 @@ Zotero.Collection.prototype.getChildren = function(recursive, nested, type, leve
|
|||
if (!type || type=='item') {
|
||||
toReturn.push({
|
||||
id: children[i].id,
|
||||
key: children[i].key,
|
||||
type: 'item',
|
||||
parent: this.id
|
||||
});
|
||||
|
@ -939,6 +1002,139 @@ Zotero.Collection.prototype._prepFieldChange = function (field) {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the collectionID of the parent collection
|
||||
* @return {Integer}
|
||||
*/
|
||||
Zotero.Collection.prototype._getParent = function() {
|
||||
if (this._parent !== false) {
|
||||
if (!this._parent) {
|
||||
return null;
|
||||
}
|
||||
if (typeof this._parent == 'number') {
|
||||
return this._parent;
|
||||
}
|
||||
var parentCollection = Zotero.Collections.getByLibraryAndKey(this.libraryID, this._parent);
|
||||
if (!parentCollection) {
|
||||
throw ("Parent collection for keyed parent doesn't exist in Zotero.Collection._getParent()");
|
||||
}
|
||||
// Replace stored key with id
|
||||
this._parent = parentCollection.id;
|
||||
return parentCollection.id;
|
||||
}
|
||||
|
||||
if (!this.id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var sql = "SELECT parentCollectionID FROM collections WHERE collectionID=?";
|
||||
var parentCollectionID = Zotero.DB.valueQuery(sql, this.id);
|
||||
if (!parentCollectionID) {
|
||||
parentCollectionID = null;
|
||||
}
|
||||
this._parent = parentCollectionID;
|
||||
return parentCollectionID;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the key of the parent collection
|
||||
* @return {String}
|
||||
*/
|
||||
Zotero.Collection.prototype._getParentKey = function() {
|
||||
if (this._parent !== false) {
|
||||
if (!this._parent) {
|
||||
return null;
|
||||
}
|
||||
if (typeof this._parent == 'string') {
|
||||
return this._parent;
|
||||
}
|
||||
var parentCollection = Zotero.Collections.get(this._parent);
|
||||
return parentCollection.key;
|
||||
}
|
||||
|
||||
if (!this.id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var sql = "SELECT B.key FROM collections A JOIN collections B "
|
||||
+ "ON (A.parentCollectionID=B.collectionID) WHERE A.collectionID=?";
|
||||
var key = Zotero.DB.valueQuery(sql, this.id);
|
||||
if (!key) {
|
||||
key = null;
|
||||
}
|
||||
this._parent = key;
|
||||
return key;
|
||||
}
|
||||
|
||||
|
||||
Zotero.Collection.prototype._setParent = function(parentCollectionID) {
|
||||
if (this.id || this.key) {
|
||||
if (!this.loaded) {
|
||||
this.load(true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.loaded = true;
|
||||
}
|
||||
|
||||
var oldParentCollectionID = this._getParent();
|
||||
if (oldParentCollectionID == parentCollectionID) {
|
||||
Zotero.debug("Parent collection has not changed for collection " + this.id);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.id && this.exists() && !this._previousData) {
|
||||
this._previousData = this.serialize();
|
||||
}
|
||||
|
||||
this._parent = parentCollectionID ? parseInt(parentCollectionID) : null;
|
||||
if (!this._changed) {
|
||||
this._changed = {};
|
||||
}
|
||||
this._changed.parent = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Zotero.Collection.prototype._setParentKey = function(parentCollectionKey) {
|
||||
if (this.id || this.key) {
|
||||
if (!this.loaded) {
|
||||
this.load(true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.loaded = true;
|
||||
}
|
||||
|
||||
var oldParentCollectionID = this._getParent();
|
||||
if (oldParentCollectionID) {
|
||||
var parentCollection = Zotero.Collections.get(oldParentCollectionID)
|
||||
var oldParentCollectionKey = parentCollection.key;
|
||||
}
|
||||
else {
|
||||
var oldParentCollectionKey = null;
|
||||
}
|
||||
if (oldParentCollectionKey == parentCollectionKey) {
|
||||
Zotero.debug("Parent collection has not changed in Zotero.Collection._setParentKey()");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.id && this.exists() && !this._previousData) {
|
||||
this._previousData = this.serialize();
|
||||
}
|
||||
|
||||
this._parent = parentCollectionKey ? parentCollectionKey : null;
|
||||
if (!this._changed) {
|
||||
this._changed = {};
|
||||
}
|
||||
this._changed.parent = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Zotero.Collection.prototype._setChildCollections = function (collectionIDs) {
|
||||
this._setChildren('collection', collectionIDs);
|
||||
|
@ -1053,7 +1249,13 @@ Zotero.Collection.prototype._loadChildCollections = function () {
|
|||
}
|
||||
|
||||
Zotero.Collection.prototype._loadChildItems = function() {
|
||||
var sql = "SELECT itemID FROM collectionItems WHERE collectionID=? ";
|
||||
if (!this.id) {
|
||||
//throw ("Collection id not set in Zotero.Collection._loadChildItems()");
|
||||
this._childItemsLoaded = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var sql = "SELECT itemID FROM collectionItems WHERE collectionID=? "
|
||||
// DEBUG: Fix for child items created via context menu on parent within
|
||||
// a collection being added to the current collection
|
||||
+ "AND itemID NOT IN "
|
||||
|
@ -1074,22 +1276,6 @@ Zotero.Collection.prototype._loadChildItems = function() {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Note: This is called by Zotero.Collections.refreshParent()
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
Zotero.Collection.prototype._refreshParent = function () {
|
||||
if (!this.id) {
|
||||
throw ("Cannot call Zotero.Collection._refreshParent() on unsaved collection");
|
||||
}
|
||||
|
||||
var sql = "SELECT parentCollectionID FROM collections "
|
||||
+ "WHERE collectionID=?";
|
||||
this._parent = Zotero.DB.valueQuery(sql, this.id);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Invalid child collection cache
|
||||
*
|
||||
|
|
|
@ -80,23 +80,6 @@ Zotero.Collections = new function() {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Refresh cached parents in specified collections, skipping
|
||||
* any that aren't loaded
|
||||
*
|
||||
* @param {Integer|Integer[]} ids One or more itemIDs
|
||||
*/
|
||||
this.refreshParents = function (ids) {
|
||||
ids = Zotero.flattenArguments(ids);
|
||||
|
||||
for each(var id in ids) {
|
||||
if (this._objectCache[id]) {
|
||||
this._objectCache[id]._refreshParent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Invalidate child collection cache in specified collections, skipping
|
||||
* any that aren't loaded
|
||||
|
|
|
@ -21,18 +21,23 @@
|
|||
*/
|
||||
|
||||
|
||||
Zotero.Creator = function (creatorID) {
|
||||
this._creatorID = creatorID ? creatorID : null;
|
||||
Zotero.Creator = function () {
|
||||
if (arguments[0]) {
|
||||
throw ("Zotero.Creator constructor doesn't take any parameters");
|
||||
}
|
||||
|
||||
this._init();
|
||||
}
|
||||
|
||||
|
||||
Zotero.Creator.prototype._init = function () {
|
||||
this._id = null;
|
||||
this._libraryID = null
|
||||
this._key = null;
|
||||
this._firstName = null;
|
||||
this._lastName = null;
|
||||
this._fieldMode = null;
|
||||
this._birthYear = null;
|
||||
this._key = null;
|
||||
this._dateAdded = null;
|
||||
this._dateModified = null;
|
||||
|
||||
|
@ -43,10 +48,14 @@ Zotero.Creator.prototype._init = function () {
|
|||
}
|
||||
|
||||
|
||||
Zotero.Creator.prototype.__defineGetter__('id', function () { return this._creatorID; });
|
||||
Zotero.Creator.prototype.__defineGetter__('objectType', function () { return 'creator'; });
|
||||
Zotero.Creator.prototype.__defineGetter__('id', function () { return this._get('id'); });
|
||||
Zotero.Creator.prototype.__defineSetter__('id', function (val) { this._set('id', val); });
|
||||
Zotero.Creator.prototype.__defineGetter__('libraryID', function () { return this._get('libraryID'); });
|
||||
Zotero.Creator.prototype.__defineSetter__('libraryID', function (val) { return this._set('libraryID', val); });
|
||||
Zotero.Creator.prototype.__defineGetter__('key', function () { return this._get('key'); });
|
||||
Zotero.Creator.prototype.__defineSetter__('key', function (val) { this._set('key', val) });
|
||||
Zotero.Creator.prototype.__defineGetter__('creatorDataID', function () { return this._get('creatorDataID'); });
|
||||
|
||||
Zotero.Creator.prototype.__defineSetter__('creatorID', function (val) { this._set('creatorID', val); });
|
||||
Zotero.Creator.prototype.__defineGetter__('firstName', function () { return this._get('firstName'); });
|
||||
Zotero.Creator.prototype.__defineSetter__('firstName', function (val) { this._set('firstName', val); });
|
||||
Zotero.Creator.prototype.__defineGetter__('lastName', function () { return this._get('lastName'); });
|
||||
|
@ -59,16 +68,13 @@ Zotero.Creator.prototype.__defineGetter__('dateAdded', function () { return this
|
|||
Zotero.Creator.prototype.__defineSetter__('dateAdded', function (val) { this._set('dateAdded', val); });
|
||||
Zotero.Creator.prototype.__defineGetter__('dateModified', function () { return this._get('dateModified'); });
|
||||
Zotero.Creator.prototype.__defineSetter__('dateModified', function (val) { this._set('dateModified', val); });
|
||||
Zotero.Creator.prototype.__defineGetter__('key', function () { return this._get('key'); });
|
||||
Zotero.Creator.prototype.__defineSetter__('key', function (val) { this._set('key', val); });
|
||||
|
||||
// Block properties that can't be set this way
|
||||
Zotero.Creator.prototype.__defineSetter__('id', function () { this._set('id', val); });
|
||||
Zotero.Creator.prototype.__defineSetter__('creatorDataID', function () { this._set('creatorDataID', val); });
|
||||
//Zotero.Creator.prototype.__defineSetter__('creatorDataID', function () { this._set('creatorDataID', val); });
|
||||
|
||||
|
||||
Zotero.Creator.prototype._get = function (field) {
|
||||
if (this.id && !this._loaded) {
|
||||
if ((this._id || this._key) && !this._loaded) {
|
||||
this.load(true);
|
||||
}
|
||||
return this['_' + field];
|
||||
|
@ -77,26 +83,40 @@ Zotero.Creator.prototype._get = function (field) {
|
|||
|
||||
Zotero.Creator.prototype._set = function (field, val) {
|
||||
switch (field) {
|
||||
case 'id':
|
||||
case 'libraryID':
|
||||
case 'key':
|
||||
if (val == this['_' + field]) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._loaded) {
|
||||
throw ("Cannot set " + field + " after object is already loaded in Zotero.Creator._set()");
|
||||
}
|
||||
this._checkValue(field, val);
|
||||
this['_' + field] = val;
|
||||
return;
|
||||
|
||||
case 'firstName':
|
||||
case 'lastName':
|
||||
case 'shortName':
|
||||
if (val) {
|
||||
val = value = Zotero.Utilities.prototype.trim(val);
|
||||
val = Zotero.Utilities.prototype.trim(val);
|
||||
}
|
||||
else {
|
||||
val = value = '';
|
||||
val = '';
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
switch (field) {
|
||||
case 'id': // set using constructor
|
||||
//case 'creatorID': // set using constructor
|
||||
|
||||
case 'fieldMode':
|
||||
val = val ? parseInt(val) : 0;
|
||||
break;
|
||||
|
||||
case 'creatorDataID':
|
||||
throw ("Invalid field '" + field + "' in Zotero.Creator.set()");
|
||||
}
|
||||
|
||||
if (this.id) {
|
||||
if (this.id || this.key) {
|
||||
if (!this._loaded) {
|
||||
this.load(true);
|
||||
}
|
||||
|
@ -121,10 +141,11 @@ Zotero.Creator.prototype._set = function (field, val) {
|
|||
}
|
||||
|
||||
|
||||
Zotero.Creator.prototype.setFields = function(fields) {
|
||||
for (var field in fields) {
|
||||
this[field] = fields[field];
|
||||
}
|
||||
Zotero.Creator.prototype.setFields = function (fields) {
|
||||
this.firstName = fields.firstName;
|
||||
this.lastName = fields.lastName;
|
||||
this.fieldMode = fields.fieldMode;
|
||||
this.birthYear = fields.birthYear;
|
||||
}
|
||||
|
||||
|
||||
|
@ -149,6 +170,10 @@ Zotero.Creator.prototype.hasChanged = function () {
|
|||
|
||||
|
||||
Zotero.Creator.prototype.save = function () {
|
||||
Zotero.Creators.editCheck(this);
|
||||
|
||||
Zotero.debug("Saving creator " + this.id);
|
||||
|
||||
if (!this.firstName && !this.lastName) {
|
||||
throw ('First and last name are empty in Zotero.Creator.save()');
|
||||
}
|
||||
|
@ -164,32 +189,6 @@ Zotero.Creator.prototype.save = function () {
|
|||
|
||||
Zotero.DB.beginTransaction();
|
||||
|
||||
// ID change
|
||||
if (this._changed['creatorID']) {
|
||||
var oldID = this._previousData.primary.creatorID;
|
||||
var params = [this.id, oldID];
|
||||
|
||||
Zotero.debug("Changing creatorID " + oldID + " to " + this.id);
|
||||
|
||||
var row = Zotero.DB.rowQuery("SELECT * FROM creators WHERE creatorID=?", oldID);
|
||||
// Add a new row so we can update the old rows despite FK checks
|
||||
// Use temp key due to UNIQUE constraint on key column
|
||||
Zotero.DB.query("INSERT INTO creators VALUES (?, ?, ?, ?, ?)",
|
||||
[this.id, row.creatorDataID, row.dateAdded, row.dateModified, 'TEMPKEY']);
|
||||
|
||||
Zotero.DB.query("UPDATE itemCreators SET creatorID=? WHERE creatorID=?", params);
|
||||
|
||||
Zotero.DB.query("DELETE FROM creators WHERE creatorID=?", oldID);
|
||||
Zotero.DB.query("UPDATE creators SET key=? WHERE creatorID=?", [row.key, this.id]);
|
||||
|
||||
Zotero.Notifier.trigger('id-change', 'creator', oldID + '-' + this.id);
|
||||
|
||||
// Do this here because otherwise updateLinkedItems() below would
|
||||
// load a duplicate copy in the new position
|
||||
Zotero.Creators.reload(this.id);
|
||||
// update caches
|
||||
}
|
||||
|
||||
var isNew = !this.id || !this.exists();
|
||||
|
||||
try {
|
||||
|
@ -197,8 +196,6 @@ Zotero.Creator.prototype.save = function () {
|
|||
|
||||
var creatorID = this.id ? this.id : Zotero.ID.get('creators');
|
||||
|
||||
Zotero.debug("Saving creator " + this.id);
|
||||
|
||||
var key = this.key ? this.key : this._generateKey();
|
||||
|
||||
// If this was the only creator with the previous data,
|
||||
|
@ -229,8 +226,16 @@ Zotero.Creator.prototype.save = function () {
|
|||
var creatorDataID = Zotero.Creators.getDataID(this, true);
|
||||
}
|
||||
|
||||
var columns = ['creatorID', 'creatorDataID', 'dateAdded', 'dateModified', 'key'];
|
||||
var placeholders = ['?', '?', '?', '?', '?'];
|
||||
var columns = [
|
||||
'creatorID',
|
||||
'creatorDataID',
|
||||
'dateAdded',
|
||||
'dateModified',
|
||||
'clientDateModified',
|
||||
'libraryID',
|
||||
'key'
|
||||
];
|
||||
var placeholders = ['?', '?', '?', '?', '?', '?', '?'];
|
||||
var sqlValues = [
|
||||
creatorID ? { int: creatorID } : null,
|
||||
{ int: creatorDataID },
|
||||
|
@ -239,6 +244,8 @@ Zotero.Creator.prototype.save = function () {
|
|||
// If date modified hasn't changed, use current timestamp
|
||||
this._changed.dateModified ?
|
||||
this.dateModified : Zotero.DB.transactionDateTime,
|
||||
Zotero.DB.transactionDateTime,
|
||||
this.libraryID ? this.libraryID : null,
|
||||
key
|
||||
];
|
||||
|
||||
|
@ -267,7 +274,7 @@ Zotero.Creator.prototype.save = function () {
|
|||
|
||||
// If successful, set values in object
|
||||
if (!this.id) {
|
||||
this._creatorID = creatorID;
|
||||
this._id = creatorID;
|
||||
}
|
||||
if (!this.key) {
|
||||
this._key = key;
|
||||
|
@ -320,9 +327,9 @@ Zotero.Creator.prototype.updateLinkedItems = function () {
|
|||
}
|
||||
}
|
||||
|
||||
sql = "UPDATE items SET dateModified=? WHERE itemID IN "
|
||||
sql = "UPDATE items SET dateModified=?, clientDateModified=? WHERE itemID IN "
|
||||
+ "(SELECT itemID FROM itemCreators WHERE creatorID=?)";
|
||||
Zotero.DB.query(sql, [Zotero.DB.transactionDateTime, this.id]);
|
||||
Zotero.DB.query(sql, [Zotero.DB.transactionDateTime, Zotero.DB.transactionDateTime, this.id]);
|
||||
|
||||
Zotero.Items.reload(changedItemIDs);
|
||||
|
||||
|
@ -346,9 +353,10 @@ Zotero.Creator.prototype.serialize = function () {
|
|||
|
||||
obj.primary = {};
|
||||
obj.primary.creatorID = this.id;
|
||||
obj.primary.libraryID = this.libraryID;
|
||||
obj.primary.key = this.key;
|
||||
obj.primary.dateAdded = this.dateAdded;
|
||||
obj.primary.dateModified = this.dateModified;
|
||||
obj.primary.key = this.key;
|
||||
|
||||
obj.fields = {};
|
||||
if (this.fieldMode == 1) {
|
||||
|
@ -419,22 +427,41 @@ Zotero.Creator.prototype.erase = function () {
|
|||
|
||||
|
||||
Zotero.Creator.prototype.load = function (allowFail) {
|
||||
Zotero.debug("Loading data for creator " + this.id + " in Zotero.Creator.load()");
|
||||
var id = this._id;
|
||||
var key = this._key;
|
||||
var libraryID = this._libraryID;
|
||||
var desc = id ? id : libraryID + "/" + key;
|
||||
|
||||
if (!this.id) {
|
||||
throw ("creatorID not set in Zotero.Creator.load()");
|
||||
Zotero.debug("Loading data for creator " + desc + " in Zotero.Creator.load()");
|
||||
|
||||
if (!id && !key) {
|
||||
throw ("ID or key not set in Zotero.Creator.load()");
|
||||
}
|
||||
|
||||
var sql = "SELECT C.*, CD.* FROM creators C NATURAL JOIN creatorData CD "
|
||||
+ "WHERE creatorID=?";
|
||||
var row = Zotero.DB.rowQuery(sql, this.id);
|
||||
var sql = "SELECT C.*, CD.* FROM creators C NATURAL JOIN creatorData CD WHERE ";
|
||||
if (id) {
|
||||
sql += "creatorID=?";
|
||||
var params = id;
|
||||
}
|
||||
else {
|
||||
sql += "key=?";
|
||||
var params = [key];
|
||||
if (libraryID) {
|
||||
sql += " AND libraryID=?";
|
||||
params.push(libraryID);
|
||||
}
|
||||
else {
|
||||
sql += " AND libraryID IS NULL";
|
||||
}
|
||||
}
|
||||
var row = Zotero.DB.rowQuery(sql, params);
|
||||
|
||||
if (!row) {
|
||||
if (allowFail) {
|
||||
this._loaded = true;
|
||||
return false;
|
||||
}
|
||||
throw ("Creator " + this.id + " not found in Zotero.Item.load()");
|
||||
throw ("Creator " + desc + " not found in Zotero.Item.load()");
|
||||
}
|
||||
|
||||
this.loadFromRow(row);
|
||||
|
@ -444,12 +471,22 @@ Zotero.Creator.prototype.load = function (allowFail) {
|
|||
|
||||
Zotero.Creator.prototype.loadFromRow = function (row) {
|
||||
this._init();
|
||||
|
||||
for (var col in row) {
|
||||
//Zotero.debug("Setting field '" + col + "' to '" + row[col] + "' for creator " + this.id);
|
||||
switch (col) {
|
||||
case 'clientDateModified':
|
||||
continue;
|
||||
|
||||
case 'creatorID':
|
||||
this._id = row[col];
|
||||
continue;
|
||||
|
||||
case 'libraryID':
|
||||
this['_' + col] = row[col] ? row[col] : null;
|
||||
continue;
|
||||
}
|
||||
this['_' + col] = row[col] ? row[col] : '';
|
||||
}
|
||||
|
||||
this._loaded = true;
|
||||
}
|
||||
|
||||
|
@ -462,6 +499,18 @@ Zotero.Creator.prototype._checkValue = function (field, value) {
|
|||
|
||||
// Data validation
|
||||
switch (field) {
|
||||
case 'id':
|
||||
if (parseInt(value) != value) {
|
||||
this._invalidValueError(field, value);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'libraryID':
|
||||
if (value && parseInt(value) != value) {
|
||||
this._invalidValueError(field, value);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'fieldMode':
|
||||
if (value !== 0 && value !== 1) {
|
||||
this._invalidValueError(field, value);
|
||||
|
|
|
@ -42,6 +42,10 @@ Zotero.Creators = new function() {
|
|||
* Returns a Zotero.Creator object for a given creatorID
|
||||
*/
|
||||
function get(creatorID) {
|
||||
if (!creatorID) {
|
||||
throw ("creatorID not provided in Zotero.Creators.get()");
|
||||
}
|
||||
|
||||
if (this._objectCache[creatorID]) {
|
||||
return this._objectCache[creatorID];
|
||||
}
|
||||
|
@ -53,7 +57,9 @@ Zotero.Creators = new function() {
|
|||
return false;
|
||||
}
|
||||
|
||||
this._objectCache[creatorID] = new Zotero.Creator(creatorID);
|
||||
var creator = new Zotero.Creator;
|
||||
creator.id = creatorID;
|
||||
this._objectCache[creatorID] = creator;
|
||||
return this._objectCache[creatorID];
|
||||
}
|
||||
|
||||
|
@ -114,15 +120,28 @@ Zotero.Creators = new function() {
|
|||
}
|
||||
|
||||
|
||||
function getCreatorsWithData(creatorDataID) {
|
||||
function getCreatorsWithData(creatorDataID, libraryID) {
|
||||
var sql = "SELECT creatorID FROM creators WHERE creatorDataID=?";
|
||||
return Zotero.DB.columnQuery(sql, creatorDataID);
|
||||
var params = [creatorDataID];
|
||||
if (libraryID) {
|
||||
sql += " AND libraryID=?";
|
||||
params.push(libraryID);
|
||||
}
|
||||
else {
|
||||
sql += " AND libraryID IS NULL";
|
||||
}
|
||||
return Zotero.DB.columnQuery(sql, params);
|
||||
}
|
||||
|
||||
|
||||
function countCreatorsWithData(creatorDataID) {
|
||||
function countCreatorsWithData(creatorDataID, libraryID) {
|
||||
var sql = "SELECT COUNT(*) FROM creators WHERE creatorDataID=?";
|
||||
return Zotero.DB.valueQuery(sql, creatorDataID);
|
||||
var params = [creatorDataID];
|
||||
if (libraryID) {
|
||||
sql += " AND libraryID=?";
|
||||
params.push(libraryID);
|
||||
}
|
||||
return Zotero.DB.valueQuery(sql, params);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -14,20 +14,86 @@ Zotero.DataObjects = function (object, objectPlural, id, table) {
|
|||
this._ZDO_id = (id ? id : object) + 'ID';
|
||||
this._ZDO_table = table ? table : this._ZDO_objects;
|
||||
|
||||
// Certain object types don't have a libary and key and only use an id
|
||||
switch (object) {
|
||||
case 'relation':
|
||||
this._ZDO_idOnly = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
this._ZDO_idOnly = false;
|
||||
}
|
||||
|
||||
this._objectCache = {};
|
||||
this._reloadCache = true;
|
||||
|
||||
|
||||
this.makeLibraryKeyHash = function (libraryID, key) {
|
||||
var libraryID = libraryID ? libraryID : 0;
|
||||
return libraryID + '_' + key;
|
||||
}
|
||||
|
||||
|
||||
this.getLibraryKeyHash = function (obj) {
|
||||
return this.makeLibraryKeyHash(obj.libraryID, obj.key);
|
||||
}
|
||||
|
||||
|
||||
this.parseLibraryKeyHash = function (libraryKey) {
|
||||
var [libraryID, key] = libraryKey.split('_');
|
||||
libraryID = parseInt(libraryID);
|
||||
return {
|
||||
libraryID: libraryID ? libraryID : null,
|
||||
key: key
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves an object by its secondary lookup key
|
||||
* Retrieves an object of the current by its key
|
||||
*
|
||||
* @param string key Secondary lookup key
|
||||
* @return object Zotero data object, or FALSE if not found
|
||||
* @param {String} key
|
||||
* @return {Zotero.DataObject} Zotero data object, or FALSE if not found
|
||||
*/
|
||||
this.getByKey = function (key) {
|
||||
var sql = "SELECT " + this._ZDO_id + " FROM " + this._ZDO_table
|
||||
+ " WHERE key=?";
|
||||
var id = Zotero.DB.valueQuery(sql, key);
|
||||
if (arguments.length > 1) {
|
||||
throw ("getByKey() takes only one argument");
|
||||
}
|
||||
|
||||
Components.utils.reportError("Zotero." + this._ZDO_Objects
|
||||
+ ".getByKey() is deprecated -- use getByLibraryAndKey()");
|
||||
|
||||
return this.getByLibraryAndKey(null, key);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves an object by its libraryID and key
|
||||
*
|
||||
* @param {Integer|NULL} libraryID
|
||||
* @param {String} key
|
||||
* @return {Zotero.DataObject} Zotero data object, or FALSE if not found
|
||||
*/
|
||||
this.getByLibraryAndKey = function (libraryID, key) {
|
||||
var sql = "SELECT ROWID FROM " + this._ZDO_table + " WHERE ";
|
||||
var params = [];
|
||||
if (this._ZDO_idOnly) {
|
||||
sql += "ROWID=?";
|
||||
params.push(key);
|
||||
}
|
||||
else {
|
||||
sql += "libraryID";
|
||||
if (libraryID) {
|
||||
sql += "=? ";
|
||||
params.push(libraryID);
|
||||
}
|
||||
else {
|
||||
sql += " IS NULL ";
|
||||
}
|
||||
sql += "AND key=?";
|
||||
params.push(key);
|
||||
}
|
||||
var id = Zotero.DB.valueQuery(sql, params);
|
||||
if (!id) {
|
||||
return false;
|
||||
}
|
||||
|
@ -41,8 +107,7 @@ Zotero.DataObjects = function (object, objectPlural, id, table) {
|
|||
+ "Zotero." + this._ZDO_Objects + ".getOlder()")
|
||||
}
|
||||
|
||||
var sql = "SELECT " + this._ZDO_id + " FROM " + this._ZDO_table
|
||||
+ " WHERE dateModified<?";
|
||||
var sql = "SELECT ROWID FROM " + this._ZDO_table + " WHERE clientDateModified<?";
|
||||
return Zotero.DB.columnQuery(sql, Zotero.Date.dateToSQL(date, true));
|
||||
}
|
||||
|
||||
|
@ -53,9 +118,9 @@ Zotero.DataObjects = function (object, objectPlural, id, table) {
|
|||
+ "Zotero." + this._ZDO_Objects + ".getNewer()")
|
||||
}
|
||||
|
||||
var sql = "SELECT " + this._ZDO_id + " FROM " + this._ZDO_table;
|
||||
var sql = "SELECT ROWID FROM " + this._ZDO_table;
|
||||
if (date) {
|
||||
sql += " WHERE dateModified>?";
|
||||
sql += " WHERE clientDateModified>?";
|
||||
return Zotero.DB.columnQuery(sql, Zotero.Date.dateToSQL(date, true));
|
||||
}
|
||||
return Zotero.DB.columnQuery(sql);
|
||||
|
@ -75,6 +140,7 @@ Zotero.DataObjects = function (object, objectPlural, id, table) {
|
|||
var ids = Zotero.flattenArguments(arguments);
|
||||
Zotero.debug('Reloading ' + this._ZDO_objects + ' ' + ids);
|
||||
|
||||
/*
|
||||
// Reset cache keys to itemIDs stored in database using object keys
|
||||
var sql = "SELECT " + this._ZDO_id + " AS id, key FROM " + this._ZDO_table
|
||||
+ " WHERE " + this._ZDO_id + " IN ("
|
||||
|
@ -87,22 +153,32 @@ Zotero.DataObjects = function (object, objectPlural, id, table) {
|
|||
}
|
||||
var store = {};
|
||||
|
||||
Zotero.debug('==================');
|
||||
for (var id in this._objectCache) {
|
||||
Zotero.debug('id is ' + id);
|
||||
var obj = this._objectCache[id];
|
||||
//Zotero.debug(obj);
|
||||
var dbID = keyIDs[obj.key];
|
||||
Zotero.debug("DBID: " + dbID);
|
||||
if (!dbID || id == dbID) {
|
||||
Zotero.debug('continuing');
|
||||
continue;
|
||||
}
|
||||
Zotero.debug('Assigning ' + dbID + ' to store');
|
||||
store[dbID] = obj;
|
||||
Zotero.debug('deleting ' + id);
|
||||
delete this._objectCache[id];
|
||||
}
|
||||
Zotero.debug('------------------');
|
||||
for (var id in store) {
|
||||
Zotero.debug(id);
|
||||
if (this._objectCache[id]) {
|
||||
throw("Existing " + this._ZDO_object + " " + id
|
||||
+ " exists in cache in Zotero.DataObjects.reload()");
|
||||
}
|
||||
this._objectCache[id] = store[id];
|
||||
}
|
||||
*/
|
||||
|
||||
// If there's an internal reload hook, call it
|
||||
if (this._reload) {
|
||||
|
@ -119,22 +195,16 @@ Zotero.DataObjects = function (object, objectPlural, id, table) {
|
|||
this.reloadAll = function () {
|
||||
Zotero.debug("Reloading all " + this._ZDO_objects);
|
||||
|
||||
// Reset cache keys to itemIDs stored in database using object keys
|
||||
var sql = "SELECT " + this._ZDO_id + " AS id, key FROM " + this._ZDO_table;
|
||||
var rows = Zotero.DB.query(sql);
|
||||
// Remove objects not stored in database
|
||||
var sql = "SELECT ROWID FROM " + this._ZDO_table;
|
||||
var ids = Zotero.DB.columnQuery(sql);
|
||||
|
||||
var keyIDs = {};
|
||||
for each(var row in rows) {
|
||||
keyIDs[row.key] = row.id;
|
||||
for (var id in this._objectCache) {
|
||||
if (!ids || ids.indexOf(id) == -1) {
|
||||
delete this._objectCache[id];
|
||||
}
|
||||
}
|
||||
|
||||
var store = {};
|
||||
for each(var obj in this._objectCache) {
|
||||
store[keyIDs[obj.key]] = obj;
|
||||
}
|
||||
|
||||
this._objectCache = store;
|
||||
|
||||
// Reload data
|
||||
this._reloadCache = true;
|
||||
this._load();
|
||||
|
@ -166,11 +236,16 @@ Zotero.DataObjects = function (object, objectPlural, id, table) {
|
|||
var numDiffs = 0;
|
||||
|
||||
var subs = ['primary', 'fields'];
|
||||
var skipFields = ['collectionID', 'creatorID', 'itemID', 'searchID', 'tagID', 'libraryID', 'key'];
|
||||
|
||||
for each(var sub in subs) {
|
||||
diff[0][sub] = {};
|
||||
diff[1][sub] = {};
|
||||
for (var field in data1[sub]) {
|
||||
if (skipFields.indexOf(field) != -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!data1[sub][field] && !data2[sub][field]) {
|
||||
continue;
|
||||
}
|
||||
|
@ -192,6 +267,10 @@ Zotero.DataObjects = function (object, objectPlural, id, table) {
|
|||
|
||||
// DEBUG: some of this is probably redundant
|
||||
for (var field in data2[sub]) {
|
||||
if (skipFields.indexOf(field) != -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (diff[0][sub][field] != undefined) {
|
||||
continue;
|
||||
}
|
||||
|
@ -218,5 +297,39 @@ Zotero.DataObjects = function (object, objectPlural, id, table) {
|
|||
|
||||
return numDiffs;
|
||||
}
|
||||
|
||||
|
||||
this.isEditable = function (obj) {
|
||||
var libraryID = obj.libraryID;
|
||||
if (!libraryID) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var type = Zotero.Libraries.getType(libraryID);
|
||||
switch (type) {
|
||||
case 'group':
|
||||
var groupID = Zotero.Groups.getGroupIDFromLibraryID(libraryID);
|
||||
var group = Zotero.Groups.get(groupID);
|
||||
if (!group.editable) {
|
||||
return false;
|
||||
}
|
||||
if (obj.objectType == 'item' && obj.isAttachment()
|
||||
&& (obj.attachmentLinkMode == Zotero.Attachments.LINK_MODE_IMPORTED_URL ||
|
||||
obj.attachmentLinkMode == Zotero.Attachments.LINK_MODE_IMPORTED_FILE)) {
|
||||
return group.filesEditable;
|
||||
}
|
||||
return true;
|
||||
|
||||
default:
|
||||
throw ("Unsupported library type '" + type + "' in Zotero.DataObjects.isEditable()");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
this.editCheck = function (obj) {
|
||||
if (!Zotero.Sync.Server.syncInProgress && !this.isEditable(obj)) {
|
||||
throw ("Cannot edit " + this._ZDO_object + " in read-only Zotero library");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
470
chrome/content/zotero/xpcom/data/group.js
Normal file
470
chrome/content/zotero/xpcom/data/group.js
Normal file
|
@ -0,0 +1,470 @@
|
|||
/*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright (c) 2006 Center for History and New Media
|
||||
George Mason University, Fairfax, Virginia, USA
|
||||
http://chnm.gmu.edu
|
||||
|
||||
Licensed under the Educational Community License, Version 1.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.opensource.org/licenses/ecl1.php
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
|
||||
Zotero.Group = function () {
|
||||
if (arguments[0]) {
|
||||
throw ("Zotero.Group constructor doesn't take any parameters");
|
||||
}
|
||||
|
||||
this._init();
|
||||
}
|
||||
|
||||
|
||||
Zotero.Group.prototype._init = function () {
|
||||
this._id = null;
|
||||
this._libraryID = null;
|
||||
this._name = null;
|
||||
this._description = null;
|
||||
this._editable = null;
|
||||
this._filesEditable = null;
|
||||
|
||||
this._loaded = false;
|
||||
this._changed = false;
|
||||
this._hasCollections = null;
|
||||
}
|
||||
|
||||
|
||||
Zotero.Group.prototype.__defineGetter__('objectType', function () { return 'group'; });
|
||||
Zotero.Group.prototype.__defineGetter__('id', function () { return this._get('id'); });
|
||||
Zotero.Group.prototype.__defineSetter__('id', function (val) { this._set('id', val); });
|
||||
Zotero.Group.prototype.__defineGetter__('libraryID', function () { return this._get('libraryID'); });
|
||||
Zotero.Group.prototype.__defineSetter__('libraryID', function (val) { return this._set('libraryID', val); });
|
||||
Zotero.Group.prototype.__defineGetter__('name', function () { return this._get('name'); });
|
||||
Zotero.Group.prototype.__defineSetter__('name', function (val) { this._set('name', val); });
|
||||
Zotero.Group.prototype.__defineGetter__('description', function () { return this._get('description'); });
|
||||
Zotero.Group.prototype.__defineSetter__('description', function (val) { this._set('description', val); });
|
||||
Zotero.Group.prototype.__defineGetter__('editable', function () { return this._get('editable'); });
|
||||
Zotero.Group.prototype.__defineSetter__('editable', function (val) { this._set('editable', val); });
|
||||
Zotero.Group.prototype.__defineGetter__('filesEditable', function () { return this._get('filesEditable'); });
|
||||
Zotero.Group.prototype.__defineSetter__('filesEditable', function (val) { this._set('filesEditable', val); });
|
||||
|
||||
|
||||
Zotero.Group.prototype._get = function (field) {
|
||||
if (this._id && !this._loaded) {
|
||||
this.load();
|
||||
}
|
||||
return this['_' + field];
|
||||
}
|
||||
|
||||
|
||||
Zotero.Group.prototype._set = function (field, val) {
|
||||
switch (field) {
|
||||
case 'id':
|
||||
case 'libraryID':
|
||||
if (val == this['_' + field]) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._loaded) {
|
||||
throw ("Cannot set " + field + " after object is already loaded in Zotero.Group._set()");
|
||||
}
|
||||
//this._checkValue(field, val);
|
||||
this['_' + field] = val;
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.id) {
|
||||
if (!this._loaded) {
|
||||
this.load();
|
||||
}
|
||||
}
|
||||
else {
|
||||
this._loaded = true;
|
||||
}
|
||||
|
||||
if (this['_' + field] != val) {
|
||||
this._prepFieldChange(field);
|
||||
|
||||
switch (field) {
|
||||
default:
|
||||
this['_' + field] = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Build group from database
|
||||
*/
|
||||
Zotero.Group.prototype.load = function() {
|
||||
var id = this._id;
|
||||
|
||||
if (!id) {
|
||||
throw ("ID not set in Zotero.Group.load()");
|
||||
}
|
||||
|
||||
var sql = "SELECT G.* FROM groups G WHERE groupID=?";
|
||||
var data = Zotero.DB.rowQuery(sql, id);
|
||||
|
||||
this._loaded = true;
|
||||
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.loadFromRow(data);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Populate group data from a database row
|
||||
*/
|
||||
Zotero.Group.prototype.loadFromRow = function(row) {
|
||||
this._loaded = true;
|
||||
this._changed = false;
|
||||
this._hasCollections = null;
|
||||
|
||||
this._id = row.groupID;
|
||||
this._libraryID = row.libraryID;
|
||||
this._name = row.name;
|
||||
this._description = row.description;
|
||||
this._editable = row.editable;
|
||||
this._filesEditable = row.filesEditable;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if group exists in the database
|
||||
*
|
||||
* @return bool TRUE if the group exists, FALSE if not
|
||||
*/
|
||||
Zotero.Group.prototype.exists = function() {
|
||||
if (!this.id) {
|
||||
throw ('groupID not set in Zotero.Group.exists()');
|
||||
}
|
||||
|
||||
var sql = "SELECT COUNT(*) FROM groups WHERE groupID=?";
|
||||
return !!Zotero.DB.valueQuery(sql, this.id);
|
||||
}
|
||||
|
||||
|
||||
Zotero.Group.prototype.hasCollections = function () {
|
||||
if (this._hasCollections !== null) {
|
||||
return this._hasCollections;
|
||||
}
|
||||
|
||||
this._hasCollections = !!this.getCollections().length;
|
||||
return this._hasCollections;
|
||||
}
|
||||
|
||||
|
||||
Zotero.Group.prototype.clearCollectionsCache = function () {
|
||||
this._hasCollections = null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns collections of this group
|
||||
*
|
||||
* @param {Boolean} asIDs Return as collectionIDs
|
||||
* @return {Zotero.Collection[]} Array of Zotero.Collection instances
|
||||
*/
|
||||
Zotero.Group.prototype.getCollections = function (parent) {
|
||||
var sql = "SELECT collectionID FROM collections WHERE libraryID=? AND "
|
||||
+ "parentCollectionID " + (parent ? '=' + parent : 'IS NULL');
|
||||
var ids = Zotero.DB.columnQuery(sql, this.libraryID);
|
||||
Zotero.debug(ids);
|
||||
|
||||
// Return Zotero.Collection objects
|
||||
var objs = [];
|
||||
for each(var id in ids) {
|
||||
var col = Zotero.Collections.get(id);
|
||||
objs.push(col);
|
||||
}
|
||||
return objs;
|
||||
}
|
||||
|
||||
|
||||
Zotero.Group.prototype.hasItem = function (itemID) {
|
||||
var item = Zotero.Items.get(itemID);
|
||||
return item.libraryID == this.libraryID;
|
||||
}
|
||||
|
||||
|
||||
Zotero.Group.prototype.save = function () {
|
||||
if (!this.id) {
|
||||
throw ("ID not set in Zotero.Group.save()");
|
||||
}
|
||||
|
||||
if (!this.libraryID) {
|
||||
throw ("libraryID not set in Zotero.Group.save()");
|
||||
}
|
||||
|
||||
if (!this._changed) {
|
||||
Zotero.debug("Group " + this.id + " has not changed");
|
||||
return false;
|
||||
}
|
||||
|
||||
Zotero.DB.beginTransaction();
|
||||
|
||||
var isNew = !this.exists();
|
||||
|
||||
try {
|
||||
Zotero.debug("Saving group " + this.id);
|
||||
|
||||
var columns = [
|
||||
'groupID',
|
||||
'libraryID',
|
||||
'name',
|
||||
'description',
|
||||
'editable',
|
||||
'filesEditable'
|
||||
];
|
||||
var placeholders = ['?', '?', '?', '?', '?', '?'];
|
||||
var sqlValues = [
|
||||
this.id,
|
||||
this.libraryID,
|
||||
this.name,
|
||||
this.description,
|
||||
this.editable ? 1 : 0,
|
||||
this.filesEditable ? 1 : 0
|
||||
];
|
||||
|
||||
if (isNew) {
|
||||
if (!Zotero.Libraries.exists(this.libraryID)) {
|
||||
Zotero.Libraries.add(this.libraryID, 'group');
|
||||
}
|
||||
|
||||
var sql = "INSERT INTO groups (" + columns.join(', ') + ") "
|
||||
+ "VALUES (" + placeholders.join(', ') + ")";
|
||||
Zotero.DB.query(sql, sqlValues);
|
||||
}
|
||||
else {
|
||||
columns.shift();
|
||||
sqlValues.shift();
|
||||
|
||||
var sql = "UPDATE groups SET "
|
||||
+ columns.map(function (val) val + '=?').join(', ')
|
||||
+ " WHERE groupID=?";
|
||||
sqlValues.push(this.id);
|
||||
Zotero.DB.query(sql, sqlValues);
|
||||
}
|
||||
|
||||
Zotero.DB.commitTransaction();
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.DB.rollbackTransaction();
|
||||
throw (e);
|
||||
}
|
||||
|
||||
//Zotero.Groups.reload(this.id);
|
||||
|
||||
Zotero.Notifier.trigger('add', 'group', this.id);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deletes group and all descendant objects
|
||||
**/
|
||||
Zotero.Group.prototype.erase = function(deleteItems) {
|
||||
Zotero.DB.beginTransaction();
|
||||
|
||||
var sql, ids, obj;
|
||||
|
||||
// Delete items
|
||||
sql = "SELECT itemID FROM items WHERE libraryID=?";
|
||||
ids = Zotero.DB.columnQuery(sql, this.libraryID);
|
||||
Zotero.Items.erase(ids);
|
||||
|
||||
// Delete collections
|
||||
sql = "SELECT collectionID FROM collections WHERE libraryID=?";
|
||||
ids = Zotero.DB.columnQuery(sql, this.libraryID);
|
||||
for each(var id in ids) {
|
||||
obj = Zotero.Collections.get(id);
|
||||
// Subcollections might've already been deleted
|
||||
if (obj) {
|
||||
obj.erase();
|
||||
}
|
||||
}
|
||||
|
||||
// Delete creators
|
||||
sql = "SELECT creatorID FROM creators WHERE libraryID=?";
|
||||
ids = Zotero.DB.columnQuery(sql, this.libraryID);
|
||||
for each(var id in ids) {
|
||||
obj = Zotero.Creators.get(id);
|
||||
obj.erase();
|
||||
}
|
||||
|
||||
// Delete saved searches
|
||||
sql = "SELECT savedSearchID FROM savedSearches WHERE libraryID=?";
|
||||
ids = Zotero.DB.columnQuery(sql, this.libraryID);
|
||||
for each(var id in ids) {
|
||||
obj = Zotero.Searches.get(id);
|
||||
obj.erase();
|
||||
}
|
||||
|
||||
// Delete tags
|
||||
sql = "SELECT tagID FROM tags WHERE libraryID=?";
|
||||
ids = Zotero.DB.columnQuery(sql, this.libraryID);
|
||||
Zotero.Tags.erase(ids);
|
||||
|
||||
// Delete delete log entries
|
||||
sql = "DELETE FROM syncDeleteLog WHERE libraryID=?";
|
||||
Zotero.DB.query(sql, this.libraryID);
|
||||
|
||||
// Delete group
|
||||
sql = "DELETE FROM groups WHERE groupID=?";
|
||||
ids = Zotero.DB.query(sql, this.id)
|
||||
|
||||
Zotero.purgeDataObjects();
|
||||
|
||||
var notifierData = {};
|
||||
notifierData[this.id] = this.serialize();
|
||||
|
||||
Zotero.DB.commitTransaction();
|
||||
|
||||
Zotero.Notifier.trigger('delete', 'group', this.id, notifierData);
|
||||
}
|
||||
|
||||
|
||||
Zotero.Group.prototype.serialize = function() {
|
||||
var obj = {
|
||||
primary: {
|
||||
groupID: this.id,
|
||||
libraryID: this.libraryID
|
||||
},
|
||||
fields: {
|
||||
name: this.name,
|
||||
description: this.description,
|
||||
editable: this.editable,
|
||||
filesEditable: this.filesEditable
|
||||
}
|
||||
};
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns an array of descendent groups and items
|
||||
*
|
||||
* @param bool recursive Descend into subgroups
|
||||
* @param bool nested Return multidimensional array with 'children'
|
||||
* nodes instead of flat array
|
||||
* @param string type 'item', 'group', or FALSE for both
|
||||
* @return {Object[]} Array of objects with 'id', 'key',
|
||||
* 'type' ('item' or 'group'), 'parent',
|
||||
* and, if group, 'name' and the nesting 'level'
|
||||
*/
|
||||
Zotero.Group.prototype.getChildren = function(recursive, nested, type, level) {
|
||||
if (!this.id) {
|
||||
throw ('Zotero.Group.getChildren() cannot be called on an unsaved item');
|
||||
}
|
||||
|
||||
var toReturn = [];
|
||||
|
||||
if (!level) {
|
||||
level = 1;
|
||||
}
|
||||
|
||||
// 0 == group
|
||||
// 1 == item
|
||||
var children = Zotero.DB.query('SELECT groupID AS id, '
|
||||
+ "0 AS type, groupName AS groupName, key "
|
||||
+ 'FROM groups WHERE parentGroupID=?1'
|
||||
+ ' UNION SELECT itemID AS id, 1 AS type, NULL AS groupName, key '
|
||||
+ 'FROM groupItems JOIN items USING (itemID) WHERE groupID=?1', this.id);
|
||||
|
||||
if (type) {
|
||||
switch (type) {
|
||||
case 'item':
|
||||
case 'group':
|
||||
break;
|
||||
default:
|
||||
throw ("Invalid type '" + type + "' in Group.getChildren()");
|
||||
}
|
||||
}
|
||||
|
||||
for(var i=0, len=children.length; i<len; i++) {
|
||||
// This seems to not work without parseInt() even though
|
||||
// typeof children[i]['type'] == 'number' and
|
||||
// children[i]['type'] === parseInt(children[i]['type']),
|
||||
// which sure seems like a bug to me
|
||||
switch (parseInt(children[i].type)) {
|
||||
case 0:
|
||||
if (!type || type=='group') {
|
||||
toReturn.push({
|
||||
id: children[i].id,
|
||||
name: children[i].groupName,
|
||||
key: children[i].key,
|
||||
type: 'group',
|
||||
level: level,
|
||||
parent: this.id
|
||||
});
|
||||
}
|
||||
|
||||
if (recursive) {
|
||||
var descendents =
|
||||
Zotero.Groups.get(children[i].id).
|
||||
getChildren(true, nested, type, level+1);
|
||||
|
||||
if (nested) {
|
||||
toReturn[toReturn.length-1].children = descendents;
|
||||
}
|
||||
else {
|
||||
for (var j=0, len2=descendents.length; j<len2; j++) {
|
||||
toReturn.push(descendents[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (!type || type=='item') {
|
||||
toReturn.push({
|
||||
id: children[i].id,
|
||||
key: children[i].key,
|
||||
type: 'item',
|
||||
parent: this.id
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Alias for the recursive mode of getChildren()
|
||||
*/
|
||||
Zotero.Group.prototype.getDescendents = function(nested, type, level) {
|
||||
return this.getChildren(true, nested, type);
|
||||
}
|
||||
|
||||
|
||||
Zotero.Group.prototype._prepFieldChange = function (field) {
|
||||
if (!this._changed) {
|
||||
this._changed = {};
|
||||
}
|
||||
this._changed[field] = true;
|
||||
|
||||
// Save a copy of the data before changing
|
||||
// TODO: only save previous data if group exists
|
||||
if (this.id && this.exists() && !this._previousData) {
|
||||
//this._previousData = this.serialize();
|
||||
}
|
||||
}
|
58
chrome/content/zotero/xpcom/data/groups.js
Normal file
58
chrome/content/zotero/xpcom/data/groups.js
Normal file
|
@ -0,0 +1,58 @@
|
|||
Zotero.Groups = new function () {
|
||||
this.__defineGetter__('addGroupURL', function () ZOTERO_CONFIG.WWW_BASE_URL + 'groups/new/');
|
||||
|
||||
this.get = function (id) {
|
||||
if (!id) {
|
||||
throw ("groupID not provided in Zotero.Groups.get()");
|
||||
}
|
||||
var group = new Zotero.Group;
|
||||
group.id = id;
|
||||
if (!group.exists()) {
|
||||
return false;
|
||||
}
|
||||
return group;
|
||||
}
|
||||
|
||||
|
||||
this.getAll = function () {
|
||||
var groups = [];
|
||||
var sql = "SELECT groupID FROM groups";
|
||||
var groupIDs = Zotero.DB.columnQuery(sql);
|
||||
if (!groupIDs) {
|
||||
return groups;
|
||||
}
|
||||
for each(var groupID in groupIDs) {
|
||||
var group = this.get(groupID);
|
||||
groups.push(group);
|
||||
}
|
||||
return groups;
|
||||
}
|
||||
|
||||
|
||||
this.getByLibraryID = function (libraryID) {
|
||||
var groupID = this.getGroupIDFromLibraryID(libraryID);
|
||||
return this.get(groupID);
|
||||
}
|
||||
|
||||
|
||||
this.getGroupIDFromLibraryID = function (libraryID) {
|
||||
var sql = "SELECT groupID FROM groups WHERE libraryID=?";
|
||||
var groupID = Zotero.DB.valueQuery(sql, libraryID);
|
||||
if (!groupID) {
|
||||
throw ("Group with libraryID " + libraryID + " does not exist "
|
||||
+ "in Zotero.Groups.getGroupIDFromLibraryID()");
|
||||
}
|
||||
return groupID;
|
||||
}
|
||||
|
||||
|
||||
this.getLibraryIDFromGroupID = function (groupID) {
|
||||
var sql = "SELECT libraryID FROM groups WHERE groupID=?";
|
||||
var libraryID = Zotero.DB.valueQuery(sql, groupID);
|
||||
if (!libraryID) {
|
||||
throw ("Group with groupID " + groupID + " does not exist "
|
||||
+ "in Zotero.Groups.getLibraryIDFromGroupID()");
|
||||
}
|
||||
return libraryID;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -38,9 +38,29 @@ Zotero.Items = new function() {
|
|||
this.getFirstCreatorSQL = getFirstCreatorSQL;
|
||||
this.getSortTitle = getSortTitle;
|
||||
|
||||
this.__defineGetter__('primaryFields', function () {
|
||||
if (!_primaryFields.length) {
|
||||
_primaryFields = Zotero.DB.getColumns('items');
|
||||
_primaryFields.splice(_primaryFields.indexOf('clientDateModified'), 1);
|
||||
_primaryFields = _primaryFields.concat(
|
||||
['firstCreator', 'numNotes', 'numAttachments']
|
||||
);
|
||||
}
|
||||
|
||||
// Make a copy of array
|
||||
var fields = [];
|
||||
for each(var field in _primaryFields) {
|
||||
fields.push(field);
|
||||
}
|
||||
return fields;
|
||||
});
|
||||
|
||||
this.__defineGetter__('linkedItemPredicate', function () "owl:sameAs");
|
||||
|
||||
// Private members
|
||||
var _cachedFields = [];
|
||||
var _firstCreatorSQL = '';
|
||||
var _primaryFields = [];
|
||||
|
||||
|
||||
/*
|
||||
|
@ -173,7 +193,7 @@ Zotero.Items = new function() {
|
|||
* var item = Zotero.Items.add('book', data);
|
||||
*/
|
||||
function add(itemTypeOrID, data) {
|
||||
var item = new Zotero.Item(false, itemTypeOrID);
|
||||
var item = new Zotero.Item(itemTypeOrID);
|
||||
for (var field in data) {
|
||||
if (field == 'creators') {
|
||||
var i = 0;
|
||||
|
@ -212,6 +232,11 @@ Zotero.Items = new function() {
|
|||
}
|
||||
|
||||
|
||||
this.isPrimaryField = function (field) {
|
||||
return this.primaryFields.indexOf(field) != -1;
|
||||
}
|
||||
|
||||
|
||||
function cacheFields(fields, items) {
|
||||
if (items && items.length == 0) {
|
||||
return;
|
||||
|
@ -236,7 +261,7 @@ Zotero.Items = new function() {
|
|||
|
||||
_cachedFields.push(field);
|
||||
|
||||
if (Zotero.Item.prototype.isPrimaryField(field)) {
|
||||
if (this.isPrimaryField(field)) {
|
||||
primaryFields.push(field);
|
||||
}
|
||||
else {
|
||||
|
|
44
chrome/content/zotero/xpcom/data/libraries.js
Normal file
44
chrome/content/zotero/xpcom/data/libraries.js
Normal file
|
@ -0,0 +1,44 @@
|
|||
Zotero.Libraries = new function () {
|
||||
this.exists = function (libraryID) {
|
||||
var sql = "SELECT COUNT(*) FROM libraries WHERE libraryID=?";
|
||||
return !!Zotero.DB.valueQuery(sql, [libraryID]);
|
||||
}
|
||||
|
||||
|
||||
this.add = function (libraryID, type) {
|
||||
switch (type) {
|
||||
case 'group':
|
||||
break;
|
||||
|
||||
default:
|
||||
throw ("Invalid library type '" + type + "' in Zotero.Libraries.add()");
|
||||
}
|
||||
|
||||
var sql = "INSERT INTO libraries (libraryID, libraryType) VALUES (?, ?)";
|
||||
Zotero.DB.query(sql, [libraryID, type]);
|
||||
}
|
||||
|
||||
|
||||
this.getName = function (libraryID) {
|
||||
var type = this.getType(libraryID);
|
||||
switch (type) {
|
||||
case 'group':
|
||||
var groupID = Zotero.Groups.getGroupIDFromLibraryID(libraryID);
|
||||
var group = Zotero.Groups.get(groupID);
|
||||
return group.name;
|
||||
|
||||
default:
|
||||
throw ("Unsupported library type '" + type + "' in Zotero.Libraries.getName()");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
this.getType = function (libraryID) {
|
||||
var sql = "SELECT libraryType FROM libraries WHERE libraryID=?";
|
||||
var libraryType = Zotero.DB.valueQuery(sql, libraryID);
|
||||
if (!libraryType) {
|
||||
throw ("Library " + libraryID + " does not exist in Zotero.Libraries.getType()");
|
||||
}
|
||||
return libraryType;
|
||||
}
|
||||
}
|
149
chrome/content/zotero/xpcom/data/relation.js
Normal file
149
chrome/content/zotero/xpcom/data/relation.js
Normal file
|
@ -0,0 +1,149 @@
|
|||
Zotero.Relation = function () {
|
||||
this._id = null;
|
||||
this._libraryID = null;
|
||||
this._subject = null;
|
||||
this._predicate = null;
|
||||
this._object = null;
|
||||
this._clientDateModified = null;
|
||||
|
||||
this._loaded = false;
|
||||
}
|
||||
|
||||
Zotero.Relation.prototype.__defineGetter__('objectType', function () 'relation');
|
||||
Zotero.Relation.prototype.__defineGetter__('id', function () this._id);
|
||||
Zotero.Relation.prototype.__defineSetter__('id', function (val) { this._set('id', val); });
|
||||
Zotero.Relation.prototype.__defineGetter__('libraryID', function () this._get('libraryID'));
|
||||
Zotero.Relation.prototype.__defineSetter__('libraryID', function (val) { return this._set('libraryID', val); });
|
||||
Zotero.Relation.prototype.__defineGetter__('key', function () this._id);
|
||||
//Zotero.Relation.prototype.__defineSetter__('key', function (val) { this._set('key', val) });
|
||||
Zotero.Relation.prototype.__defineGetter__('dateModified', function () this._get('dateModified'));
|
||||
Zotero.Relation.prototype.__defineGetter__('subject', function () this._get('subject'));
|
||||
Zotero.Relation.prototype.__defineSetter__('subject', function (val) { this._set('subject', val); });
|
||||
Zotero.Relation.prototype.__defineGetter__('predicate', function () this._get('predicate'));
|
||||
Zotero.Relation.prototype.__defineSetter__('predicate', function (val) { this._set('predicate', val); });
|
||||
Zotero.Relation.prototype.__defineGetter__('object', function () this._get('object'));
|
||||
Zotero.Relation.prototype.__defineSetter__('object', function (val) { this._set('object', val); });
|
||||
|
||||
|
||||
Zotero.Relation.prototype._get = function (field) {
|
||||
if (this._id && !this._loaded) {
|
||||
this.load();
|
||||
}
|
||||
return this['_' + field];
|
||||
}
|
||||
|
||||
|
||||
Zotero.Relation.prototype._set = function (field, val) {
|
||||
switch (field) {
|
||||
case 'id':
|
||||
case 'libraryID':
|
||||
if (field == 'libraryID' && !val) {
|
||||
throw ("libraryID cannot be empty in Zotero.Relation._set()");
|
||||
}
|
||||
|
||||
if (val == this['_' + field]) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._loaded) {
|
||||
throw ("Cannot set " + field + " after object is already loaded in Zotero.Relation._set()");
|
||||
}
|
||||
this['_' + field] = val;
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.id) {
|
||||
if (!this._loaded) {
|
||||
this.load();
|
||||
}
|
||||
}
|
||||
else {
|
||||
this._loaded = true;
|
||||
}
|
||||
|
||||
if (this['_' + field] != val) {
|
||||
//this._prepFieldChange(field);
|
||||
|
||||
switch (field) {
|
||||
default:
|
||||
this['_' + field] = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if search exists in the database
|
||||
*
|
||||
* @return bool TRUE if the relation exists, FALSE if not
|
||||
*/
|
||||
Zotero.Relation.prototype.exists = function () {
|
||||
if (this.id) {
|
||||
var sql = "SELECT COUNT(*) FROM relations WHERE relationID=?";
|
||||
return !!Zotero_DB::valueQuery(sql, this.id);
|
||||
}
|
||||
|
||||
if (this.libraryID && this.subject && this.predicate && this.object) {
|
||||
var sql = "SELECT COUNT(*) FROM relations WHERE libraryID=? AND "
|
||||
+ "subject=? AND predicate=? AND object=?";
|
||||
var params = [this.libraryID, this.subject, this.predicate, this.object];
|
||||
return !!Zotero.DB.valueQuery(sql, params);
|
||||
}
|
||||
|
||||
throw ("ID or libraryID/subject/predicate/object not set in Zotero.Relation.exists()");
|
||||
}
|
||||
|
||||
|
||||
|
||||
Zotero.Relation.prototype.load = function () {
|
||||
var id = this._id;
|
||||
if (!id) {
|
||||
throw ("ID not set in Zotero.Relation.load()");
|
||||
}
|
||||
|
||||
var sql = "SELECT * FROM relations WHERE ROWID=?";
|
||||
var row = Zotero.DB.rowQuery(sql, id);
|
||||
if (!row) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._libraryID = row.libraryID;
|
||||
this._subject = row.subject;
|
||||
this._predicate = row.predicate;
|
||||
this._object = row.object;
|
||||
this._clientDateModified = row.clientDateModified;
|
||||
this._loaded = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Zotero.Relation.prototype.save = function () {
|
||||
if (this.id) {
|
||||
throw ("Existing relations cannot currently be altered in Zotero.Relation.save()");
|
||||
}
|
||||
|
||||
if (!this.subject) {
|
||||
throw ("Missing subject in Zotero.Relation.save()");
|
||||
}
|
||||
if (!this.predicate) {
|
||||
throw ("Missing predicate in Zotero.Relation.save()");
|
||||
}
|
||||
if (!this.object) {
|
||||
throw ("Missing object in Zotero.Relation.save()");
|
||||
}
|
||||
|
||||
var sql = "INSERT INTO relations (libraryID, subject, predicate, object) VALUES (?, ?, ?, ?)";
|
||||
var insertID = Zotero.DB.query(sql, [this.libraryID, this.subject, this.predicate, this.object]);
|
||||
|
||||
return insertID;
|
||||
}
|
||||
|
||||
|
||||
Zotero.Relation.prototype.toXML = function () {
|
||||
var xml = <relation/>;
|
||||
xml.subject = this.subject;
|
||||
xml.predicate = this.predicate;
|
||||
xml.object = this.object;
|
||||
return xml;
|
||||
}
|
149
chrome/content/zotero/xpcom/data/relations.js
Normal file
149
chrome/content/zotero/xpcom/data/relations.js
Normal file
|
@ -0,0 +1,149 @@
|
|||
Zotero.Relations = new function () {
|
||||
Zotero.DataObjects.apply(this, ['relation']);
|
||||
this.constructor.prototype = new Zotero.DataObjects();
|
||||
|
||||
var _namespaces = {
|
||||
owl: 'http://www.w3.org/2002/07/owl#'
|
||||
};
|
||||
|
||||
|
||||
this.get = function (id) {
|
||||
if (typeof id != 'number') {
|
||||
throw ("id '" + id + "' must be an integer in Zotero.Relations.get()");
|
||||
}
|
||||
|
||||
var relation = new Zotero.Relation;
|
||||
relation.id = id;
|
||||
return relation;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return {Object[]}
|
||||
*/
|
||||
this.getByURIs = function (subject, predicate, object) {
|
||||
predicate = _getPrefixAndValue(predicate).join(':');
|
||||
if (!subject && !predicate && !object) {
|
||||
throw ("No values provided in Zotero.Relations.get()");
|
||||
}
|
||||
|
||||
var sql = "SELECT ROWID FROM relations WHERE 1";
|
||||
var params = [];
|
||||
if (subject) {
|
||||
sql += " AND subject=?";
|
||||
params.push(subject);
|
||||
}
|
||||
if (predicate) {
|
||||
sql += " AND predicate=?";
|
||||
params.push(predicate);
|
||||
}
|
||||
if (object) {
|
||||
sql += " AND object=?";
|
||||
params.push(object);
|
||||
}
|
||||
var rows = Zotero.DB.columnQuery(sql, params);
|
||||
if (!rows) {
|
||||
return [];
|
||||
}
|
||||
|
||||
var toReturn = [];
|
||||
for each(var id in rows) {
|
||||
var relation = new Zotero.Relation;
|
||||
relation.id = id;
|
||||
toReturn.push(relation);
|
||||
}
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
|
||||
this.getSubject = function (subject, predicate, object) {
|
||||
var subjects = [];
|
||||
var relations = this.getByURIs(subject, predicate, object);
|
||||
for each(var relation in relations) {
|
||||
subjects.push(relation.subject);
|
||||
}
|
||||
return subjects;
|
||||
}
|
||||
|
||||
|
||||
this.getObject = function (subject, predicate, object) {
|
||||
var objects = [];
|
||||
var relations = this.getByURIs(subject, predicate, object);
|
||||
for each(var relation in relations) {
|
||||
objects.push(relation.object);
|
||||
}
|
||||
return objects;
|
||||
}
|
||||
|
||||
|
||||
this.add = function (libraryID, subject, predicate, object) {
|
||||
predicate = _getPrefixAndValue(predicate).join(':');
|
||||
|
||||
var relation = new Zotero.Relation;
|
||||
if (libraryID) {
|
||||
relation.libraryID = parseInt(libraryID);
|
||||
}
|
||||
else {
|
||||
libraryID = Zotero.libraryID;
|
||||
if (!libraryID) {
|
||||
libraryID = Zotero.getLocalUserKey(true);
|
||||
}
|
||||
relation.libraryID = parseInt(libraryID);
|
||||
}
|
||||
relation.subject = subject;
|
||||
relation.predicate = predicate;
|
||||
relation.object = object;
|
||||
relation.save();
|
||||
}
|
||||
|
||||
|
||||
this.erase = function (id) {
|
||||
Zotero.DB.beginTransaction();
|
||||
|
||||
var sql = "DELETE FROM relations WHERE ROWID=?";
|
||||
Zotero.DB.query(sql, [id]);
|
||||
|
||||
// TODO: log to syncDeleteLog
|
||||
|
||||
Zotero.DB.commitTransaction();
|
||||
}
|
||||
|
||||
|
||||
this.xmlToRelation = function (xml) {
|
||||
var relation = new Zotero.Relation;
|
||||
var libraryID = xml.@libraryID.toString();
|
||||
if (libraryID) {
|
||||
relation.libraryID = parseInt(libraryID);
|
||||
}
|
||||
else {
|
||||
libraryID = Zotero.libraryID;
|
||||
if (!libraryID) {
|
||||
libraryID = Zotero.getLocalUserKey(true);
|
||||
}
|
||||
relation.libraryID = parseInt(libraryID);
|
||||
}
|
||||
relation.subject = xml.subject.toString();
|
||||
relation.predicate = xml.predicate.toString();
|
||||
relation.object = xml.object.toString();
|
||||
return relation;
|
||||
}
|
||||
|
||||
|
||||
function _getPrefixAndValue(uri) {
|
||||
var [prefix, value] = uri.split(':');
|
||||
if (prefix && value) {
|
||||
if (!_namespaces[prefix]) {
|
||||
throw ("Invalid prefix '" + prefix + "' in Zotero.Relations.add()");
|
||||
}
|
||||
return [prefix, value];
|
||||
}
|
||||
|
||||
for (var prefix in namespaces) {
|
||||
if (uri.indexOf(namespaces[prefix]) == 0) {
|
||||
var value = uri.substr(namespaces[prefix].length - 1)
|
||||
return [prefix, value];
|
||||
}
|
||||
}
|
||||
throw ("Invalid namespace in URI '" + uri + "' in Zotero.Relations._getPrefixAndValue()");
|
||||
}
|
||||
}
|
|
@ -21,18 +21,23 @@
|
|||
*/
|
||||
|
||||
|
||||
Zotero.Tag = function(tagID) {
|
||||
this._tagID = tagID ? tagID : null;
|
||||
Zotero.Tag = function () {
|
||||
if (arguments[0]) {
|
||||
throw ("Zotero.Tag constructor doesn't take any parameters");
|
||||
}
|
||||
|
||||
this._init();
|
||||
}
|
||||
|
||||
Zotero.Tag.prototype._init = function () {
|
||||
// Public members for access by public methods -- do not access directly
|
||||
this._id = null;
|
||||
this._libraryID = null
|
||||
this._key = null;
|
||||
this._name = null;
|
||||
this._type = null;
|
||||
this._dateAdded = null;
|
||||
this._dateModified = null;
|
||||
this._key = null;
|
||||
|
||||
this._loaded = false;
|
||||
this._changed = false;
|
||||
|
@ -43,9 +48,13 @@ Zotero.Tag.prototype._init = function () {
|
|||
}
|
||||
|
||||
|
||||
Zotero.Tag.prototype.__defineGetter__('id', function () { return this._tagID; });
|
||||
|
||||
Zotero.Tag.prototype.__defineSetter__('tagID', function (val) { this._set('tagID', val); });
|
||||
Zotero.Tag.prototype.__defineGetter__('objectType', function () { return 'tag'; });
|
||||
Zotero.Tag.prototype.__defineGetter__('id', function () { return this._get('id'); });
|
||||
Zotero.Tag.prototype.__defineSetter__('id', function (val) { this._set('id', val); });
|
||||
Zotero.Tag.prototype.__defineGetter__('libraryID', function () { return this._get('libraryID'); });
|
||||
Zotero.Tag.prototype.__defineSetter__('libraryID', function (val) { return this._set('libraryID', val); });
|
||||
Zotero.Tag.prototype.__defineGetter__('key', function () { return this._get('key'); });
|
||||
Zotero.Tag.prototype.__defineSetter__('key', function (val) { this._set('key', val) });
|
||||
Zotero.Tag.prototype.__defineGetter__('name', function () { return this._get('name'); });
|
||||
Zotero.Tag.prototype.__defineSetter__('name', function (val) { this._set('name', val); });
|
||||
Zotero.Tag.prototype.__defineGetter__('type', function () { return this._get('type'); });
|
||||
|
@ -55,13 +64,12 @@ Zotero.Tag.prototype.__defineSetter__('dateAdded', function (val) { this._set('d
|
|||
Zotero.Tag.prototype.__defineGetter__('dateModified', function () { return this._get('dateModified'); });
|
||||
Zotero.Tag.prototype.__defineSetter__('dateModified', function (val) { this._set('dateModified', val); });
|
||||
Zotero.Tag.prototype.__defineGetter__('key', function () { return this._get('key'); });
|
||||
Zotero.Tag.prototype.__defineSetter__('key', function (val) { this._set('key', val); });
|
||||
|
||||
Zotero.Tag.prototype.__defineSetter__('linkedItems', function (arr) { this._setLinkedItems(arr); });
|
||||
|
||||
|
||||
Zotero.Tag.prototype._get = function (field) {
|
||||
if (this.id && !this._loaded) {
|
||||
if ((this._id || this._key) && !this._loaded) {
|
||||
this.load();
|
||||
}
|
||||
return this['_' + field];
|
||||
|
@ -69,17 +77,27 @@ Zotero.Tag.prototype._get = function (field) {
|
|||
|
||||
|
||||
Zotero.Tag.prototype._set = function (field, val) {
|
||||
if (field == 'name') {
|
||||
val = Zotero.Utilities.prototype.trim(val);
|
||||
}
|
||||
|
||||
switch (field) {
|
||||
case 'id': // set using constructor
|
||||
//case 'tagID': // set using constructor
|
||||
throw ("Invalid field '" + field + "' in Zotero.Tag.set()");
|
||||
case 'id':
|
||||
case 'libraryID':
|
||||
case 'key':
|
||||
if (val == this['_' + field]) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._loaded) {
|
||||
throw ("Cannot set " + field + " after object is already loaded in Zotero.Tag._set()");
|
||||
}
|
||||
//this._checkValue(field, val);
|
||||
this['_' + field] = val;
|
||||
return;
|
||||
|
||||
case 'name':
|
||||
val = Zotero.Utilities.prototype.trim(val);
|
||||
break;
|
||||
}
|
||||
|
||||
if (this.id) {
|
||||
if (this.id || this.key) {
|
||||
if (!this._loaded) {
|
||||
this.load();
|
||||
}
|
||||
|
@ -118,14 +136,38 @@ Zotero.Tag.prototype.exists = function() {
|
|||
* Build tag from database
|
||||
*/
|
||||
Zotero.Tag.prototype.load = function() {
|
||||
Zotero.debug("Loading data for tag " + this.id + " in Zotero.Tag.load()");
|
||||
var id = this._id;
|
||||
var key = this._key;
|
||||
var libraryID = this._libraryID;
|
||||
var desc = id ? id : libraryID + "/" + key;
|
||||
|
||||
if (!this.id) {
|
||||
throw ("tagID not set in Zotero.Tag.load()");
|
||||
Zotero.debug("Loading data for tag " + desc + " in Zotero.Tag.load()");
|
||||
|
||||
if (!id && !key) {
|
||||
throw ("ID or key not set in Zotero.Tag.load()");
|
||||
}
|
||||
|
||||
var sql = "SELECT name, type, dateAdded, dateModified, key FROM tags WHERE tagID=?";
|
||||
var row = Zotero.DB.rowQuery(sql, this.id);
|
||||
var sql = "SELECT * FROM tags WHERE ";
|
||||
if (id) {
|
||||
sql += "tagID=?";
|
||||
var params = id;
|
||||
}
|
||||
else {
|
||||
sql += "key=?";
|
||||
var params = [key];
|
||||
if (libraryID) {
|
||||
sql += " AND libraryID=?";
|
||||
params.push(libraryID);
|
||||
}
|
||||
else {
|
||||
sql += " AND libraryID IS NULL";
|
||||
}
|
||||
}
|
||||
var row = Zotero.DB.rowQuery(sql, params);
|
||||
|
||||
if (!row) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.loadFromRow(row);
|
||||
return true;
|
||||
|
@ -136,6 +178,18 @@ Zotero.Tag.prototype.loadFromRow = function (row) {
|
|||
this._init();
|
||||
for (var col in row) {
|
||||
//Zotero.debug("Setting field '" + col + "' to '" + row[col] + "' for tag " + this.id);
|
||||
switch (col) {
|
||||
case 'clientDateModified':
|
||||
continue;
|
||||
|
||||
case 'tagID':
|
||||
this._id = row[col];
|
||||
continue;
|
||||
|
||||
case 'libraryID':
|
||||
this['_' + col] = row[col] ? row[col] : null;
|
||||
continue;
|
||||
}
|
||||
this['_' + col] = (!row[col] && row[col] !== 0) ? '' : row[col];
|
||||
}
|
||||
this._loaded = true;
|
||||
|
@ -220,12 +274,15 @@ Zotero.Tag.prototype.removeItem = function (itemID) {
|
|||
|
||||
|
||||
Zotero.Tag.prototype.save = function (full) {
|
||||
Zotero.Tags.editCheck(this);
|
||||
|
||||
// Default to manual tag
|
||||
if (!this.type) {
|
||||
this.type = 0;
|
||||
}
|
||||
|
||||
if (this.type != 0 && this.type != 1) {
|
||||
Zotero.debug(this);
|
||||
throw ('Invalid tag type ' + this.type + ' for tag ' + this.id + ' in Zotero.Tag.save()');
|
||||
}
|
||||
|
||||
|
@ -241,34 +298,6 @@ Zotero.Tag.prototype.save = function (full) {
|
|||
|
||||
Zotero.DB.beginTransaction();
|
||||
|
||||
// ID change
|
||||
if (this._changed.tagID) {
|
||||
var oldID = this._previousData.primary.tagID;
|
||||
var params = [this.id, oldID];
|
||||
|
||||
Zotero.debug("Changing tagID " + oldID + " to " + this.id);
|
||||
|
||||
var row = Zotero.DB.rowQuery("SELECT * FROM tags WHERE tagID=?", oldID);
|
||||
|
||||
// Set type on old row to -1, since there's a UNIQUE on name/type
|
||||
Zotero.DB.query("UPDATE tags SET type=-1 WHERE tagID=?", oldID);
|
||||
|
||||
// Add a new row so we can update the old rows despite FK checks
|
||||
// Use temp key due to UNIQUE constraint on key column
|
||||
Zotero.DB.query("INSERT INTO tags VALUES (?, ?, ?, ?, ?, ?)",
|
||||
[this.id, row.name, row.type, row.dateAdded, row.dateModified, 'TEMPKEY']);
|
||||
|
||||
Zotero.DB.query("UPDATE itemTags SET tagID=? WHERE tagID=?", params);
|
||||
|
||||
Zotero.DB.query("DELETE FROM tags WHERE tagID=?", oldID);
|
||||
|
||||
Zotero.DB.query("UPDATE tags SET key=? WHERE tagID=?", [row.key, this.id]);
|
||||
|
||||
Zotero.Notifier.trigger('id-change', 'tag', oldID + '-' + this.id);
|
||||
|
||||
// update caches
|
||||
}
|
||||
|
||||
var isNew = !this.id || !this.exists();
|
||||
|
||||
try {
|
||||
|
@ -281,9 +310,16 @@ Zotero.Tag.prototype.save = function (full) {
|
|||
var key = this.key ? this.key : this._generateKey();
|
||||
|
||||
var columns = [
|
||||
'tagID', 'name', 'type', 'dateAdded', 'dateModified', 'key'
|
||||
'tagID',
|
||||
'name',
|
||||
'type',
|
||||
'dateAdded',
|
||||
'dateModified',
|
||||
'clientDateModified',
|
||||
'libraryID',
|
||||
'key'
|
||||
];
|
||||
var placeholders = ['?', '?', '?', '?', '?', '?'];
|
||||
var placeholders = ['?', '?', '?', '?', '?', '?', '?', '?'];
|
||||
var sqlValues = [
|
||||
tagID ? { int: tagID } : null,
|
||||
{ string: this.name },
|
||||
|
@ -293,6 +329,8 @@ Zotero.Tag.prototype.save = function (full) {
|
|||
// If date modified hasn't changed, use current timestamp
|
||||
this._changed.dateModified ?
|
||||
this.dateModified : Zotero.DB.transactionDateTime,
|
||||
Zotero.DB.transactionDateTime,
|
||||
this.libraryID ? this.libraryID : null,
|
||||
key
|
||||
];
|
||||
|
||||
|
@ -372,6 +410,8 @@ Zotero.Tag.prototype.save = function (full) {
|
|||
insertStatement.execute();
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.debug("itemID: " + itemID);
|
||||
Zotero.debug("tagID: " + tagID);
|
||||
throw (e + ' [ERROR: ' + Zotero.DB.getLastErrorString() + ']');
|
||||
}
|
||||
}
|
||||
|
@ -392,7 +432,7 @@ Zotero.Tag.prototype.save = function (full) {
|
|||
|
||||
// If successful, set values in object
|
||||
if (!this.id) {
|
||||
this._tagID = tagID;
|
||||
this._id = tagID;
|
||||
}
|
||||
|
||||
if (!this.key) {
|
||||
|
@ -465,9 +505,10 @@ Zotero.Tag.prototype.serialize = function () {
|
|||
var obj = {
|
||||
primary: {
|
||||
tagID: this.id,
|
||||
libraryID: this.libraryID,
|
||||
key: this.key,
|
||||
dateAdded: this.dateAdded,
|
||||
dateModified: this.dateModified,
|
||||
key: this.key
|
||||
dateModified: this.dateModified
|
||||
},
|
||||
fields: {
|
||||
name: this.name,
|
||||
|
@ -545,10 +586,20 @@ Zotero.Tag.prototype.erase = function () {
|
|||
|
||||
|
||||
Zotero.Tag.prototype._loadLinkedItems = function() {
|
||||
if (!this.id && !this.key) {
|
||||
this._linkedItemsLoaded = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this._loaded) {
|
||||
this.load();
|
||||
}
|
||||
|
||||
if (!this.id) {
|
||||
this._linkedItemsLoaded = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var sql = "SELECT itemID FROM itemTags WHERE tagID=?";
|
||||
var ids = Zotero.DB.columnQuery(sql, this.id);
|
||||
|
||||
|
|
|
@ -73,25 +73,39 @@ Zotero.Tags = new function() {
|
|||
/*
|
||||
* Returns the tagID matching given tag and type
|
||||
*/
|
||||
function getID(name, type) {
|
||||
function getID(name, type, libraryID) {
|
||||
name = Zotero.Utilities.prototype.trim(name);
|
||||
var lcname = name.toLowerCase();
|
||||
|
||||
if (_tags[type] && _tags[type]['_' + lcname]) {
|
||||
return _tags[type]['_' + lcname];
|
||||
if (!libraryID) {
|
||||
libraryID = 0;
|
||||
}
|
||||
|
||||
if (_tags[libraryID] && _tags[libraryID][type] && _tags[libraryID][type]['_' + lcname]) {
|
||||
return _tags[libraryID][type]['_' + lcname];
|
||||
}
|
||||
|
||||
// FIXME: COLLATE NOCASE doesn't work for Unicode characters, so this
|
||||
// won't find Äbc if "äbc" is entered and will allow a duplicate tag
|
||||
// to be created
|
||||
var sql = 'SELECT tagID FROM tags WHERE name=? AND type=?';
|
||||
var tagID = Zotero.DB.valueQuery(sql, [name, type]);
|
||||
|
||||
var sql = "SELECT tagID FROM tags WHERE name=? AND type=? AND libraryID";
|
||||
var params = [name, type];
|
||||
if (libraryID) {
|
||||
sql += "=?";
|
||||
params.push(libraryID);
|
||||
}
|
||||
else {
|
||||
sql += " IS NULL";
|
||||
}
|
||||
var tagID = Zotero.DB.valueQuery(sql, params);
|
||||
if (tagID) {
|
||||
if (!_tags[type]) {
|
||||
_tags[type] = [];
|
||||
if (!_tags[libraryID]) {
|
||||
_tags[libraryID] = {};
|
||||
}
|
||||
_tags[type]['_' + lcname] = tagID;
|
||||
if (!_tags[libraryID][type]) {
|
||||
_tags[libraryID][type] = [];
|
||||
}
|
||||
_tags[libraryID][type]['_' + lcname] = tagID;
|
||||
}
|
||||
|
||||
return tagID;
|
||||
|
@ -101,20 +115,36 @@ Zotero.Tags = new function() {
|
|||
/*
|
||||
* Returns all tagIDs for this tag (of all types)
|
||||
*/
|
||||
function getIDs(name) {
|
||||
function getIDs(name, libraryID) {
|
||||
name = Zotero.Utilities.prototype.trim(name);
|
||||
var sql = 'SELECT tagID FROM tags WHERE name=?';
|
||||
return Zotero.DB.columnQuery(sql, [name]);
|
||||
var sql = "SELECT tagID FROM tags WHERE name=? AND libraryID";
|
||||
var params = [name];
|
||||
if (libraryID) {
|
||||
sql += "=?";
|
||||
params.push(libraryID);
|
||||
}
|
||||
else {
|
||||
sql += " IS NULL";
|
||||
}
|
||||
return Zotero.DB.columnQuery(sql, params);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Returns an array of tag types for tags matching given tag
|
||||
*/
|
||||
function getTypes(name) {
|
||||
function getTypes(name, libraryID) {
|
||||
name = Zotero.Utilities.prototype.trim(name);
|
||||
var sql = 'SELECT type FROM tags WHERE name=?';
|
||||
return Zotero.DB.columnQuery(sql, [name]);
|
||||
var sql = "SELECT type FROM tags WHERE name=? AND libraryID";
|
||||
var params = [name];
|
||||
if (libraryID) {
|
||||
sql += "=?";
|
||||
params.push(libraryID);
|
||||
}
|
||||
else {
|
||||
sql += " IS NULL";
|
||||
}
|
||||
return Zotero.DB.columnQuery(sql, params);
|
||||
}
|
||||
|
||||
|
||||
|
@ -123,12 +153,25 @@ Zotero.Tags = new function() {
|
|||
*
|
||||
* _types_ is an optional array of tag types to fetch
|
||||
*/
|
||||
function getAll(types) {
|
||||
var sql = "SELECT tagID, name FROM tags ";
|
||||
if (types) {
|
||||
sql += "WHERE type IN (" + types.join() + ") ";
|
||||
function getAll(types, libraryID) {
|
||||
var sql = "SELECT tagID, name FROM tags WHERE libraryID";
|
||||
var params = [];
|
||||
if (libraryID) {
|
||||
sql += "=?";
|
||||
params.push(libraryID);
|
||||
}
|
||||
else {
|
||||
sql += " IS NULL";
|
||||
}
|
||||
if (types) {
|
||||
sql += " AND type IN (" + types.join() + ")";
|
||||
}
|
||||
if (params.length) {
|
||||
var tags = Zotero.DB.query(sql, params);
|
||||
}
|
||||
else {
|
||||
var tags = Zotero.DB.query(sql);
|
||||
}
|
||||
var tags = Zotero.DB.query(sql);
|
||||
if (!tags) {
|
||||
return {};
|
||||
}
|
||||
|
@ -244,6 +287,7 @@ Zotero.Tags = new function() {
|
|||
Zotero.DB.beginTransaction();
|
||||
|
||||
var tagObj = this.get(tagID);
|
||||
var oldLibraryID = tagObj.libraryID;
|
||||
var oldName = tagObj.name;
|
||||
var oldType = tagObj.type;
|
||||
var notifierData = {};
|
||||
|
@ -278,8 +322,8 @@ Zotero.Tags = new function() {
|
|||
// Manual purge of old tag
|
||||
sql = "DELETE FROM tags WHERE tagID=?";
|
||||
Zotero.DB.query(sql, tagID);
|
||||
if (_tags[oldType]) {
|
||||
delete _tags[oldType]['_' + oldName];
|
||||
if (_tags[oldLibraryID] && _tags[oldLibraryID][oldType]) {
|
||||
delete _tags[oldLibraryID][oldType]['_' + oldName];
|
||||
}
|
||||
delete this._objectCache[tagID];
|
||||
Zotero.Notifier.trigger('delete', 'tag', tagID, notifierData);
|
||||
|
@ -426,8 +470,9 @@ Zotero.Tags = new function() {
|
|||
for each(var id in ids) {
|
||||
var tag = this._objectCache[id];
|
||||
delete this._objectCache[id];
|
||||
if (tag && _tags[tag.type]) {
|
||||
delete _tags[tag.type]['_' + tag.name];
|
||||
var libraryID = tag.libraryID ? tag.libraryID : 0;
|
||||
if (tag && _tags[libraryID] && _tags[libraryID][tag.type]) {
|
||||
delete _tags[libraryID][tag.type]['_' + tag.name];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,6 +39,9 @@ Zotero.getCollections = function(parent, recursive) {
|
|||
|
||||
var sql = "SELECT collectionID AS id, collectionName AS name FROM collections C "
|
||||
+ "WHERE parentCollectionID " + (parent ? '=' + parent : 'IS NULL');
|
||||
if (!parent) {
|
||||
sql += " AND libraryID IS NULL";
|
||||
}
|
||||
var children = Zotero.DB.query(sql);
|
||||
|
||||
if (!children) {
|
||||
|
|
|
@ -148,6 +148,25 @@ Zotero.File = new function(){
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {nsIFile} file
|
||||
* @return {String} Base-64 representation of MD5 hash
|
||||
*/
|
||||
this.getFileHash = function (file) {
|
||||
var fis = Components.classes["@mozilla.org/network/file-input-stream;1"]
|
||||
.createInstance(Components.interfaces.nsIFileInputStream);
|
||||
fis.init(file, -1, -1, false);
|
||||
|
||||
var hash = Components.classes["@mozilla.org/security/hash;1"].
|
||||
createInstance(Components.interfaces.nsICryptoHash);
|
||||
hash.init(Components.interfaces.nsICryptoHash.MD5);
|
||||
hash.updateFromStream(fis, 4294967295); // PR_UINT32_MAX
|
||||
hash = hash.finish(true);
|
||||
fis.close();
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Write string to a file, overwriting existing file if necessary
|
||||
*/
|
||||
|
|
|
@ -136,7 +136,7 @@ Zotero.Fulltext = new function(){
|
|||
return false;
|
||||
}
|
||||
|
||||
versionFile = exec.parent;
|
||||
var versionFile = exec.parent;
|
||||
versionFile.append(fileName + '.version');
|
||||
if (versionFile.exists()) {
|
||||
var version = Zotero.File.getSample(versionFile).split(/[\r\n\s]/)[0];
|
||||
|
|
|
@ -31,12 +31,14 @@ Zotero.Ingester = new function() {
|
|||
getService(Components.interfaces.nsIWindowWatcher).activeWindow;
|
||||
|
||||
frontWindow.Zotero_Browser.progress.show();
|
||||
var saveLocation = null;
|
||||
var libraryID = null;
|
||||
var collection = null;
|
||||
try {
|
||||
saveLocation = frontWindow.ZoteroPane.getSelectedCollection();
|
||||
libraryID = frontWindow.ZoteroPane.getSelectedLibraryID();
|
||||
collection = frontWindow.ZoteroPane.getSelectedCollection();
|
||||
} catch(e) {}
|
||||
translation.setHandler("itemDone", function(obj, item) { frontWindow.Zotero_Browser.itemDone(obj, item, saveLocation) });
|
||||
translation.setHandler("done", function(obj, item) { frontWindow.Zotero_Browser.finishScraping(obj, item, saveLocation) });
|
||||
translation.setHandler("itemDone", function(obj, item) { frontWindow.Zotero_Browser.itemDone(obj, item, collection) });
|
||||
translation.setHandler("done", function(obj, item) { frontWindow.Zotero_Browser.finishScraping(obj, item, collection) });
|
||||
|
||||
// attempt to retrieve translators
|
||||
var translators = translation.getTranslators();
|
||||
|
@ -48,7 +50,7 @@ Zotero.Ingester = new function() {
|
|||
|
||||
// translate using first available
|
||||
translation.setTranslator(translators[0]);
|
||||
translation.translate();
|
||||
translation.translate(libraryID);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -242,13 +242,6 @@ Zotero.ItemTreeView.prototype.refresh = function()
|
|||
}
|
||||
|
||||
|
||||
Zotero.ItemTreeView.prototype.__defineGetter__('readOnly', function () {
|
||||
if (this._itemGroup.isTrash() || this._itemGroup.isShare()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
/*
|
||||
* Called by Zotero.Notifier on any changes to items in the data layer
|
||||
*/
|
||||
|
@ -264,6 +257,8 @@ Zotero.ItemTreeView.prototype.notify = function(action, type, ids, extraData)
|
|||
return;
|
||||
}
|
||||
|
||||
var itemGroup = this._itemGroup;
|
||||
|
||||
var madeChanges = false;
|
||||
var sort = false;
|
||||
|
||||
|
@ -272,7 +267,7 @@ Zotero.ItemTreeView.prototype.notify = function(action, type, ids, extraData)
|
|||
// If refreshing a single item, just unselect and reselect it
|
||||
if (action == 'refresh') {
|
||||
if (type == 'share-items') {
|
||||
if (this._itemGroup.isShare()) {
|
||||
if (itemGroup.isShare()) {
|
||||
this.refresh();
|
||||
}
|
||||
}
|
||||
|
@ -299,13 +294,14 @@ Zotero.ItemTreeView.prototype.notify = function(action, type, ids, extraData)
|
|||
|
||||
var quicksearch = this._ownerDocument.getElementById('zotero-tb-search');
|
||||
|
||||
|
||||
// 'collection-item' ids are in the form collectionID-itemID
|
||||
if (type == 'collection-item') {
|
||||
var splitIDs = [];
|
||||
for each(var id in ids) {
|
||||
var split = id.split('-');
|
||||
// Skip if not collection or not an item in this collection
|
||||
if (!this._itemGroup.isCollection() || split[0] != this._itemGroup.ref.id) {
|
||||
if (!itemGroup.isCollection() || split[0] != this._itemGroup.ref.id) {
|
||||
continue;
|
||||
}
|
||||
splitIDs.push(split[1]);
|
||||
|
@ -319,23 +315,16 @@ Zotero.ItemTreeView.prototype.notify = function(action, type, ids, extraData)
|
|||
}
|
||||
}
|
||||
|
||||
if ((action == 'remove' && !this._itemGroup.isLibrary())
|
||||
|| action == 'delete' || action == 'id-change' || action == 'trash') {
|
||||
|
||||
// We only care about the old ids
|
||||
if (action == 'id-change') {
|
||||
for (var i=0, len=ids.length; i<len; i++) {
|
||||
ids[i] = ids[i].split('-')[0];
|
||||
}
|
||||
}
|
||||
if ((action == 'remove' && !itemGroup.isLibrary(true))
|
||||
|| action == 'delete' || action == 'trash') {
|
||||
|
||||
// Since a remove involves shifting of rows, we have to do it in order,
|
||||
// so sort the ids by row
|
||||
var rows = [];
|
||||
for(var i=0, len=ids.length; i<len; i++)
|
||||
{
|
||||
if (action == 'delete' || action == 'trash' || action == 'id-change' ||
|
||||
!this._itemGroup.ref.hasItem(ids[i])) {
|
||||
if (action == 'delete' || action == 'trash' ||
|
||||
!itemGroup.ref.hasItem(ids[i])) {
|
||||
// Row might already be gone (e.g. if this is a child and
|
||||
// 'modify' was sent to parent)
|
||||
if (this._itemRowMap[ids[i]] != undefined) {
|
||||
|
@ -365,7 +354,7 @@ Zotero.ItemTreeView.prototype.notify = function(action, type, ids, extraData)
|
|||
else if (action == 'modify')
|
||||
{
|
||||
// If trash or saved search, just re-run search
|
||||
if (this._itemGroup.isTrash() || this._itemGroup.isSearch())
|
||||
if (itemGroup.isTrash() || itemGroup.isSearch())
|
||||
{
|
||||
this.refresh();
|
||||
madeChanges = true;
|
||||
|
@ -375,9 +364,11 @@ Zotero.ItemTreeView.prototype.notify = function(action, type, ids, extraData)
|
|||
// If no quicksearch, process modifications manually
|
||||
else if (!quicksearch || quicksearch.value == '')
|
||||
{
|
||||
for(var i=0, len=ids.length; i<len; i++)
|
||||
{
|
||||
var row = this._itemRowMap[ids[i]];
|
||||
var items = Zotero.Items.get(ids);
|
||||
for each(var item in items) {
|
||||
var id = item.id;
|
||||
|
||||
var row = this._itemRowMap[id];
|
||||
// Item already exists in this view
|
||||
if( row != null)
|
||||
{
|
||||
|
@ -401,25 +392,19 @@ Zotero.ItemTreeView.prototype.notify = function(action, type, ids, extraData)
|
|||
else if (!this.isContainer(row) && parentIndex != -1
|
||||
&& !sourceItemID)
|
||||
{
|
||||
var item = Zotero.Items.get(ids[i]);
|
||||
this._showItem(new Zotero.ItemTreeView.TreeRow(item, 0, false), this.rowCount);
|
||||
this._treebox.rowCountChanged(this.rowCount-1, 1);
|
||||
sort = ids[i];
|
||||
sort = id;
|
||||
}
|
||||
// If not moved from under one item to another
|
||||
else if (!(sourceItemID && parentIndex != -1 && this._itemRowMap[sourceItemID] != parentIndex)) {
|
||||
sort = ids[i];
|
||||
sort = id;
|
||||
}
|
||||
madeChanges = true;
|
||||
}
|
||||
|
||||
else if (this._itemGroup.isLibrary() || this._itemGroup.ref.hasItem(ids[i])) {
|
||||
var item = Zotero.Items.get(ids[i]);
|
||||
if (!item) {
|
||||
// DEBUG: this shouldn't really happen but could if a
|
||||
// modify comes in after a delete
|
||||
continue;
|
||||
}
|
||||
else if (((itemGroup.isLibrary() || itemGroup.isGroup()) && itemGroup.ref.libraryID == item.libraryID)
|
||||
|| (itemGroup.isCollection() && item.inCollection(itemGroup.ref.id))) {
|
||||
// Deleted items get a modify that we have to ignore when
|
||||
// not viewing the trash
|
||||
if (item.deleted) {
|
||||
|
@ -452,7 +437,7 @@ Zotero.ItemTreeView.prototype.notify = function(action, type, ids, extraData)
|
|||
else if(action == 'add')
|
||||
{
|
||||
// If saved search or trash, just re-run search
|
||||
if (this._itemGroup.isSearch() || this._itemGroup.isTrash()) {
|
||||
if (itemGroup.isSearch() || itemGroup.isTrash()) {
|
||||
this.refresh();
|
||||
madeChanges = true;
|
||||
sort = true;
|
||||
|
@ -463,24 +448,21 @@ Zotero.ItemTreeView.prototype.notify = function(action, type, ids, extraData)
|
|||
else if (quicksearch && quicksearch.value == '')
|
||||
{
|
||||
var items = Zotero.Items.get(ids);
|
||||
for (var i in items)
|
||||
{
|
||||
for each(var item in items) {
|
||||
// if the item belongs in this collection
|
||||
if((this._itemGroup.isLibrary() || items[i].inCollection(this._itemGroup.ref.id))
|
||||
if ((((itemGroup.isLibrary() || itemGroup.isGroup()) && itemGroup.ref.libraryID == item.libraryID)
|
||||
|| (itemGroup.isCollection() && item.inCollection(itemGroup.ref.id)))
|
||||
// if we haven't already added it to our hash map
|
||||
&& this._itemRowMap[items[i].id] == null
|
||||
&& this._itemRowMap[item.id] == null
|
||||
// Regular item or standalone note/attachment
|
||||
&& (items[i].isRegularItem() || !items[i].getSource()))
|
||||
{
|
||||
this._showItem(new Zotero.ItemTreeView.TreeRow(items[i],0,false),this.rowCount);
|
||||
&& (item.isRegularItem() || !item.getSource())) {
|
||||
this._showItem(new Zotero.ItemTreeView.TreeRow(item, 0, false), this.rowCount);
|
||||
this._treebox.rowCountChanged(this.rowCount-1,1);
|
||||
|
||||
madeChanges = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (madeChanges) {
|
||||
sort = (ids.length == 1) ? ids[0] : true;
|
||||
sort = (items.length == 1) ? items[0].id : true;
|
||||
}
|
||||
}
|
||||
// Otherwise re-run the search, which refreshes the item list
|
||||
|
@ -510,6 +492,7 @@ Zotero.ItemTreeView.prototype.notify = function(action, type, ids, extraData)
|
|||
|
||||
// Reset to Info tab
|
||||
this._ownerDocument.getElementById('zotero-view-tabs').selectedIndex = 0;
|
||||
|
||||
this.selectItem(ids[0]);
|
||||
}
|
||||
// If single item is selected and was modified
|
||||
|
@ -548,7 +531,7 @@ Zotero.ItemTreeView.prototype.notify = function(action, type, ids, extraData)
|
|||
}
|
||||
|
||||
// On delete, select item at previous position
|
||||
if (action == 'delete') {
|
||||
if (action == 'delete' || action == 'remove') {
|
||||
if (this._dataItems[previousRow]) {
|
||||
this.selection.select(previousRow);
|
||||
}
|
||||
|
@ -571,6 +554,10 @@ Zotero.ItemTreeView.prototype.notify = function(action, type, ids, extraData)
|
|||
this.selectItem(selectItem);
|
||||
}
|
||||
|
||||
if (Zotero.Sync.Server.syncInProgress) {
|
||||
this.rememberSelection(savedSelection);
|
||||
}
|
||||
|
||||
this.selection.selectEventsSuppressed = false;
|
||||
}
|
||||
|
||||
|
@ -1085,11 +1072,16 @@ Zotero.ItemTreeView.prototype.sort = function(itemID)
|
|||
///
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/*
|
||||
* Select an item
|
||||
*/
|
||||
Zotero.ItemTreeView.prototype.selectItem = function(id, expand, noRecurse)
|
||||
{
|
||||
if (Zotero.Sync.Server.syncInProgress) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If no row map, we're probably in the process of switching collections,
|
||||
// so store the item to select on the item group for later
|
||||
if (!this._itemRowMap) {
|
||||
|
@ -1223,14 +1215,18 @@ Zotero.ItemTreeView.prototype.deleteSelection = function(eraseChildren, force)
|
|||
ids.push(this._getItemAtRow(j).ref.id);
|
||||
}
|
||||
|
||||
// Erase item(s) from DB
|
||||
if (this._itemGroup.isLibrary() || force) {
|
||||
var itemGroup = this._itemGroup;
|
||||
|
||||
if (itemGroup.isGroup() || (force && itemGroup.isWithinGroup())) {
|
||||
Zotero.Items.erase(ids, eraseChildren);
|
||||
}
|
||||
else if (itemGroup.isLibrary() || force) {
|
||||
Zotero.Items.trash(ids);
|
||||
}
|
||||
else if (this._itemGroup.isCollection()) {
|
||||
this._itemGroup.ref.removeItems(ids);
|
||||
else if (itemGroup.isCollection()) {
|
||||
itemGroup.ref.removeItems(ids);
|
||||
}
|
||||
else if (this._itemGroup.isTrash()) {
|
||||
else if (itemGroup.isTrash()) {
|
||||
Zotero.Items.erase(ids, eraseChildren);
|
||||
}
|
||||
this._treebox.endUpdateBatch();
|
||||
|
@ -1597,7 +1593,7 @@ Zotero.ItemTreeView.prototype.onDragStart = function (event, transferData, actio
|
|||
var oldMethod = Zotero.isFx2 || Zotero.isFx30;
|
||||
|
||||
// Quick implementation of dragging of XML item format
|
||||
if (this.readOnly) {
|
||||
if (this._itemGroup.isShare()) {
|
||||
var items = this.getSelectedItems();
|
||||
|
||||
var xml = <data/>;
|
||||
|
@ -1985,7 +1981,7 @@ Zotero.ItemTreeView.prototype.canDrop = function(row, orient, dragData)
|
|||
//Zotero.debug("Row is " + row + "; orient is " + orient);
|
||||
|
||||
if (row == -1 && orient == -1) {
|
||||
return true;
|
||||
//return true;
|
||||
}
|
||||
|
||||
if (!dragData) {
|
||||
|
@ -2001,6 +1997,8 @@ Zotero.ItemTreeView.prototype.canDrop = function(row, orient, dragData)
|
|||
var ids = data;
|
||||
}
|
||||
|
||||
var itemGroup = this._itemGroup;
|
||||
|
||||
// workaround... two different services call canDrop
|
||||
// (nsDragAndDrop, and the tree) -- this is for the former,
|
||||
// used when dragging between windows
|
||||
|
@ -2010,53 +2008,56 @@ Zotero.ItemTreeView.prototype.canDrop = function(row, orient, dragData)
|
|||
if (nsDragAndDrop.mDragSession.sourceNode!=row.target)
|
||||
{
|
||||
if (dataType == 'zotero/item') {
|
||||
var items = Zotero.Items.get(ids);
|
||||
|
||||
// Check if at least one item (or parent item for children) doesn't
|
||||
// already exist in target
|
||||
for each(var id in ids)
|
||||
{
|
||||
var item = Zotero.Items.get(id);
|
||||
|
||||
for each(var item in items) {
|
||||
// Skip non-top-level items
|
||||
if (!item.isRegularItem() && item.getSource())
|
||||
{
|
||||
if (!item.isTopLevelItem()) {
|
||||
continue;
|
||||
}
|
||||
// DISABLED: move parent on child drag
|
||||
//var source = item.isRegularItem() ? false : item.getSource();
|
||||
//if (!this._itemGroup.ref.hasItem(source ? source : id))
|
||||
if (this._itemGroup.ref && !this._itemGroup.ref.hasItem(id))
|
||||
{
|
||||
|
||||
// TODO: For now, disable cross-window cross-library drag
|
||||
if (itemGroup.ref.libraryID != item.libraryID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (itemGroup.ref && !itemGroup.ref.hasItem(item.id)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (dataType == 'text/x-moz-url' || dataType == 'application/x-moz-file') {
|
||||
if (this._itemGroup.isSearch()) {
|
||||
if (itemGroup.isSearch()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Highlight the rows correctly on drag
|
||||
if (orient == 0) {
|
||||
var rowItem = this._getItemAtRow(row).ref; // the item we are dragging over
|
||||
}
|
||||
|
||||
var rowItem = this._getItemAtRow(row).ref; //the item we are dragging over
|
||||
if (dataType == 'zotero/item') {
|
||||
var items = Zotero.Items.get(ids);
|
||||
|
||||
// Directly on a row
|
||||
if (orient == 0)
|
||||
{
|
||||
if (orient == 0) {
|
||||
var canDrop = false;
|
||||
for each(var id in ids) {
|
||||
var item = Zotero.Items.get(id);
|
||||
|
||||
|
||||
for each(var item in items) {
|
||||
// If any regular items, disallow drop
|
||||
if (item.isRegularItem()) {
|
||||
canDrop = false;
|
||||
break;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Disallow cross-library child drag
|
||||
if (item.libraryID != itemGroup.ref.libraryID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only allow dragging of notes and attachments
|
||||
|
@ -2070,14 +2071,19 @@ Zotero.ItemTreeView.prototype.canDrop = function(row, orient, dragData)
|
|||
}
|
||||
|
||||
// In library, allow children to be dragged out of parent
|
||||
else if (this._itemGroup.isLibrary() || this._itemGroup.isCollection())
|
||||
{
|
||||
for each(var id in ids)
|
||||
{
|
||||
else if (itemGroup.isLibrary(true) || itemGroup.isCollection()) {
|
||||
for each(var item in items) {
|
||||
// Don't allow drag if any top-level items
|
||||
var item = Zotero.Items.get(id);
|
||||
if (item.isRegularItem() || !item.getSource())
|
||||
{
|
||||
if (item.isTopLevelItem()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (item.isWebAttachment()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Disallow cross-library child drag
|
||||
if (item.libraryID != itemGroup.ref.libraryID) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -2092,7 +2098,8 @@ Zotero.ItemTreeView.prototype.canDrop = function(row, orient, dragData)
|
|||
return false;
|
||||
}
|
||||
}
|
||||
else if (this._itemGroup.isSearch()) {
|
||||
// Don't allow drop into searches
|
||||
else if (itemGroup.isSearch()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2116,18 +2123,22 @@ Zotero.ItemTreeView.prototype.drop = function(row, orient)
|
|||
var dataType = dragData.dataType;
|
||||
var data = dragData.data;
|
||||
|
||||
var itemGroup = this._itemGroup;
|
||||
|
||||
if (dataType == 'zotero/item') {
|
||||
var ids = data;
|
||||
var items = Zotero.Items.get(ids);
|
||||
if (items.length < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Dropped directly on a row
|
||||
if (orient == 0)
|
||||
{
|
||||
// If item was a top-level item and it exists in a collection,
|
||||
// replace it in collections with the parent item
|
||||
if (orient == 0) {
|
||||
// Set drop target as the parent item for dragged items
|
||||
//
|
||||
// canDrop() limits this to child items
|
||||
var rowItem = this._getItemAtRow(row).ref; // the item we are dragging over
|
||||
for each(var id in ids)
|
||||
{
|
||||
var item = Zotero.Items.get(id);
|
||||
for each(var item in items) {
|
||||
item.setSource(rowItem.id);
|
||||
item.save();
|
||||
}
|
||||
|
@ -2137,11 +2148,8 @@ Zotero.ItemTreeView.prototype.drop = function(row, orient)
|
|||
else
|
||||
{
|
||||
// Remove from parent and make top-level
|
||||
if (this._itemGroup.isLibrary())
|
||||
{
|
||||
for each(var id in ids)
|
||||
{
|
||||
var item = Zotero.Items.get(id);
|
||||
if (itemGroup.isLibrary(true)) {
|
||||
for each(var item in items) {
|
||||
if (!item.isRegularItem())
|
||||
{
|
||||
item.setSource();
|
||||
|
@ -2152,30 +2160,49 @@ Zotero.ItemTreeView.prototype.drop = function(row, orient)
|
|||
// Add to collection
|
||||
else
|
||||
{
|
||||
for each(var id in ids)
|
||||
for each(var item in items)
|
||||
{
|
||||
var item = Zotero.Items.get(id);
|
||||
var source = item.isRegularItem() ? false : item.getSource();
|
||||
|
||||
// Top-level item
|
||||
if (source) {
|
||||
item.setSource();
|
||||
item.save()
|
||||
}
|
||||
this._itemGroup.ref.addItem(id);
|
||||
itemGroup.ref.addItem(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (dataType == 'text/x-moz-url' || dataType == 'application/x-moz-file') {
|
||||
// FIXME: temporarily disable dragging in of files
|
||||
if (dataType == 'application/x-moz-file' && itemGroup.isWithinGroup()) {
|
||||
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
|
||||
.getService(Components.interfaces.nsIPromptService);
|
||||
ps.alert(null, "", "Files cannot currently be added to group libraries.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Disallow drop into read-only libraries
|
||||
if (!itemGroup.isEditable()) {
|
||||
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
|
||||
.getService(Components.interfaces.nsIWindowMediator);
|
||||
var win = wm.getMostRecentWindow("navigator:browser");
|
||||
win.ZoteroPane.displayCannotEditLibraryMessage();
|
||||
return;
|
||||
}
|
||||
|
||||
var sourceItemID = false;
|
||||
var parentCollectionID = false;
|
||||
|
||||
var treerow = this._getItemAtRow(row);
|
||||
if (orient == 0) {
|
||||
sourceItemID = this._getItemAtRow(row).ref.id
|
||||
sourceItemID = treerow.ref.id
|
||||
}
|
||||
else if (this._itemGroup.isCollection()) {
|
||||
var parentCollectionID = this._itemGroup.ref.id;
|
||||
else if (itemGroup.isCollection()) {
|
||||
var parentCollectionID = itemGroup.ref.id;
|
||||
}
|
||||
else if (itemGroup.isLibrary(true)) {
|
||||
var libraryID = itemGroup.ref.libraryID;
|
||||
}
|
||||
|
||||
var unlock = Zotero.Notifier.begin(true);
|
||||
|
@ -2207,7 +2234,15 @@ Zotero.ItemTreeView.prototype.drop = function(row, orient)
|
|||
|
||||
// Still string, so remote URL
|
||||
if (typeof file == 'string') {
|
||||
Zotero.Attachments.importFromURL(url, sourceItemID, false, false, parentCollectionID);
|
||||
if (sourceItemID) {
|
||||
Zotero.Attachments.importFromURL(url, sourceItemID);
|
||||
}
|
||||
else {
|
||||
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
|
||||
.getService(Components.interfaces.nsIWindowMediator);
|
||||
var win = wm.getMostRecentWindow("navigator:browser");
|
||||
win.ZoteroPane.addItemFromURL(url);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ Zotero.Notifier = new function(){
|
|||
var _disabled = false;
|
||||
var _types = [
|
||||
'collection', 'creator', 'search', 'share', 'share-items', 'item',
|
||||
'collection-item', 'item-tag', 'tag'
|
||||
'collection-item', 'item-tag', 'tag', 'group'
|
||||
];
|
||||
var _inTransaction;
|
||||
var _locked = false;
|
||||
|
@ -87,7 +87,7 @@ Zotero.Notifier = new function(){
|
|||
*
|
||||
* event: 'add', 'modify', 'delete', 'move' ('c', for changing parent),
|
||||
* 'remove' (ci, it), 'refresh', 'trash'
|
||||
* type - 'collection', 'search', 'item', 'collection-item', 'item-tag', 'tag'
|
||||
* type - 'collection', 'search', 'item', 'collection-item', 'item-tag', 'tag', 'group'
|
||||
* ids - single id or array of ids
|
||||
*
|
||||
* Notes:
|
||||
|
|
|
@ -116,8 +116,8 @@ Zotero.Schema = new function(){
|
|||
}
|
||||
}
|
||||
|
||||
var up1 = _migrateUserDataSchema(dbVersion);
|
||||
var up2 = _updateSchema('system');
|
||||
var up1 = _migrateUserDataSchema(dbVersion);
|
||||
var up3 = _updateSchema('triggers');
|
||||
|
||||
Zotero.DB.commitTransaction();
|
||||
|
@ -2270,7 +2270,7 @@ Zotero.Schema = new function(){
|
|||
Zotero.DB.query("DROP TABLE syncDeleteLogOld");
|
||||
}
|
||||
|
||||
//
|
||||
// 1.5 Sync Preview 3.7
|
||||
if (i==48) {
|
||||
Zotero.DB.query("CREATE TABLE deletedItems (\n itemID INTEGER PRIMARY KEY,\n dateDeleted DEFAULT CURRENT_TIMESTAMP NOT NULL\n);");
|
||||
}
|
||||
|
@ -2300,10 +2300,73 @@ Zotero.Schema = new function(){
|
|||
Zotero.DB.query("DROP TABLE tagsOld");
|
||||
}
|
||||
|
||||
// 1.5 Beta 3
|
||||
if (i==50) {
|
||||
Zotero.DB.query("DELETE FROM proxyHosts");
|
||||
Zotero.DB.query("DELETE FROM proxies");
|
||||
}
|
||||
|
||||
if (i==51) {
|
||||
Zotero.DB.query("ALTER TABLE collections RENAME TO collectionsOld");
|
||||
Zotero.DB.query("DROP INDEX creators_creatorDataID");
|
||||
Zotero.DB.query("ALTER TABLE creators RENAME TO creatorsOld");
|
||||
Zotero.DB.query("ALTER TABLE items RENAME TO itemsOld")
|
||||
Zotero.DB.query("ALTER TABLE savedSearches RENAME TO savedSearchesOld");
|
||||
Zotero.DB.query("ALTER TABLE tags RENAME TO tagsOld");
|
||||
|
||||
Zotero.DB.query("CREATE TABLE collections (\n collectionID INTEGER PRIMARY KEY,\n collectionName TEXT NOT NULL,\n parentCollectionID INT DEFAULT NULL,\n dateAdded TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\n dateModified TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\n clientDateModified TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\n libraryID INT,\n key TEXT NOT NULL,\n UNIQUE (libraryID, key),\n FOREIGN KEY (parentCollectionID) REFERENCES collections(collectionID)\n);");
|
||||
Zotero.DB.query("CREATE TABLE creators (\n creatorID INTEGER PRIMARY KEY,\n creatorDataID INT NOT NULL,\n dateAdded TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\n dateModified TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\n clientDateModified TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\n libraryID INT,\n key TEXT NOT NULL,\n UNIQUE (libraryID, key),\n FOREIGN KEY (creatorDataID) REFERENCES creatorData(creatorDataID)\n);");
|
||||
Zotero.DB.query("CREATE TABLE items (\n itemID INTEGER PRIMARY KEY,\n itemTypeID INT NOT NULL,\n dateAdded TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\n dateModified TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\n clientDateModified TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\n libraryID INT,\n key TEXT NOT NULL,\n UNIQUE (libraryID, key)\n);");
|
||||
Zotero.DB.query("CREATE TABLE savedSearches (\n savedSearchID INTEGER PRIMARY KEY,\n savedSearchName TEXT NOT NULL,\n dateAdded TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\n dateModified TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\n clientDateModified TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\n libraryID INT,\n key TEXT NOT NULL,\n UNIQUE (libraryID, key)\n);");
|
||||
Zotero.DB.query("CREATE TABLE tags (\n tagID INTEGER PRIMARY KEY,\n name TEXT NOT NULL COLLATE NOCASE,\n type INT NOT NULL,\n dateAdded TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\n dateModified TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\n clientDateModified TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\n libraryID INT,\n key TEXT NOT NULL,\n UNIQUE (libraryID, name, type),\n UNIQUE (libraryID, key)\n);\n");
|
||||
|
||||
Zotero.DB.query("INSERT INTO collections SELECT collectionID, collectionName, parentCollectionID, dateAdded, dateModified, dateModified, NULL, key FROM collectionsOld");
|
||||
Zotero.DB.query("INSERT INTO creators SELECT creatorID, creatorDataID, dateAdded, dateModified, dateModified, NULL, key FROM creatorsOld");
|
||||
Zotero.DB.query("INSERT INTO items SELECT itemID, itemTypeID, dateAdded, dateModified, dateModified, NULL, key FROM itemsOld");
|
||||
Zotero.DB.query("INSERT INTO savedSearches SELECT savedSearchID, savedSearchName, dateAdded, dateModified, dateModified, NULL, key FROM savedSearchesOld");
|
||||
Zotero.DB.query("INSERT INTO tags SELECT tagID, name, type, dateAdded, dateModified, dateModified, NULL, key FROM tagsOld");
|
||||
|
||||
Zotero.DB.query("CREATE INDEX creators_creatorDataID ON creators(creatorDataID);");
|
||||
|
||||
Zotero.DB.query("DROP TABLE collectionsOld");
|
||||
Zotero.DB.query("DROP TABLE creatorsOld");
|
||||
Zotero.DB.query("DROP TABLE itemsOld");
|
||||
Zotero.DB.query("DROP TABLE savedSearchesOld");
|
||||
Zotero.DB.query("DROP TABLE tagsOld");
|
||||
|
||||
Zotero.DB.query("CREATE TABLE libraries (\n libraryID INTEGER PRIMARY KEY,\n libraryType TEXT NOT NULL\n);");
|
||||
Zotero.DB.query("CREATE TABLE users (\n userID INTEGER PRIMARY KEY,\n username TEXT NOT NULL\n);");
|
||||
Zotero.DB.query("CREATE TABLE groups (\n groupID INTEGER PRIMARY KEY,\n libraryID INT NOT NULL UNIQUE,\n name TEXT NOT NULL,\n description TEXT NOT NULL,\n editable INT NOT NULL,\n filesEditable INT NOT NULL,\n FOREIGN KEY (libraryID) REFERENCES libraries(libraryID)\n);");
|
||||
Zotero.DB.query("CREATE TABLE groupItems (\n itemID INTEGER PRIMARY KEY,\n createdByUserID INT NOT NULL,\n lastModifiedByUserID INT NOT NULL,\n FOREIGN KEY (createdByUserID) REFERENCES users(userID),\n FOREIGN KEY (lastModifiedByUserID) REFERENCES users(userID)\n);");
|
||||
|
||||
Zotero.DB.query("ALTER TABLE syncDeleteLog RENAME TO syncDeleteLogOld");
|
||||
Zotero.DB.query("DROP INDEX syncDeleteLog_timestamp");
|
||||
Zotero.DB.query("CREATE TABLE syncDeleteLog (\n syncObjectTypeID INT NOT NULL,\n libraryID INT,\n key TEXT NOT NULL,\n timestamp INT NOT NULL,\n UNIQUE (libraryID, key),\n FOREIGN KEY (syncObjectTypeID) REFERENCES syncObjectTypes(syncObjectTypeID)\n);");
|
||||
Zotero.DB.query("INSERT INTO syncDeleteLog SELECT syncObjectTypeID, NULL, key, timestamp FROM syncDeleteLogOld");
|
||||
Zotero.DB.query("CREATE INDEX syncDeleteLog_timestamp ON syncDeleteLog(timestamp)");
|
||||
Zotero.DB.query("DROP TABLE syncDeleteLogOld");
|
||||
|
||||
Zotero.DB.query("ALTER TABLE storageDeleteLog RENAME TO storageDeleteLogOld");
|
||||
Zotero.DB.query("DROP INDEX storageDeleteLog_timestamp");
|
||||
Zotero.DB.query("CREATE TABLE storageDeleteLog (\n libraryID INT,\n key TEXT NOT NULL,\n timestamp INT NOT NULL,\n PRIMARY KEY (libraryID, key)\n);");
|
||||
Zotero.DB.query("INSERT INTO storageDeleteLog SELECT NULL, key, timestamp FROM storageDeleteLogOld");
|
||||
Zotero.DB.query("CREATE INDEX storageDeleteLog_timestamp ON storageDeleteLog(timestamp)");
|
||||
Zotero.DB.query("DROP TABLE storageDeleteLogOld");
|
||||
|
||||
Zotero.DB.query("CREATE TEMPORARY TABLE tmpUpdatedItems (itemID INTEGER PRIMARY KEY)");
|
||||
Zotero.DB.query("INSERT INTO tmpUpdatedItems SELECT itemID FROM items NATURAL JOIN itemData WHERE fieldID=10 AND itemTypeID IN (2,9)");
|
||||
Zotero.DB.query("UPDATE itemData SET fieldID=118 WHERE fieldID=10 AND itemID IN (SELECT itemID FROM tmpUpdatedItems)");
|
||||
Zotero.DB.query("DROP TABLE tmpUpdatedItems");
|
||||
}
|
||||
|
||||
if (i==52) {
|
||||
Zotero.DB.query("CREATE TABLE relations (\n libraryID INT NOT NULL,\n subject TEXT NOT NULL,\n predicate TEXT NOT NULL,\n object TEXT NOT NULL,\n clientDateModified TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\n PRIMARY KEY (libraryID, subject, predicate, object)\n)");
|
||||
Zotero.DB.query("CREATE INDEX relations_object ON relations(libraryID, object)")
|
||||
}
|
||||
|
||||
if (i==53) {
|
||||
Zotero.DB.query("DELETE FROM collectionItems WHERE itemID IN (SELECT itemID FROM items WHERE itemID IN (SELECT itemID FROM itemAttachments WHERE sourceItemID IS NOT NULL) OR itemID IN (SELECT itemID FROM itemNotes WHERE sourceItemID IS NOT NULL))");
|
||||
}
|
||||
}
|
||||
|
||||
_updateDBVersion('userdata', toVersion);
|
||||
|
|
|
@ -20,20 +20,25 @@
|
|||
***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
Zotero.Search = function(searchID) {
|
||||
this._id = searchID ? searchID : null;
|
||||
Zotero.Search = function() {
|
||||
if (arguments[0]) {
|
||||
throw ("Zotero.Search constructor doesn't take any parameters");
|
||||
}
|
||||
|
||||
this._loaded = false;
|
||||
this._init();
|
||||
}
|
||||
|
||||
|
||||
Zotero.Search.prototype._init = function () {
|
||||
// Public members for access by public methods -- do not access directly
|
||||
this._id = null;
|
||||
this._libraryID = null;
|
||||
this._key = null;
|
||||
this._name = null;
|
||||
this._dateAdded = null;
|
||||
this._dateModified = null;
|
||||
this._key = null;
|
||||
|
||||
this._loaded = false;
|
||||
this._changed = false;
|
||||
this._previousData = false;
|
||||
|
||||
|
@ -64,24 +69,25 @@ Zotero.Search.prototype.setName = function(val) {
|
|||
}
|
||||
|
||||
|
||||
Zotero.Search.prototype.__defineGetter__('id', function () { return this._id; });
|
||||
|
||||
Zotero.Search.prototype.__defineGetter__('objectType', function () { return 'search'; });
|
||||
Zotero.Search.prototype.__defineGetter__('id', function () { return this._get('id'); });
|
||||
Zotero.Search.prototype.__defineSetter__('id', function (val) { this._set('id', val); });
|
||||
Zotero.Search.prototype.__defineSetter__('searchID', function (val) { this._set('id', val); });
|
||||
Zotero.Search.prototype.__defineGetter__('libraryID', function () { return this._get('libraryID'); });
|
||||
Zotero.Search.prototype.__defineSetter__('libraryID', function (val) { return this._set('libraryID', val); });
|
||||
Zotero.Search.prototype.__defineGetter__('key', function () { return this._get('key'); });
|
||||
Zotero.Search.prototype.__defineSetter__('key', function (val) { this._set('key', val) });
|
||||
Zotero.Search.prototype.__defineGetter__('name', function () { return this._get('name'); });
|
||||
Zotero.Search.prototype.__defineSetter__('name', function (val) { this._set('name', val); });
|
||||
Zotero.Search.prototype.__defineGetter__('dateAdded', function () { return this._get('dateAdded'); });
|
||||
Zotero.Search.prototype.__defineSetter__('dateAdded', function (val) { this._set('dateAdded', val); });
|
||||
Zotero.Search.prototype.__defineGetter__('dateModified', function () { return this._get('dateModified'); });
|
||||
Zotero.Search.prototype.__defineSetter__('dateModified', function (val) { this._set('dateModified', val); });
|
||||
Zotero.Search.prototype.__defineGetter__('key', function () { return this._get('key'); });
|
||||
Zotero.Search.prototype.__defineSetter__('key', function (val) { this._set('key', val); });
|
||||
|
||||
Zotero.Search.prototype.__defineGetter__('conditions', function (arr) { this.getSearchConditions(); });
|
||||
|
||||
|
||||
Zotero.Search.prototype._get = function (field) {
|
||||
if (this.id && !this._loaded) {
|
||||
if ((this._id || this._key) && !this._loaded) {
|
||||
this.load();
|
||||
}
|
||||
return this['_' + field];
|
||||
|
@ -89,17 +95,27 @@ Zotero.Search.prototype._get = function (field) {
|
|||
|
||||
|
||||
Zotero.Search.prototype._set = function (field, val) {
|
||||
if (field == 'name') {
|
||||
val = Zotero.Utilities.prototype.trim(val);
|
||||
}
|
||||
|
||||
switch (field) {
|
||||
//case 'id': // set using constructor
|
||||
case 'searchID':
|
||||
throw ("Invalid field '" + field + "' in Zotero.Search.set()");
|
||||
case 'id':
|
||||
case 'libraryID':
|
||||
case 'key':
|
||||
if (val == this['_' + field]) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._loaded) {
|
||||
throw ("Cannot set " + field + " after object is already loaded in Zotero.Search._set()");
|
||||
}
|
||||
//this._checkValue(field, val);
|
||||
this['_' + field] = val;
|
||||
return;
|
||||
|
||||
case 'name':
|
||||
val = Zotero.Utilities.prototype.trim(val);
|
||||
break;
|
||||
}
|
||||
|
||||
if (this.id) {
|
||||
if (this.id || this.key) {
|
||||
if (!this._loaded) {
|
||||
this.load();
|
||||
}
|
||||
|
@ -143,32 +159,51 @@ Zotero.Search.prototype.load = function() {
|
|||
throw ('Parameter no longer allowed in Zotero.Search.load()');
|
||||
}
|
||||
|
||||
var id = this._id;
|
||||
var key = this._key;
|
||||
var libraryID = this._libraryID;
|
||||
var desc = id ? id : libraryID + "/" + key;
|
||||
|
||||
var sql = "SELECT S.*, "
|
||||
+ "MAX(searchConditionID) AS maxID "
|
||||
+ "FROM savedSearches S LEFT JOIN savedSearchConditions "
|
||||
+ "USING (savedSearchID) WHERE savedSearchID=? "
|
||||
+ "GROUP BY savedSearchID";
|
||||
var data = Zotero.DB.rowQuery(sql, this.id);
|
||||
+ "USING (savedSearchID) WHERE ";
|
||||
if (id) {
|
||||
sql += "savedSearchID=?";
|
||||
var params = id;
|
||||
}
|
||||
else {
|
||||
sql += "key=?";
|
||||
var params = [key];
|
||||
if (libraryID) {
|
||||
sql += " AND libraryID=?";
|
||||
params.push(libraryID);
|
||||
}
|
||||
else {
|
||||
sql += " AND libraryID IS NULL";
|
||||
}
|
||||
}
|
||||
sql += " GROUP BY savedSearchID";
|
||||
var data = Zotero.DB.rowQuery(sql, params);
|
||||
|
||||
this._init();
|
||||
this._loaded = true;
|
||||
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._changed = false;
|
||||
this._previousData = false;
|
||||
this._init();
|
||||
this._id = data.savedSearchID;
|
||||
this._libraryID = data.libraryID;
|
||||
this._key = data.key;
|
||||
this._name = data.savedSearchName;
|
||||
this._dateAdded = data.dateAdded;
|
||||
this._dateModified = data.dateModified;
|
||||
this._key = data.key;
|
||||
this._maxSearchConditionID = data.maxID;
|
||||
|
||||
var sql = "SELECT * FROM savedSearchConditions "
|
||||
+ "WHERE savedSearchID=? ORDER BY searchConditionID";
|
||||
var conditions = Zotero.DB.query(sql, this.id);
|
||||
var conditions = Zotero.DB.query(sql, this._id);
|
||||
|
||||
for (var i in conditions) {
|
||||
// Parse "condition[/mode]"
|
||||
|
@ -203,36 +238,14 @@ Zotero.Search.prototype.load = function() {
|
|||
* For new searches, name must be set called before saving
|
||||
*/
|
||||
Zotero.Search.prototype.save = function(fixGaps) {
|
||||
Zotero.Searches.editCheck(this);
|
||||
|
||||
if (!this.name) {
|
||||
throw('Name not provided for saved search');
|
||||
}
|
||||
|
||||
Zotero.DB.beginTransaction();
|
||||
|
||||
// ID change
|
||||
if (this._changed.id) {
|
||||
var oldID = this._previousData.primary.id;
|
||||
var params = [this.id, oldID];
|
||||
|
||||
Zotero.debug("Changing search id " + oldID + " to " + this.id);
|
||||
|
||||
var row = Zotero.DB.rowQuery("SELECT * FROM savedSearches WHERE savedSearchID=?", oldID);
|
||||
// Add a new row so we can update the old rows despite FK checks
|
||||
// Use temp key due to UNIQUE constraint on key column
|
||||
Zotero.DB.query("INSERT INTO savedSearches VALUES (?, ?, ?, ?, ?)",
|
||||
[this.id, row.savedSearchName, row.dateAdded, row.dateModified, 'TEMPKEY']);
|
||||
|
||||
Zotero.DB.query("UPDATE savedSearchConditions SET savedSearchID=? WHERE savedSearchID=?", params);
|
||||
|
||||
Zotero.DB.query("DELETE FROM savedSearches WHERE savedSearchID=?", oldID);
|
||||
Zotero.DB.query("UPDATE savedSearches SET key=? WHERE savedSearchID=?", [row.key, this.id]);
|
||||
|
||||
//Zotero.Searches.unload(oldID);
|
||||
Zotero.Notifier.trigger('id-change', 'search', oldID + '-' + this.id);
|
||||
|
||||
// update caches
|
||||
}
|
||||
|
||||
var isNew = !this.id || !this.exists();
|
||||
|
||||
try {
|
||||
|
@ -243,9 +256,15 @@ Zotero.Search.prototype.save = function(fixGaps) {
|
|||
var key = this.key ? this.key : this._generateKey();
|
||||
|
||||
var columns = [
|
||||
'savedSearchID', 'savedSearchName', 'dateAdded', 'dateModified', 'key'
|
||||
'savedSearchID',
|
||||
'savedSearchName',
|
||||
'dateAdded',
|
||||
'dateModified',
|
||||
'clientDateModified',
|
||||
'libraryID',
|
||||
'key'
|
||||
];
|
||||
var placeholders = ['?', '?', '?', '?', '?'];
|
||||
var placeholders = ['?', '?', '?', '?', '?', '?', '?'];
|
||||
var sqlValues = [
|
||||
searchID ? { int: searchID } : null,
|
||||
{ string: this.name },
|
||||
|
@ -254,6 +273,8 @@ Zotero.Search.prototype.save = function(fixGaps) {
|
|||
// If date modified hasn't changed, use current timestamp
|
||||
this._changed.dateModified ?
|
||||
this.dateModified : Zotero.DB.transactionDateTime,
|
||||
Zotero.DB.transactionDateTime,
|
||||
this.libraryID ? this.libraryID : this.libraryID,
|
||||
key
|
||||
];
|
||||
|
||||
|
@ -352,7 +373,7 @@ Zotero.Search.prototype.clone = function() {
|
|||
|
||||
|
||||
Zotero.Search.prototype.addCondition = function(condition, operator, value, required) {
|
||||
if (this.id && !this._loaded) {
|
||||
if ((this.id || this.key) && !this._loaded) {
|
||||
this.load();
|
||||
}
|
||||
|
||||
|
@ -416,7 +437,7 @@ Zotero.Search.prototype.setScope = function (searchObj, includeChildren) {
|
|||
|
||||
|
||||
Zotero.Search.prototype.updateCondition = function(searchConditionID, condition, operator, value, required){
|
||||
if (this.id && !this._loaded) {
|
||||
if ((this.id || this.key) && !this._loaded) {
|
||||
this.load();
|
||||
}
|
||||
|
||||
|
@ -445,7 +466,7 @@ Zotero.Search.prototype.updateCondition = function(searchConditionID, condition,
|
|||
|
||||
|
||||
Zotero.Search.prototype.removeCondition = function(searchConditionID){
|
||||
if (this.id && !this._loaded) {
|
||||
if ((this.id || this.key) && !this._loaded) {
|
||||
this.load();
|
||||
}
|
||||
|
||||
|
@ -462,7 +483,7 @@ Zotero.Search.prototype.removeCondition = function(searchConditionID){
|
|||
* for the given searchConditionID
|
||||
*/
|
||||
Zotero.Search.prototype.getSearchCondition = function(searchConditionID){
|
||||
if (this.id && !this._loaded) {
|
||||
if ((this.id || this.key) && !this._loaded) {
|
||||
this.load();
|
||||
}
|
||||
return this._conditions[searchConditionID];
|
||||
|
@ -474,7 +495,7 @@ Zotero.Search.prototype.getSearchCondition = function(searchConditionID){
|
|||
* used in the search, indexed by searchConditionID
|
||||
*/
|
||||
Zotero.Search.prototype.getSearchConditions = function(){
|
||||
if (this.id && !this._loaded) {
|
||||
if ((this.id || this.key) && !this._loaded) {
|
||||
this.load();
|
||||
}
|
||||
var conditions = [];
|
||||
|
@ -495,7 +516,7 @@ Zotero.Search.prototype.getSearchConditions = function(){
|
|||
|
||||
|
||||
Zotero.Search.prototype.hasPostSearchFilter = function() {
|
||||
if (this.id && !this._loaded) {
|
||||
if ((this.id || this.key) && !this._loaded) {
|
||||
this.load();
|
||||
}
|
||||
for each(var i in this._conditions){
|
||||
|
@ -511,7 +532,7 @@ Zotero.Search.prototype.hasPostSearchFilter = function() {
|
|||
* Run the search and return an array of item ids for results
|
||||
*/
|
||||
Zotero.Search.prototype.search = function(asTempTable){
|
||||
if (this.id && !this._loaded) {
|
||||
if ((this.id || this.key) && !this._loaded) {
|
||||
this.load();
|
||||
}
|
||||
|
||||
|
@ -821,9 +842,10 @@ Zotero.Search.prototype.serialize = function() {
|
|||
var obj = {
|
||||
primary: {
|
||||
id: this.id,
|
||||
libraryID: this.libraryID,
|
||||
key: this.key,
|
||||
dateAdded: this.dateAdded,
|
||||
dateModified: this.dateModified,
|
||||
key: this.key
|
||||
dateModified: this.dateModified
|
||||
},
|
||||
fields: {
|
||||
name: this.name,
|
||||
|
@ -1095,7 +1117,8 @@ Zotero.Search.prototype._buildQuery = function(){
|
|||
condSQL += "NOT ";
|
||||
}
|
||||
condSQL += "IN (";
|
||||
var search = new Zotero.Search(condition.value);
|
||||
var search = new Zotero.Search();
|
||||
search.id = condition.value;
|
||||
|
||||
// Check if there are any post-search filters
|
||||
var hasFilter = search.hasPostSearchFilter();
|
||||
|
@ -1346,10 +1369,14 @@ Zotero.Search.prototype._buildQuery = function(){
|
|||
case 'isNot': // excluded with NOT IN above
|
||||
// Automatically cast values which might
|
||||
// have been stored as integers
|
||||
if (condition.value
|
||||
if (condition.value && typeof condition.value == 'string'
|
||||
&& condition.value.match(/^[1-9]+[0-9]*$/)) {
|
||||
condSQL += ' LIKE ?';
|
||||
}
|
||||
else if (condition.value === null) {
|
||||
condSQL += ' IS NULL';
|
||||
break;
|
||||
}
|
||||
else {
|
||||
condSQL += '=?';
|
||||
}
|
||||
|
@ -1514,7 +1541,9 @@ Zotero.Searches = new function(){
|
|||
function get(id) {
|
||||
var sql = "SELECT COUNT(*) FROM savedSearches WHERE savedSearchID=?";
|
||||
if (Zotero.DB.valueQuery(sql, id)) {
|
||||
return new Zotero.Search(id);
|
||||
var search = new Zotero.Search;
|
||||
search.id = id;
|
||||
return search;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -1548,7 +1577,8 @@ Zotero.Searches = new function(){
|
|||
|
||||
Zotero.DB.beginTransaction();
|
||||
for each(var id in ids) {
|
||||
var search = new Zotero.Search(id);
|
||||
var search = new Zotero.Search;
|
||||
search.id = id;
|
||||
notifierData[id] = { old: search.serialize() };
|
||||
|
||||
var sql = "DELETE FROM savedSearchConditions WHERE savedSearchID=?";
|
||||
|
@ -1883,6 +1913,17 @@ Zotero.SearchConditions = new function(){
|
|||
template: true // mark for special handling
|
||||
},
|
||||
|
||||
{
|
||||
name: 'libraryID',
|
||||
operators: {
|
||||
is: true,
|
||||
isNot: true
|
||||
},
|
||||
table: 'items',
|
||||
field: 'libraryID',
|
||||
special: true
|
||||
},
|
||||
|
||||
{
|
||||
name: 'annotation',
|
||||
operators: {
|
||||
|
|
|
@ -461,7 +461,7 @@ Zotero.Sync.Storage = new function () {
|
|||
* Also marks missing files for downloading
|
||||
*
|
||||
* @param {Integer[]} itemIDs An optional set of item ids to check
|
||||
* @param {Object} itemModTimes Item mod times indexed by item ids
|
||||
* @param {Object} itemModTimes Item mod times indexed by item ids
|
||||
* appearing in itemIDs; if set,
|
||||
* items with stored mod times
|
||||
* that differ from the provided
|
||||
|
@ -497,8 +497,8 @@ Zotero.Sync.Storage = new function () {
|
|||
do {
|
||||
var chunk = itemIDs.splice(0, maxIDs);
|
||||
var sql = "SELECT itemID, linkMode, path, storageModTime, syncState "
|
||||
+ "FROM itemAttachments "
|
||||
+ "WHERE linkMode IN (?,?) AND syncState IN (?,?)";
|
||||
+ "FROM itemAttachments JOIN items USING (itemID) "
|
||||
+ "WHERE linkMode IN (?,?) AND syncState IN (?,?) AND libraryID IS NULL";
|
||||
var params = [
|
||||
Zotero.Attachments.LINK_MODE_IMPORTED_FILE,
|
||||
Zotero.Attachments.LINK_MODE_IMPORTED_URL,
|
||||
|
@ -665,7 +665,7 @@ Zotero.Sync.Storage = new function () {
|
|||
*/
|
||||
this.downloadFile = function (request) {
|
||||
var key = request.name;
|
||||
var item = Zotero.Items.getByKey(key);
|
||||
var item = Zotero.Items.getByLibraryAndKey(null, key);
|
||||
if (!item) {
|
||||
_error("Item '" + key
|
||||
+ "' not found in Zotero.Sync.Storage.downloadFile()");
|
||||
|
@ -735,7 +735,7 @@ Zotero.Sync.Storage = new function () {
|
|||
wbp.saveURI(uri, null, null, null, null, destFile);
|
||||
}
|
||||
catch (e) {
|
||||
request.error(e.message);
|
||||
request.error(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -918,7 +918,7 @@ Zotero.Sync.Storage = new function () {
|
|||
}
|
||||
|
||||
var key = file.replace(/\.(zip|prop)$/, '');
|
||||
var item = Zotero.Items.getByKey(key);
|
||||
var item = Zotero.Items.getByLibraryAndKey(null, key);
|
||||
if (item) {
|
||||
Zotero.debug("Skipping existing file " + file);
|
||||
continue;
|
||||
|
@ -1006,7 +1006,8 @@ Zotero.Sync.Storage = new function () {
|
|||
+ "Zotero.Sync.Storage.resetAllSyncStates()");
|
||||
}
|
||||
|
||||
var sql = "UPDATE itemAttachments SET syncState=?";
|
||||
var sql = "UPDATE itemAttachments SET syncState=? WHERE itemID IN "
|
||||
+ "(SELECT itemID FROM items WHERE libraryID IS NULL)";
|
||||
Zotero.DB.query(sql, [syncState]);
|
||||
|
||||
var sql = "DELETE FROM version WHERE schema='storage'";
|
||||
|
@ -1184,7 +1185,7 @@ Zotero.Sync.Storage = new function () {
|
|||
*/
|
||||
function _createUploadFile(request) {
|
||||
var key = request.name;
|
||||
var item = Zotero.Items.getByKey(key);
|
||||
var item = Zotero.Items.getByLibraryAndKey(null, key);
|
||||
Zotero.debug("Creating zip file for item " + item.key);
|
||||
|
||||
try {
|
||||
|
@ -1222,7 +1223,7 @@ Zotero.Sync.Storage = new function () {
|
|||
return true;
|
||||
}
|
||||
catch (e) {
|
||||
request.error(e.message);
|
||||
request.error(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1273,7 +1274,7 @@ Zotero.Sync.Storage = new function () {
|
|||
*/
|
||||
|
||||
var request = data.request;
|
||||
var item = Zotero.Items.getByKey(request.name);
|
||||
var item = Zotero.Items.getByLibraryAndKey(null, request.name);
|
||||
|
||||
Zotero.Sync.Storage.getStorageModificationTime(item, function (item, mdate) {
|
||||
if (!request.isRunning()) {
|
||||
|
@ -1378,7 +1379,7 @@ Zotero.Sync.Storage = new function () {
|
|||
channel.asyncOpen(listener, null);
|
||||
}
|
||||
catch (e) {
|
||||
request.error(e.message);
|
||||
request.error(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -1459,7 +1460,8 @@ Zotero.Sync.Storage = new function () {
|
|||
* @return {Number[]} Array of attachment itemIDs
|
||||
*/
|
||||
function _getFilesToDownload() {
|
||||
var sql = "SELECT itemID FROM itemAttachments WHERE syncState IN (?,?)";
|
||||
var sql = "SELECT itemID FROM itemAttachments JOIN items USING (itemID) "
|
||||
+ "WHERE syncState IN (?,?) AND libraryID IS NULL";
|
||||
return Zotero.DB.columnQuery(sql,
|
||||
[
|
||||
Zotero.Sync.Storage.SYNC_STATE_TO_DOWNLOAD,
|
||||
|
@ -1476,8 +1478,8 @@ Zotero.Sync.Storage = new function () {
|
|||
* @return {Number[]} Array of attachment itemIDs
|
||||
*/
|
||||
function _getFilesToUpload() {
|
||||
var sql = "SELECT itemID FROM itemAttachments WHERE syncState IN (?,?) "
|
||||
+ "AND linkMode IN (?,?)";
|
||||
var sql = "SELECT itemID FROM itemAttachments JOIN items USING (itemID) "
|
||||
+ "WHERE syncState IN (?,?) AND linkMode IN (?,?) AND libraryID IS NULL";
|
||||
return Zotero.DB.columnQuery(sql,
|
||||
[
|
||||
Zotero.Sync.Storage.SYNC_STATE_TO_UPLOAD,
|
||||
|
@ -2371,7 +2373,7 @@ Zotero.Sync.Storage.QueueManager = new function () {
|
|||
function _reconcileConflicts() {
|
||||
var objectPairs = [];
|
||||
for each(var conflict in _conflicts) {
|
||||
var item = Zotero.Items.getByKey(conflict.name);
|
||||
var item = Zotero.Items.getByLibraryAndKey(null, conflict.name);
|
||||
var item1 = item.clone();
|
||||
item1.setField('dateModified',
|
||||
Zotero.Date.dateToSQL(new Date(conflict.localData.modTime * 1000), true));
|
||||
|
@ -2406,7 +2408,7 @@ Zotero.Sync.Storage.QueueManager = new function () {
|
|||
// Since we're only putting cloned items into the merge window,
|
||||
// we have to manually set the ids
|
||||
for (var i=0; i<_conflicts.length; i++) {
|
||||
io.dataOut[i].id = Zotero.Items.getByKey(_conflicts[i].name).id;
|
||||
io.dataOut[i].id = Zotero.Items.getByLibraryAndKey(null, _conflicts[i].name).id;
|
||||
}
|
||||
|
||||
return io.dataOut;
|
||||
|
@ -2876,6 +2878,8 @@ Zotero.Sync.Storage.Request.prototype.onProgress = function (channel, progress,
|
|||
|
||||
|
||||
Zotero.Sync.Storage.Request.prototype.error = function (msg) {
|
||||
msg = typeof msg == 'object' ? msg.message : msg;
|
||||
|
||||
this.queue.logError(msg);
|
||||
|
||||
// DEBUG: ever need to stop channel?
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -265,8 +265,8 @@ Zotero.Translator.prototype.logError = function(message, type, line, lineNumber,
|
|||
* setItems). setting items disables export of collections.
|
||||
* path - the path to the target; for web, this is the same as location
|
||||
* string - the string content to be used as a file.
|
||||
* saveItem - whether new items should be saved to the database. defaults to
|
||||
* true; set using second argument of constructor.
|
||||
* libraryID - libraryID (e.g., of a group) of saved database items. null for local items,
|
||||
* or false not to save. defaults to null; set using second argument of constructor.
|
||||
* newItems - items created when translate() was called
|
||||
* newCollections - collections created when translate() was called
|
||||
*
|
||||
|
@ -305,7 +305,11 @@ Zotero.Translator.prototype.logError = function(message, type, line, lineNumber,
|
|||
*
|
||||
* output - export output (if no location has been specified)
|
||||
*/
|
||||
Zotero.Translate = function(type, saveItem, saveAttachments) {
|
||||
Zotero.Translate = function(type) {
|
||||
if (arguments.length > 1) {
|
||||
throw ("Zotero.Translate only takes one parameter");
|
||||
}
|
||||
|
||||
this.type = type;
|
||||
|
||||
// import = 0001 = 1
|
||||
|
@ -335,9 +339,6 @@ Zotero.Translate = function(type, saveItem, saveAttachments) {
|
|||
}
|
||||
this._numericTypes = this._numericTypes.substr(1);
|
||||
|
||||
this.saveItem = !(saveItem === false);
|
||||
this.saveAttachments = !(saveAttachments === false);
|
||||
|
||||
this._handlers = new Array();
|
||||
this._streams = new Array();
|
||||
}
|
||||
|
@ -606,10 +607,15 @@ Zotero.Translate.prototype._loadTranslator = function() {
|
|||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* does the actual translation
|
||||
*
|
||||
* @param {NULL|Integer|FALSE} [libraryID=null] Library in which to save items,
|
||||
* or NULL for default library;
|
||||
* if FALSE, don't save items
|
||||
* @param {Boolean} [saveAttachments=true]
|
||||
*/
|
||||
Zotero.Translate.prototype.translate = function() {
|
||||
Zotero.Translate.prototype.translate = function(libraryID, saveAttachments) {
|
||||
/*
|
||||
* initialize properties
|
||||
*/
|
||||
|
@ -629,6 +635,24 @@ Zotero.Translate.prototype.translate = function() {
|
|||
throw("cannot translate: no location specified");
|
||||
}
|
||||
|
||||
this.libraryID = (libraryID == undefined) ? null : libraryID;
|
||||
this.saveAttachments = !(saveAttachments === false);
|
||||
this.saveFiles = this.saveAttachments;
|
||||
|
||||
// If group filesEditable==false, don't save attachments
|
||||
if (this.libraryID) {
|
||||
var type = Zotero.Libraries.getType(this.libraryID);
|
||||
switch (type) {
|
||||
case 'group':
|
||||
var groupID = Zotero.Groups.getGroupIDFromLibraryID(this.libraryID);
|
||||
var group = Zotero.Groups.get(groupID);
|
||||
if (!group.filesEditable) {
|
||||
this.saveFiles = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// erroring should end
|
||||
this.error = this._translationComplete;
|
||||
|
||||
|
@ -750,7 +774,7 @@ Zotero.Translate.prototype._generateSandbox = function() {
|
|||
|
||||
// for loading other translators and accessing their methods
|
||||
this._sandbox.Zotero.loadTranslator = function(type) {
|
||||
var translation = new Zotero.Translate(type, false);
|
||||
var translation = new Zotero.Translate(type);
|
||||
translation._parentTranslator = me;
|
||||
|
||||
if(type == "export" && (this.type == "web" || this.type == "search")) {
|
||||
|
@ -781,7 +805,7 @@ Zotero.Translate.prototype._generateSandbox = function() {
|
|||
}
|
||||
}
|
||||
|
||||
return translation.translate()
|
||||
return translation.translate(false);
|
||||
};
|
||||
safeTranslator.getTranslatorObject = function() {
|
||||
// load the translator into our sandbox
|
||||
|
@ -1134,7 +1158,7 @@ Zotero.Translate.prototype._itemDone = function(item, attachedTo) {
|
|||
|
||||
this._itemsDone = true;
|
||||
|
||||
if(!this.saveItem) { // if we're not supposed to save the item, just
|
||||
if(this.libraryID === false) { // if we're not supposed to save the item, just
|
||||
// return the item array
|
||||
|
||||
// if a parent sandbox exists, use complete() function from that sandbox
|
||||
|
@ -1151,7 +1175,8 @@ Zotero.Translate.prototype._itemDone = function(item, attachedTo) {
|
|||
var type = (item.itemType ? item.itemType : "webpage");
|
||||
|
||||
if(type == "note") { // handle notes differently
|
||||
var newItem = new Zotero.Item(false, 'note');
|
||||
var newItem = new Zotero.Item('note');
|
||||
newItem.libraryID = this.libraryID ? this.libraryID : null;
|
||||
newItem.setNote(item.note);
|
||||
var myID = newItem.save();
|
||||
// re-retrieve the item
|
||||
|
@ -1248,7 +1273,8 @@ Zotero.Translate.prototype._itemDone = function(item, attachedTo) {
|
|||
}
|
||||
} else {
|
||||
var typeID = Zotero.ItemTypes.getID(type);
|
||||
var newItem = new Zotero.Item(false, typeID);
|
||||
var newItem = new Zotero.Item(typeID);
|
||||
newItem.libraryID = this.libraryID ? this.libraryID : null;
|
||||
}
|
||||
|
||||
// makes looping through easier
|
||||
|
@ -1280,7 +1306,7 @@ Zotero.Translate.prototype._itemDone = function(item, attachedTo) {
|
|||
}
|
||||
|
||||
// Single-field mode
|
||||
if (data[j].fieldMode == 1) {
|
||||
if (data[j].fieldMode && data[j].fieldMode == 1) {
|
||||
var fields = {
|
||||
lastName: data[j].lastName,
|
||||
fieldMode: 1
|
||||
|
@ -1294,14 +1320,19 @@ Zotero.Translate.prototype._itemDone = function(item, attachedTo) {
|
|||
};
|
||||
}
|
||||
|
||||
var creator = null;
|
||||
var creatorDataID = Zotero.Creators.getDataID(fields);
|
||||
if(creatorDataID) {
|
||||
var linkedCreators = Zotero.Creators.getCreatorsWithData(creatorDataID);
|
||||
// TODO: support identical creators via popup? ugh...
|
||||
var creatorID = linkedCreators[0];
|
||||
var creator = Zotero.Creators.get(creatorID);
|
||||
} else {
|
||||
var creator = new Zotero.Creator;
|
||||
var linkedCreators = Zotero.Creators.getCreatorsWithData(creatorDataID, this.libraryID);
|
||||
if (linkedCreators) {
|
||||
// TODO: support identical creators via popup? ugh...
|
||||
var creatorID = linkedCreators[0];
|
||||
creator = Zotero.Creators.get(creatorID);
|
||||
}
|
||||
}
|
||||
if(!creator) {
|
||||
creator = new Zotero.Creator;
|
||||
creator.libraryID = this.libraryID ? this.libraryID : null;
|
||||
creator.setFields(fields);
|
||||
var creatorID = creator.save();
|
||||
}
|
||||
|
@ -1375,7 +1406,8 @@ Zotero.Translate.prototype._itemDone = function(item, attachedTo) {
|
|||
// handle notes
|
||||
if(item.notes) {
|
||||
for each(var note in item.notes) {
|
||||
var myNote = new Zotero.Item(false, 'note');
|
||||
var myNote = new Zotero.Item('note');
|
||||
myNote.libraryID = this.libraryID ? this.libraryID : null;
|
||||
myNote.setNote(note.note);
|
||||
if (myID) {
|
||||
myNote.setSource(myID);
|
||||
|
@ -1423,9 +1455,9 @@ Zotero.Translate.prototype._itemDone = function(item, attachedTo) {
|
|||
Zotero.debug("Translate: Error adding attachment "+attachment.url, 2);
|
||||
}
|
||||
}
|
||||
} else if(attachment.document
|
||||
} else if(this.saveFiles && (attachment.document
|
||||
|| (attachment.mimeType && attachment.mimeType == "text/html")
|
||||
|| downloadAssociatedFiles) {
|
||||
|| downloadAssociatedFiles)) {
|
||||
|
||||
// if snapshot is not explicitly set to false, retrieve snapshot
|
||||
if(attachment.document) {
|
||||
|
@ -1438,8 +1470,8 @@ Zotero.Translate.prototype._itemDone = function(item, attachedTo) {
|
|||
}
|
||||
// Save attachment if snapshot pref enabled or not HTML
|
||||
// (in which case downloadAssociatedFiles applies)
|
||||
} else if(automaticSnapshots || !attachment.mimeType
|
||||
|| attachment.mimeType != "text/html") {
|
||||
} else if(this.saveFiles && (automaticSnapshots || !attachment.mimeType
|
||||
|| attachment.mimeType != "text/html")) {
|
||||
var mimeType = null;
|
||||
var title = null;
|
||||
|
||||
|
|
112
chrome/content/zotero/xpcom/uri.js
Normal file
112
chrome/content/zotero/xpcom/uri.js
Normal file
|
@ -0,0 +1,112 @@
|
|||
Zotero.URI = new function () {
|
||||
var _baseURI = ZOTERO_CONFIG.BASE_URI;
|
||||
|
||||
|
||||
this.getCurrentUserURI = function () {
|
||||
var userID = Zotero.userID;
|
||||
if (userID) {
|
||||
return _baseURI + "users/" + userID;
|
||||
}
|
||||
|
||||
return _baseURI + "users/local/" + Zotero.getLocalUserKey(true);
|
||||
}
|
||||
|
||||
|
||||
this.getLibraryURI = function (libraryID) {
|
||||
var libraryType = Zotero.Libraries.getType(libraryID);
|
||||
switch (libraryType) {
|
||||
case 'group':
|
||||
var id = Zotero.Groups.getGroupIDFromLibraryID(libraryID);
|
||||
break;
|
||||
|
||||
case 'user':
|
||||
throw ("User library ids are not supported in Zotero.URI.getLibraryURI");
|
||||
|
||||
default:
|
||||
throw ("Unsupported library type '" + libraryType + "' in Zotero.URI.getLibraryURI()");
|
||||
}
|
||||
return _baseURI + libraryType + "s/" + id;
|
||||
}
|
||||
|
||||
|
||||
this.getItemURI = function (item) {
|
||||
if (item.libraryID) {
|
||||
var baseURI = this.getLibraryURI(item.libraryID);
|
||||
}
|
||||
else {
|
||||
var baseURI = this.getCurrentUserURI();
|
||||
}
|
||||
return baseURI + "/items/" + item.key;
|
||||
}
|
||||
|
||||
|
||||
this.getGroupsURL = function () {
|
||||
return ZOTERO_CONFIG.WWW_BASE_URL + "groups";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {Zotero.Group} group
|
||||
* @return {String}
|
||||
*/
|
||||
this.getGroupURI = function (group, webRoot) {
|
||||
var uri = _baseURI + "groups/" + group.id;
|
||||
if (webRoot) {
|
||||
uri = uri.replace(ZOTERO_CONFIG.BASE_URI, ZOTERO_CONFIG.WWW_BASE_URL);
|
||||
}
|
||||
return uri;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert an item URI into an item
|
||||
*
|
||||
* @param {String} itemURI
|
||||
* @param {Zotero.Item|FALSE}
|
||||
*/
|
||||
this.getURIItem = function (itemURI) {
|
||||
var libraryType = null;
|
||||
|
||||
// If this is a local URI, compare to the local user key
|
||||
if (itemURI.match(/\/users\/local\//)) {
|
||||
var currentUserURI = this.getCurrentUserURI() + "/";
|
||||
if (itemURI.indexOf(currentUserURI) == 0) {
|
||||
itemURI = itemURI.substr(currentUserURI.length);
|
||||
var libraryType = 'user';
|
||||
var libraryTypeID = null;
|
||||
}
|
||||
}
|
||||
|
||||
// If not found, try global URI
|
||||
if (!libraryType) {
|
||||
if (itemURI.indexOf(_baseURI) != 0) {
|
||||
throw ("Invalid base URI '" + itemURI + "' in Zotero.URI.getURIItem()");
|
||||
}
|
||||
itemURI = itemURI.substr(_baseURI.length);
|
||||
var typeRE = /^(users|groups)\/([0-9]+)\//;
|
||||
var matches = itemURI.match(typeRE);
|
||||
if (!matches) {
|
||||
throw ("Invalid library URI '" + itemURI + "' in Zotero.URI.getURIItem()");
|
||||
}
|
||||
var libraryType = matches[1].substr(0, matches[1].length-1);
|
||||
var libraryTypeID = matches[2];
|
||||
itemURI = itemURI.replace(typeRE, '');
|
||||
}
|
||||
|
||||
// TODO: itemID-based URI?
|
||||
var matches = itemURI.match(/items\/([A-Z0-9]{8})/);
|
||||
if (!matches) {
|
||||
throw ("Invalid item URI '" + itemURI + "' in Zotero.URI.getURIItem()");
|
||||
}
|
||||
var itemKey = matches[1];
|
||||
|
||||
if (libraryType == 'user') {
|
||||
return Zotero.Items.getByLibraryAndKey(null, itemKey);
|
||||
}
|
||||
|
||||
if (libraryType == 'group') {
|
||||
var libraryID = Zotero.Groups.getLibraryIDFromGroupID(libraryTypeID);
|
||||
return Zotero.Items.getByLibraryAndKey(libraryID, itemKey);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -27,6 +27,8 @@ const ZOTERO_CONFIG = {
|
|||
REPOSITORY_CHECK_INTERVAL: 86400, // 24 hours
|
||||
REPOSITORY_RETRY_INTERVAL: 3600, // 1 hour
|
||||
FIRST_RUN_URL: 'http://www.zotero.org/support/quick_start_guide',
|
||||
BASE_URI: 'http://zotero.org/',
|
||||
WWW_BASE_URL: 'http://www.zotero.org/',
|
||||
SYNC_URL: 'https://sync.zotero.org/'
|
||||
};
|
||||
|
||||
|
@ -62,7 +64,6 @@ var Zotero = new function(){
|
|||
this.hasValues = hasValues;
|
||||
this.randomString = randomString;
|
||||
this.moveToUnique = moveToUnique;
|
||||
this.reloadDataObjects = reloadDataObjects;
|
||||
|
||||
// Public properties
|
||||
this.initialized = false;
|
||||
|
@ -77,6 +78,49 @@ var Zotero = new function(){
|
|||
this.isWin;
|
||||
this.initialURL; // used by Schema to show the changelog on upgrades
|
||||
|
||||
|
||||
this.__defineGetter__('userID', function () {
|
||||
var sql = "SELECT value FROM settings WHERE "
|
||||
+ "setting='account' AND key='userID'";
|
||||
return Zotero.DB.valueQuery(sql);
|
||||
});
|
||||
|
||||
this.__defineSetter__('userID', function (val) {
|
||||
var sql = "REPLACE INTO settings VALUES ('account', 'userID', ?)";
|
||||
Zotero.DB.query(sql, parseInt(val));
|
||||
});
|
||||
|
||||
this.__defineGetter__('libraryID', function () {
|
||||
var sql = "SELECT value FROM settings WHERE "
|
||||
+ "setting='account' AND key='libraryID'";
|
||||
return Zotero.DB.valueQuery(sql);
|
||||
});
|
||||
|
||||
this.__defineSetter__('libraryID', function (val) {
|
||||
var sql = "REPLACE INTO settings VALUES ('account', 'libraryID', ?)";
|
||||
Zotero.DB.query(sql, parseInt(val));
|
||||
});
|
||||
|
||||
this.getLocalUserKey = function (generate) {
|
||||
if (_localUserKey) {
|
||||
return _localUserKey;
|
||||
}
|
||||
|
||||
var sql = "SELECT value FROM settings WHERE "
|
||||
+ "setting='account' AND key='localUserKey'";
|
||||
var key = Zotero.DB.valueQuery(sql);
|
||||
|
||||
// Generate a local user key if we don't have a global library id
|
||||
if (!key && generate) {
|
||||
key = Zotero.randomString(8);
|
||||
var sql = "INSERT INTO settings VALUES ('account', 'localUserKey', ?)";
|
||||
Zotero.DB.query(sql, key);
|
||||
}
|
||||
_localUserKey = key;
|
||||
return key;
|
||||
};
|
||||
|
||||
|
||||
var _startupError;
|
||||
var _startupErrorHandler;
|
||||
var _zoteroDirectory = false;
|
||||
|
@ -85,7 +129,7 @@ var Zotero = new function(){
|
|||
var _debugTime;
|
||||
var _debugLastTime;
|
||||
var _localizedStringBundle;
|
||||
|
||||
var _localUserKey;
|
||||
|
||||
/*
|
||||
* Initialize the extension
|
||||
|
@ -841,19 +885,21 @@ var Zotero = new function(){
|
|||
* values and/or an arbitrary number of individual values
|
||||
*/
|
||||
function flattenArguments(args){
|
||||
var isArguments = args.callee && args.length;
|
||||
|
||||
// Put passed scalar values into an array
|
||||
if (typeof args!='object' || args===null){
|
||||
if (args === null || (args.constructor.name != 'Array' && !isArguments)) {
|
||||
args = [args];
|
||||
}
|
||||
|
||||
var returns = new Array();
|
||||
|
||||
var returns = [];
|
||||
for (var i=0; i<args.length; i++){
|
||||
if (typeof args[i]=='object'){
|
||||
if(args[i]) {
|
||||
for (var j=0; j<args[i].length; j++){
|
||||
returns.push(args[i][j]);
|
||||
}
|
||||
if (!args[i]) {
|
||||
continue;
|
||||
}
|
||||
if (args[i].constructor.name == 'Array') {
|
||||
for (var j=0; j<args[i].length; j++){
|
||||
returns.push(args[i][j]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -987,7 +1033,7 @@ var Zotero = new function(){
|
|||
}
|
||||
|
||||
|
||||
function reloadDataObjects() {
|
||||
this.reloadDataObjects = function () {
|
||||
Zotero.Tags.reloadAll();
|
||||
Zotero.Collections.reloadAll();
|
||||
Zotero.Creators.reloadAll();
|
||||
|
@ -2129,7 +2175,7 @@ Zotero.DragDrop = {
|
|||
dragData.dataType = 'text/x-moz-url';
|
||||
var urls = [];
|
||||
for (var i=0; i<len; i++) {
|
||||
var url = dt.getData("application/x-moz-url", i).split("\n")[0];
|
||||
var url = dt.getData("text/x-moz-url").split("\n")[0];
|
||||
urls.push(url);
|
||||
}
|
||||
dragData.data = urls;
|
||||
|
|
BIN
chrome/skin/default/zotero/group_add.png
Executable file
BIN
chrome/skin/default/zotero/group_add.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 807 B |
|
@ -69,7 +69,7 @@ zoteromergegroup {
|
|||
overflow-y: auto;
|
||||
}
|
||||
|
||||
zoteromergepane #delete-box {
|
||||
zoteromergepane #trash-box, zoteromergepane #delete-box {
|
||||
min-width: 15em;
|
||||
-moz-box-align: center;
|
||||
-moz-box-pack: center;
|
||||
|
|
|
@ -115,6 +115,12 @@ window[active="true"] #zotero-pane[fullscreenmode="true"][platform="mac"]
|
|||
margin-top: -2px;
|
||||
}
|
||||
|
||||
#zotero-tb-group-add
|
||||
{
|
||||
list-style-image: url('chrome://zotero/skin/group_add.png');
|
||||
}
|
||||
|
||||
|
||||
#zotero-tb-tag-selector
|
||||
{
|
||||
list-style-image: url(chrome://zotero/skin/tag-selector.png);
|
||||
|
@ -283,6 +289,10 @@ window[active="true"] #zotero-pane[fullscreenmode="true"][platform="mac"]
|
|||
list-style-image: url('chrome://zotero/skin/search-cancel-active.png');
|
||||
}
|
||||
|
||||
#zotero-view-tabs tab
|
||||
{
|
||||
}
|
||||
|
||||
#zotero-view-item > vbox
|
||||
{
|
||||
overflow: auto;
|
||||
|
|
BIN
chrome/skin/default/zotero/treesource-groups.png
Executable file
BIN
chrome/skin/default/zotero/treesource-groups.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 753 B |
|
@ -109,13 +109,14 @@ function ChromeExtensionHandler() {
|
|||
break;
|
||||
|
||||
case 'search':
|
||||
var s = new Zotero.Search(ids);
|
||||
var ids = s.search();
|
||||
var s = new Zotero.Search();
|
||||
s.id = ids;
|
||||
ids = s.search();
|
||||
break;
|
||||
|
||||
case 'items':
|
||||
case 'item':
|
||||
var ids = ids.split('-');
|
||||
ids = ids.split('-');
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -30,8 +30,13 @@ var xpcomFiles = [
|
|||
'data/collections',
|
||||
'data/creator',
|
||||
'data/creators',
|
||||
'data/group',
|
||||
'data/groups',
|
||||
'data/itemFields',
|
||||
'data/notes',
|
||||
'data/libraries',
|
||||
'data/relation',
|
||||
'data/relations',
|
||||
'data/tag',
|
||||
'data/tags',
|
||||
'db',
|
||||
|
@ -57,6 +62,7 @@ var xpcomFiles = [
|
|||
'storage',
|
||||
'timeline',
|
||||
'translate',
|
||||
'uri',
|
||||
'utilities',
|
||||
'zeroconf'
|
||||
];
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
<em:id>zotero@chnm.gmu.edu</em:id>
|
||||
<em:name>Zotero</em:name>
|
||||
<em:version>1.5b2.SVN</em:version>
|
||||
<em:version>2.0b3.SVN</em:version>
|
||||
<em:creator>Center for History and New Media<br/>George Mason University</em:creator>
|
||||
<em:contributor>Dan Cohen</em:contributor>
|
||||
<em:contributor>Sean Takats</em:contributor>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
-- 22
|
||||
-- 24
|
||||
|
||||
-- This file creates system tables that can be safely wiped and reinitialized
|
||||
-- at any time, as long as existing ids are preserved.
|
||||
|
@ -275,6 +275,7 @@ INSERT INTO fields VALUES (114,'proceedingsTitle',NULL);
|
|||
INSERT INTO fields VALUES (115,'bookTitle',NULL);
|
||||
INSERT INTO fields VALUES (116,'shortTitle',NULL);
|
||||
INSERT INTO fields VALUES (117,'docketNumber',NULL);
|
||||
INSERT INTO fields VALUES (118,'numPages',NULL);
|
||||
|
||||
INSERT INTO itemTypeFields VALUES (2, 110, NULL, 1);
|
||||
INSERT INTO itemTypeFields VALUES (2, 90, NULL, 2);
|
||||
|
@ -286,7 +287,7 @@ INSERT INTO itemTypeFields VALUES (2, 6, NULL, 7);
|
|||
INSERT INTO itemTypeFields VALUES (2, 7, NULL, 8);
|
||||
INSERT INTO itemTypeFields VALUES (2, 8, NULL, 9);
|
||||
INSERT INTO itemTypeFields VALUES (2, 14, NULL, 10);
|
||||
INSERT INTO itemTypeFields VALUES (2, 10, NULL, 11);
|
||||
INSERT INTO itemTypeFields VALUES (2, 118, NULL, 11);
|
||||
INSERT INTO itemTypeFields VALUES (2, 87, NULL, 12);
|
||||
INSERT INTO itemTypeFields VALUES (2, 11, NULL, 13);
|
||||
INSERT INTO itemTypeFields VALUES (2, 116, NULL, 14);
|
||||
|
@ -408,7 +409,7 @@ INSERT INTO itemTypeFields VALUES (9, 90, NULL, 2);
|
|||
INSERT INTO itemTypeFields VALUES (9, 66, NULL, 3);
|
||||
INSERT INTO itemTypeFields VALUES (9, 7, NULL, 4);
|
||||
INSERT INTO itemTypeFields VALUES (9, 14, NULL, 5);
|
||||
INSERT INTO itemTypeFields VALUES (9, 10, NULL, 6);
|
||||
INSERT INTO itemTypeFields VALUES (9, 118, NULL, 6);
|
||||
INSERT INTO itemTypeFields VALUES (9, 87, NULL, 7);
|
||||
INSERT INTO itemTypeFields VALUES (9, 116, NULL, 8);
|
||||
INSERT INTO itemTypeFields VALUES (9, 1, NULL, 9);
|
||||
|
@ -1253,3 +1254,4 @@ INSERT INTO "syncObjectTypes" VALUES(2, 'creator');
|
|||
INSERT INTO "syncObjectTypes" VALUES(3, 'item');
|
||||
INSERT INTO "syncObjectTypes" VALUES(4, 'search');
|
||||
INSERT INTO "syncObjectTypes" VALUES(5, 'tag');
|
||||
INSERT INTO "syncObjectTypes" VALUES(6, 'relations');
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"translatorType":4,
|
||||
"label":"zotero.org",
|
||||
"creator":"Dan Stillman",
|
||||
"target":"^https?://[^/]*zotero\\.org/[^/]+/[0-9]+/(items(/?[0-9]+?)?|items/collection/[0-9]+)(\\?.*)?$",
|
||||
"target":"^https?://[^/]*zotero\\.net/(groups/)?[^/]+/[0-9]+/(items(/?[0-9]+?)?|items/collection/[0-9]+)(\\?.*)?$",
|
||||
"minVersion":"1.0",
|
||||
"maxVersion":"",
|
||||
"priority":100,
|
||||
|
@ -16,7 +16,7 @@ function detectWeb(doc, url) {
|
|||
var nsResolver = namespace ? function(prefix) {
|
||||
if (prefix == 'x') return namespace; else return null;
|
||||
} : null;
|
||||
var a = doc.evaluate('//div[@id="login-links"]/a[text()="My Library"]', doc, nsResolver, XPathResult.ANY_TYPE, null).iterateNext();
|
||||
var a = doc.evaluate('//li[@class="topnav"]/a[text()="My Library"]', doc, nsResolver, XPathResult.ANY_TYPE, null).iterateNext();
|
||||
// Skip current user's library
|
||||
if (a && url.indexOf(a.href.match(/(^.+)\/items/)[1]) == 0) {
|
||||
return false;
|
||||
|
@ -131,10 +131,20 @@ function xmlToItem(xmlItem) {
|
|||
|
||||
}
|
||||
|
||||
|
||||
function doWeb(doc, url) {
|
||||
var userID = url.match(/^http:\/\/[^\/]*zotero\.org\/[^\/]+\/([0-9]+)/)[1];
|
||||
var apiPrefix = "https://api.zotero.org/users/" + userID + "/";
|
||||
var itemRe = /^http:\/\/[^\/]*zotero\.org\/[^\/]+\/[0-9]+\/items\/([0-9]+)/;
|
||||
if (url.indexOf("/groups/") == -1) {
|
||||
var userID = url.match(/^http:\/\/[^\/]*zotero\.net\/[^\/]+\/([0-9]+)/)[1];
|
||||
var apiPrefix = "https://apidev.zotero.org/users/" + userID + "/";
|
||||
var itemRe = /^http:\/\/[^\/]*zotero\.net\/[^\/]+\/[0-9]+\/items\/([0-9]+)/;
|
||||
} else {
|
||||
//var groupID = url.match(/^http:\/\/[^\/]*zotero\.net\/groups\/[^\/]+\/([0-9]+)/)[1]; // need slug url fix
|
||||
var groupID = url.match(/^http:\/\/[^\/]*zotero\.net\/groups\/([0-9]+)/)[1];
|
||||
var apiPrefix = "https://apidev.zotero.org/groups/" + groupID + "/";
|
||||
//var itemRe = /^http:\/\/[^\/]*zotero\.net\/groups\/[^\/]+\/[0-9]+\/items\/([0-9]+)/;
|
||||
var itemRe = /^http:\/\/[^\/]*zotero\.net\/groups\/[0-9]+\/items\/([0-9]+)/;
|
||||
}
|
||||
|
||||
var nsAtom = new Namespace('http://www.w3.org/2005/Atom');
|
||||
var nsZXfer = new Namespace('http://zotero.org/namespaces/transfer');
|
||||
|
||||
|
@ -143,7 +153,7 @@ function doWeb(doc, url) {
|
|||
var nsResolver = namespace ? function(prefix) {
|
||||
if (prefix == 'x') return namespace; else return null;
|
||||
} : null;
|
||||
var column = doc.evaluate('//table[@id="field-table"]//td[1][@class="title"]', doc, nsResolver, XPathResult.ANY_TYPE, null);
|
||||
var column = doc.evaluate('//table[@id="field-table"]//td[1][@class="title"][not(contains(./a, "Unpublished Note"))]', doc, nsResolver, XPathResult.ANY_TYPE, null);
|
||||
var elems = [], td;
|
||||
while (td = column.iterateNext()) {
|
||||
elems.push(td);
|
||||
|
|
441
triggers.sql
441
triggers.sql
|
@ -1,4 +1,4 @@
|
|||
-- 4
|
||||
-- 9
|
||||
|
||||
-- Triggers to validate date field
|
||||
DROP TRIGGER IF EXISTS insert_date_field;
|
||||
|
@ -97,6 +97,47 @@ CREATE TRIGGER fku_collections_collectionID_collections_parentCollectionID
|
|||
UPDATE collections SET parentCollectionID=NEW.collectionID WHERE parentCollectionID=OLD.collectionID;
|
||||
END;
|
||||
|
||||
-- Don't allow collection parents in different libraries
|
||||
DROP TRIGGER IF EXISTS fki_collections_parentCollectionID_libraryID;
|
||||
CREATE TRIGGER fki_collections_parentCollectionID_libraryID
|
||||
BEFORE INSERT ON collections
|
||||
FOR EACH ROW BEGIN
|
||||
SELECT RAISE(ABORT, 'insert on table "collections" violates foreign key constraint "fki_collections_parentCollectionID_libraryID"')
|
||||
WHERE NEW.parentCollectionID IS NOT NULL AND
|
||||
(
|
||||
(
|
||||
NEW.libraryID IS NULL
|
||||
AND
|
||||
(SELECT libraryID FROM collections WHERE collectionID = NEW.parentCollectionID) IS NOT NULL
|
||||
) OR (
|
||||
NEW.libraryID IS NOT NULL
|
||||
AND
|
||||
(SELECT libraryID FROM collections WHERE collectionID = NEW.parentCollectionID) IS NULL
|
||||
) OR
|
||||
NEW.libraryID != (SELECT libraryID FROM collections WHERE collectionID = NEW.parentCollectionID)
|
||||
);
|
||||
END;
|
||||
|
||||
DROP TRIGGER IF EXISTS fku_collections_parentCollectionID_libraryID;
|
||||
CREATE TRIGGER fku_collections_parentCollectionID_libraryID
|
||||
BEFORE UPDATE ON collections
|
||||
FOR EACH ROW BEGIN
|
||||
SELECT RAISE(ABORT, 'update on table "collections" violates foreign key constraint "fku_collections_parentCollectionID_libraryID"')
|
||||
WHERE NEW.parentCollectionID IS NOT NULL AND
|
||||
(
|
||||
(
|
||||
NEW.libraryID IS NULL
|
||||
AND
|
||||
(SELECT libraryID FROM collections WHERE collectionID = NEW.parentCollectionID) IS NOT NULL
|
||||
) OR (
|
||||
NEW.libraryID IS NOT NULL
|
||||
AND
|
||||
(SELECT libraryID FROM collections WHERE collectionID = NEW.parentCollectionID) IS NULL
|
||||
) OR
|
||||
NEW.libraryID != (SELECT libraryID FROM collections WHERE collectionID = NEW.parentCollectionID)
|
||||
);
|
||||
END;
|
||||
|
||||
-- collectionItems/collectionID
|
||||
DROP TRIGGER IF EXISTS fki_collectionItems_collectionID_collections_collectionID;
|
||||
CREATE TRIGGER fki_collectionItems_collectionID_collections_collectionID
|
||||
|
@ -161,6 +202,76 @@ CREATE TRIGGER fku_items_itemID_collectionItems_itemID
|
|||
UPDATE collectionItems SET collectionID=NEW.itemID WHERE collectionID=OLD.itemID;
|
||||
END;
|
||||
|
||||
-- collectionItems libraryID
|
||||
DROP TRIGGER IF EXISTS fki_collectionItems_libraryID;
|
||||
CREATE TRIGGER fki_collectionItems_libraryID
|
||||
BEFORE INSERT ON collectionItems
|
||||
FOR EACH ROW BEGIN
|
||||
SELECT RAISE(ABORT, 'insert on table "collectionItems" violates foreign key constraint "fki_collectionItems_libraryID"')
|
||||
WHERE (
|
||||
(SELECT libraryID FROM collections WHERE collectionID = NEW.collectionID) IS NULL
|
||||
AND
|
||||
(SELECT libraryID FROM items WHERE itemID = NEW.itemID) IS NOT NULL
|
||||
) OR (
|
||||
(SELECT libraryID FROM collections WHERE collectionID = NEW.collectionID) IS NOT NULL
|
||||
AND
|
||||
(SELECT libraryID FROM items WHERE itemID = NEW.itemID) IS NULL
|
||||
) OR
|
||||
(SELECT libraryID FROM collections WHERE collectionID = NEW.collectionID) != (SELECT libraryID FROM items WHERE itemID = NEW.itemID);
|
||||
END;
|
||||
|
||||
DROP TRIGGER IF EXISTS fku_collectionItems_libraryID;
|
||||
CREATE TRIGGER fku_collectionItems_libraryID
|
||||
BEFORE UPDATE ON collectionItems
|
||||
FOR EACH ROW BEGIN
|
||||
SELECT RAISE(ABORT, 'update on table "collectionItems" violates foreign key constraint "fku_collectionItems_libraryID"')
|
||||
WHERE (
|
||||
(SELECT libraryID FROM collections WHERE collectionID = NEW.collectionID) IS NULL
|
||||
AND
|
||||
(SELECT libraryID FROM items WHERE itemID = NEW.itemID) IS NOT NULL
|
||||
) OR (
|
||||
(SELECT libraryID FROM collections WHERE collectionID = NEW.collectionID) IS NOT NULL
|
||||
AND
|
||||
(SELECT libraryID FROM items WHERE itemID = NEW.itemID) IS NULL
|
||||
) OR
|
||||
(SELECT libraryID FROM collections WHERE collectionID = NEW.collectionID) != (SELECT libraryID FROM items WHERE itemID = NEW.itemID);
|
||||
END;
|
||||
|
||||
|
||||
-- Don't allow child items to exist explicitly in collections
|
||||
DROP TRIGGER IF EXISTS fki_collectionItems_itemID_sourceItemID;
|
||||
CREATE TRIGGER fki_collectionItems_itemID_sourceItemID
|
||||
BEFORE INSERT ON collectionItems
|
||||
FOR EACH ROW BEGIN
|
||||
SELECT RAISE(ABORT, 'insert on table "collectionItems" violates foreign key constraint "fki_collectionItems_itemID_sourceItemID"')
|
||||
WHERE NEW.itemID IN (SELECT itemID FROM items WHERE itemID IN (SELECT itemID FROM itemAttachments WHERE sourceItemID IS NOT NULL) OR itemID IN (SELECT itemID FROM itemNotes WHERE sourceItemID IS NOT NULL));
|
||||
END;
|
||||
|
||||
DROP TRIGGER IF EXISTS fku_collectionItems_itemID_sourceItemID;
|
||||
CREATE TRIGGER fku_collectionItems_itemID_sourceItemID
|
||||
BEFORE UPDATE OF itemID ON collectionItems
|
||||
FOR EACH ROW BEGIN
|
||||
SELECT RAISE(ABORT, 'update on table "collectionItems" violates foreign key constraint "fku_collectionItems_itemID_sourceItemID"')
|
||||
WHERE NEW.itemID IN (SELECT itemID FROM items WHERE itemID IN (SELECT itemID FROM itemAttachments WHERE sourceItemID IS NOT NULL) OR itemID IN (SELECT itemID FROM itemNotes WHERE sourceItemID IS NOT NULL));
|
||||
END;
|
||||
|
||||
DROP TRIGGER IF EXISTS fku_itemAttachments_sourceItemID_collectionItems_itemID;
|
||||
CREATE TRIGGER fku_itemAttachments_sourceItemID_collectionItems_itemID
|
||||
BEFORE UPDATE OF sourceItemID ON itemAttachments
|
||||
FOR EACH ROW BEGIN
|
||||
SELECT RAISE(ABORT, 'update on table "itemAttachments" violates foreign key constraint "fku_itemAttachments_sourceItemID_collectionItems_itemID"')
|
||||
WHERE NEW.sourceItemID IS NOT NULL AND (SELECT COUNT(*) FROM collectionItems WHERE itemID = NEW.itemID) > 0;
|
||||
END;
|
||||
|
||||
DROP TRIGGER IF EXISTS fku_itemNotes_sourceItemID_collectionItems_itemID;
|
||||
CREATE TRIGGER fku_itemNotes_sourceItemID_collectionItems_itemID
|
||||
BEFORE UPDATE OF sourceItemID ON itemNotes
|
||||
FOR EACH ROW BEGIN
|
||||
SELECT RAISE(ABORT, 'update on table "itemNotes" violates foreign key constraint "fku_itemNotes_sourceItemID_collectionItems_itemID"')
|
||||
WHERE NEW.sourceItemID IS NOT NULL AND (SELECT COUNT(*) FROM collectionItems WHERE itemID = NEW.itemID) > 0;
|
||||
END;
|
||||
|
||||
|
||||
-- creators/creatorDataID
|
||||
DROP TRIGGER IF EXISTS fki_creators_creatorDataID_creatorData_creatorDataID;
|
||||
CREATE TRIGGER fki_creators_creatorDataID_creatorData_creatorDataID
|
||||
|
@ -292,6 +403,102 @@ CREATE TRIGGER fku_items_itemID_fulltextItemWords_itemID
|
|||
UPDATE fulltextItemWords SET itemID=NEW.itemID WHERE itemID=OLD.itemID;
|
||||
END;
|
||||
|
||||
-- groups/libraryID
|
||||
DROP TRIGGER IF EXISTS fki_groups_libraryID_libraries_libraryID;
|
||||
CREATE TRIGGER fki_groups_libraryID_libraries_libraryID
|
||||
BEFORE INSERT ON groups
|
||||
FOR EACH ROW BEGIN
|
||||
SELECT RAISE(ABORT, 'insert on table "groups" violates foreign key constraint "fki_groups_libraryID_libraries_libraryID"')
|
||||
WHERE NEW.libraryID IS NOT NULL AND (SELECT COUNT(*) FROM libraries WHERE libraryID = NEW.libraryID) = 0;
|
||||
END;
|
||||
|
||||
DROP TRIGGER IF EXISTS fku_groups_libraryID_libraries_libraryID;
|
||||
CREATE TRIGGER fku_groups_libraryID_libraries_libraryID
|
||||
BEFORE UPDATE OF libraryID ON groups
|
||||
FOR EACH ROW BEGIN
|
||||
SELECT RAISE(ABORT, 'update on table "groups" violates foreign key constraint "fku_groups_libraryID_libraries_libraryID"')
|
||||
WHERE NEW.libraryID IS NOT NULL AND (SELECT COUNT(*) FROM libraries WHERE libraryID = NEW.libraryID) = 0;
|
||||
END;
|
||||
|
||||
DROP TRIGGER IF EXISTS fkd_groups_libraryID_libraries_libraryID;
|
||||
CREATE TRIGGER fkd_groups_libraryID_libraries_libraryID
|
||||
BEFORE DELETE ON libraries
|
||||
FOR EACH ROW BEGIN
|
||||
SELECT RAISE(ABORT, 'delete on table "libraries" violates foreign key constraint "fkd_groups_libraryID_libraries_libraryID"')
|
||||
WHERE (SELECT COUNT(*) FROM groups WHERE libraryID = OLD.libraryID) > 0;
|
||||
END;
|
||||
|
||||
DROP TRIGGER IF EXISTS fku_libraries_libraryID_groups_libraryID;
|
||||
CREATE TRIGGER fku_libraries_libraryID_groups_libraryID
|
||||
AFTER UPDATE OF libraryID ON libraries
|
||||
FOR EACH ROW BEGIN
|
||||
UPDATE groups SET libraryID=NEW.libraryID WHERE libraryID=OLD.libraryID;
|
||||
END;
|
||||
|
||||
-- groupItems/createdByUserID
|
||||
DROP TRIGGER IF EXISTS fki_groupItems_createdByUserID_users_userID;
|
||||
CREATE TRIGGER fki_groupItems_createdByUserID_users_userID
|
||||
BEFORE INSERT ON groupItems
|
||||
FOR EACH ROW BEGIN
|
||||
SELECT RAISE(ABORT, 'insert on table "groupItems" violates foreign key constraint "fki_groupItems_createdByUserID_users_userID"')
|
||||
WHERE NEW.createdByUserID IS NOT NULL AND (SELECT COUNT(*) FROM users WHERE userID = NEW.createdByUserID) = 0;
|
||||
END;
|
||||
|
||||
DROP TRIGGER IF EXISTS fku_groupItems_createdByUserID_users_userID;
|
||||
CREATE TRIGGER fku_groupItems_createdByUserID_users_userID
|
||||
BEFORE UPDATE OF createdByUserID ON groupItems
|
||||
FOR EACH ROW BEGIN
|
||||
SELECT RAISE(ABORT, 'update on table "groupItems" violates foreign key constraint "fku_groupItems_createdByUserID_users_userID"')
|
||||
WHERE NEW.createdByUserID IS NOT NULL AND (SELECT COUNT(*) FROM users WHERE userID = NEW.createdByUserID) = 0;
|
||||
END;
|
||||
|
||||
DROP TRIGGER IF EXISTS fkd_groupItems_createdByUserID_users_userID;
|
||||
CREATE TRIGGER fkd_groupItems_createdByUserID_users_userID
|
||||
BEFORE DELETE ON users
|
||||
FOR EACH ROW BEGIN
|
||||
SELECT RAISE(ABORT, 'delete on table "users" violates foreign key constraint "fkd_groupItems_createdByUserID_users_userID"')
|
||||
WHERE (SELECT COUNT(*) FROM groupItems WHERE createdByUserID = OLD.userID) > 0;
|
||||
END;
|
||||
|
||||
DROP TRIGGER IF EXISTS fku_users_userID_groupItems_createdByUserID;
|
||||
CREATE TRIGGER fku_users_userID_groupItems_createdByUserID
|
||||
AFTER UPDATE OF userID ON users
|
||||
FOR EACH ROW BEGIN
|
||||
UPDATE groupItems SET createdByUserID=NEW.userID WHERE createdByUserID=OLD.userID;
|
||||
END;
|
||||
|
||||
-- groupItems/lastModifiedByUserID
|
||||
DROP TRIGGER IF EXISTS fki_groupItems_lastModifiedByUserID_users_userID;
|
||||
CREATE TRIGGER fki_groupItems_lastModifiedByUserID_users_userID
|
||||
BEFORE INSERT ON groupItems
|
||||
FOR EACH ROW BEGIN
|
||||
SELECT RAISE(ABORT, 'insert on table "groupItems" violates foreign key constraint "fki_groupItems_lastModifiedByUserID_users_userID"')
|
||||
WHERE NEW.lastModifiedByUserID IS NOT NULL AND (SELECT COUNT(*) FROM users WHERE userID = NEW.lastModifiedByUserID) = 0;
|
||||
END;
|
||||
|
||||
DROP TRIGGER IF EXISTS fku_groupItems_lastModifiedByUserID_users_userID;
|
||||
CREATE TRIGGER fku_groupItems_lastModifiedByUserID_users_userID
|
||||
BEFORE UPDATE OF lastModifiedByUserID ON groupItems
|
||||
FOR EACH ROW BEGIN
|
||||
SELECT RAISE(ABORT, 'update on table "groupItems" violates foreign key constraint "fku_groupItems_lastModifiedByUserID_users_userID"')
|
||||
WHERE NEW.lastModifiedByUserID IS NOT NULL AND (SELECT COUNT(*) FROM users WHERE userID = NEW.lastModifiedByUserID) = 0;
|
||||
END;
|
||||
|
||||
DROP TRIGGER IF EXISTS fkd_groupItems_lastModifiedByUserID_users_userID;
|
||||
CREATE TRIGGER fkd_groupItems_lastModifiedByUserID_users_userID
|
||||
BEFORE DELETE ON users
|
||||
FOR EACH ROW BEGIN
|
||||
SELECT RAISE(ABORT, 'delete on table "users" violates foreign key constraint "fkd_groupItems_lastModifiedByUserID_users_userID"')
|
||||
WHERE (SELECT COUNT(*) FROM groupItems WHERE lastModifiedByUserID = OLD.userID) > 0;
|
||||
END;
|
||||
|
||||
DROP TRIGGER IF EXISTS fku_users_userID_groupItems_lastModifiedByUserID;
|
||||
CREATE TRIGGER fku_users_userID_groupItems_lastModifiedByUserID
|
||||
AFTER UPDATE OF userID ON users
|
||||
FOR EACH ROW BEGIN
|
||||
UPDATE groupItems SET lastModifiedByUserID=NEW.userID WHERE lastModifiedByUserID=OLD.userID;
|
||||
END;
|
||||
|
||||
-- highlights/itemID
|
||||
DROP TRIGGER IF EXISTS fki_highlights_itemID_itemAttachments_itemID;
|
||||
CREATE TRIGGER fki_highlights_itemID_itemAttachments_itemID
|
||||
|
@ -356,6 +563,49 @@ CREATE TRIGGER fku_items_itemID_itemAttachments_itemID
|
|||
UPDATE itemAttachments SET itemID=NEW.itemID WHERE itemID=OLD.itemID;
|
||||
END;
|
||||
|
||||
|
||||
-- itemAttachments libraryID
|
||||
DROP TRIGGER IF EXISTS fki_itemAttachments_libraryID;
|
||||
CREATE TRIGGER fki_itemAttachments_libraryID
|
||||
BEFORE INSERT ON itemAttachments
|
||||
FOR EACH ROW BEGIN
|
||||
SELECT RAISE(ABORT, 'insert on table "itemAttachments" violates foreign key constraint "fki_itemAttachments_libraryID"')
|
||||
WHERE
|
||||
NEW.sourceItemID IS NOT NULL AND (
|
||||
(
|
||||
(SELECT libraryID FROM items WHERE itemID = NEW.itemID) IS NULL
|
||||
AND
|
||||
(SELECT libraryID FROM items WHERE itemID = NEW.sourceItemID) IS NOT NULL
|
||||
) OR (
|
||||
(SELECT libraryID FROM items WHERE itemID = NEW.itemID) IS NOT NULL
|
||||
AND
|
||||
(SELECT libraryID FROM items WHERE itemID = NEW.sourceItemID) IS NULL
|
||||
) OR
|
||||
(SELECT libraryID FROM items WHERE itemID = NEW.itemID) != (SELECT libraryID FROM items WHERE itemID = NEW.sourceItemID)
|
||||
);
|
||||
END;
|
||||
|
||||
DROP TRIGGER IF EXISTS fku_itemAttachments_libraryID;
|
||||
CREATE TRIGGER fku_itemAttachments_libraryID
|
||||
BEFORE UPDATE ON itemAttachments
|
||||
FOR EACH ROW BEGIN
|
||||
SELECT RAISE(ABORT, 'update on table "itemAttachments" violates foreign key constraint "fku_itemAttachments_libraryID"')
|
||||
WHERE
|
||||
NEW.sourceItemID IS NOT NULL AND (
|
||||
(
|
||||
(SELECT libraryID FROM items WHERE itemID = NEW.itemID) IS NULL
|
||||
AND
|
||||
(SELECT libraryID FROM items WHERE itemID = NEW.sourceItemID) IS NOT NULL
|
||||
) OR (
|
||||
(SELECT libraryID FROM items WHERE itemID = NEW.itemID) IS NOT NULL
|
||||
AND
|
||||
(SELECT libraryID FROM items WHERE itemID = NEW.sourceItemID) IS NULL
|
||||
) OR
|
||||
(SELECT libraryID FROM items WHERE itemID = NEW.itemID) != (SELECT libraryID FROM items WHERE itemID = NEW.sourceItemID)
|
||||
);
|
||||
END;
|
||||
|
||||
|
||||
-- itemAttachments/sourceItemID
|
||||
DROP TRIGGER IF EXISTS fki_itemAttachments_sourceItemID_items_itemID;
|
||||
CREATE TRIGGER fki_itemAttachments_sourceItemID_items_itemID
|
||||
|
@ -485,6 +735,43 @@ CREATE TRIGGER fku_creatorTypes_creatorTypeID_itemCreators_creatorTypeID
|
|||
WHERE (SELECT COUNT(*) FROM itemCreators WHERE creatorTypeID = OLD.creatorTypeID) > 0;
|
||||
END;
|
||||
|
||||
|
||||
-- itemCreators libraryID
|
||||
DROP TRIGGER IF EXISTS fki_itemCreators_libraryID;
|
||||
CREATE TRIGGER fki_itemCreators_libraryID
|
||||
BEFORE INSERT ON itemCreators
|
||||
FOR EACH ROW BEGIN
|
||||
SELECT RAISE(ABORT, 'insert on table "itemCreators" violates foreign key constraint "fki_itemCreators_libraryID"')
|
||||
WHERE (
|
||||
(SELECT libraryID FROM creators WHERE creatorID = NEW.creatorID) IS NULL
|
||||
AND
|
||||
(SELECT libraryID FROM items WHERE itemID = NEW.itemID) IS NOT NULL
|
||||
) OR (
|
||||
(SELECT libraryID FROM creators WHERE creatorID = NEW.creatorID) IS NOT NULL
|
||||
AND
|
||||
(SELECT libraryID FROM items WHERE itemID = NEW.itemID) IS NULL
|
||||
) OR
|
||||
(SELECT libraryID FROM creators WHERE creatorID = NEW.creatorID) != (SELECT libraryID FROM items WHERE itemID = NEW.itemID);
|
||||
END;
|
||||
|
||||
DROP TRIGGER IF EXISTS fku_itemCreators_libraryID;
|
||||
CREATE TRIGGER fku_itemCreators_libraryID
|
||||
BEFORE UPDATE ON itemCreators
|
||||
FOR EACH ROW BEGIN
|
||||
SELECT RAISE(ABORT, 'update on table "itemCreators" violates foreign key constraint "fku_itemCreators_libraryID"')
|
||||
WHERE (
|
||||
(SELECT libraryID FROM creators WHERE creatorID = NEW.creatorID) IS NULL
|
||||
AND
|
||||
(SELECT libraryID FROM items WHERE itemID = NEW.itemID) IS NOT NULL
|
||||
) OR (
|
||||
(SELECT libraryID FROM creators WHERE creatorID = NEW.creatorID) IS NOT NULL
|
||||
AND
|
||||
(SELECT libraryID FROM items WHERE itemID = NEW.itemID) IS NULL
|
||||
) OR
|
||||
(SELECT libraryID FROM creators WHERE creatorID = NEW.creatorID) != (SELECT libraryID FROM items WHERE itemID = NEW.itemID);
|
||||
END;
|
||||
|
||||
|
||||
-- itemData/itemID
|
||||
DROP TRIGGER IF EXISTS fki_itemData_itemID_items_itemID;
|
||||
CREATE TRIGGER fki_itemData_itemID_items_itemID
|
||||
|
@ -615,6 +902,49 @@ CREATE TRIGGER fku_items_itemID_itemNotes_itemID
|
|||
UPDATE itemNotes SET itemID=NEW.itemID WHERE itemID=OLD.itemID;
|
||||
END;
|
||||
|
||||
|
||||
-- itemNotes libraryID
|
||||
DROP TRIGGER IF EXISTS fki_itemNotes_libraryID;
|
||||
CREATE TRIGGER fki_itemNotes_libraryID
|
||||
BEFORE INSERT ON itemNotes
|
||||
FOR EACH ROW BEGIN
|
||||
SELECT RAISE(ABORT, 'insert on table "itemNotes" violates foreign key constraint "fki_itemNotes_libraryID"')
|
||||
WHERE
|
||||
NEW.sourceItemID IS NOT NULL AND (
|
||||
(
|
||||
(SELECT libraryID FROM items WHERE itemID = NEW.itemID) IS NULL
|
||||
AND
|
||||
(SELECT libraryID FROM items WHERE itemID = NEW.sourceItemID) IS NOT NULL
|
||||
) OR (
|
||||
(SELECT libraryID FROM items WHERE itemID = NEW.itemID) IS NOT NULL
|
||||
AND
|
||||
(SELECT libraryID FROM items WHERE itemID = NEW.sourceItemID) IS NULL
|
||||
) OR
|
||||
(SELECT libraryID FROM items WHERE itemID = NEW.itemID) != (SELECT libraryID FROM items WHERE itemID = NEW.sourceItemID)
|
||||
);
|
||||
END;
|
||||
|
||||
DROP TRIGGER IF EXISTS fku_itemNotes_libraryID;
|
||||
CREATE TRIGGER fku_itemNotes_libraryID
|
||||
BEFORE UPDATE ON itemNotes
|
||||
FOR EACH ROW BEGIN
|
||||
SELECT RAISE(ABORT, 'update on table "itemNotes" violates foreign key constraint "fku_itemNotes_libraryID"')
|
||||
WHERE
|
||||
NEW.sourceItemID IS NOT NULL AND (
|
||||
(
|
||||
(SELECT libraryID FROM items WHERE itemID = NEW.itemID) IS NULL
|
||||
AND
|
||||
(SELECT libraryID FROM items WHERE itemID = NEW.sourceItemID) IS NOT NULL
|
||||
) OR (
|
||||
(SELECT libraryID FROM items WHERE itemID = NEW.itemID) IS NOT NULL
|
||||
AND
|
||||
(SELECT libraryID FROM items WHERE itemID = NEW.sourceItemID) IS NULL
|
||||
) OR
|
||||
(SELECT libraryID FROM items WHERE itemID = NEW.itemID) != (SELECT libraryID FROM items WHERE itemID = NEW.sourceItemID)
|
||||
);
|
||||
END;
|
||||
|
||||
|
||||
-- itemNotes/sourceItemID
|
||||
DROP TRIGGER IF EXISTS fki_itemNotes_sourceItemID_items_itemID;
|
||||
CREATE TRIGGER fki_itemNotes_sourceItemID_items_itemID
|
||||
|
@ -647,6 +977,38 @@ CREATE TRIGGER fku_items_itemID_itemNotes_sourceItemID
|
|||
UPDATE itemNotes SET sourceItemID=NEW.itemID WHERE sourceItemID=OLD.itemID;
|
||||
END;
|
||||
|
||||
-- items/libraryID
|
||||
DROP TRIGGER IF EXISTS fki_items_libraryID_libraries_libraryID;
|
||||
CREATE TRIGGER fki_items_libraryID_libraries_libraryID
|
||||
BEFORE INSERT ON items
|
||||
FOR EACH ROW BEGIN
|
||||
SELECT RAISE(ABORT, 'insert on table "items" violates foreign key constraint "fki_items_libraryID_libraries_libraryID"')
|
||||
WHERE NEW.libraryID IS NOT NULL AND (SELECT COUNT(*) FROM libraries WHERE libraryID = NEW.libraryID) = 0;
|
||||
END;
|
||||
|
||||
DROP TRIGGER IF EXISTS fku_items_libraryID_libraries_libraryID;
|
||||
CREATE TRIGGER fku_items_libraryID_libraries_libraryID
|
||||
BEFORE UPDATE OF libraryID ON items
|
||||
FOR EACH ROW BEGIN
|
||||
SELECT RAISE(ABORT, 'update on table "items" violates foreign key constraint "fku_items_libraryID_libraries_libraryID"')
|
||||
WHERE NEW.libraryID IS NOT NULL AND (SELECT COUNT(*) FROM libraries WHERE libraryID = NEW.libraryID) = 0;
|
||||
END;
|
||||
|
||||
DROP TRIGGER IF EXISTS fkd_items_libraryID_libraries_libraryID;
|
||||
CREATE TRIGGER fkd_items_libraryID_libraries_libraryID
|
||||
BEFORE DELETE ON libraries
|
||||
FOR EACH ROW BEGIN
|
||||
SELECT RAISE(ABORT, 'delete on table "libraries" violates foreign key constraint "fkd_items_libraryID_libraries_libraryID"')
|
||||
WHERE (SELECT COUNT(*) FROM items WHERE libraryID = OLD.libraryID) > 0;
|
||||
END;
|
||||
|
||||
DROP TRIGGER IF EXISTS fku_libraries_libraryID_items_libraryID;
|
||||
CREATE TRIGGER fku_libraries_libraryID_items_libraryID
|
||||
AFTER UPDATE OF libraryID ON libraries
|
||||
FOR EACH ROW BEGIN
|
||||
UPDATE items SET libraryID=NEW.libraryID WHERE libraryID=OLD.libraryID;
|
||||
END;
|
||||
|
||||
-- itemSeeAlso/itemID
|
||||
DROP TRIGGER IF EXISTS fki_itemSeeAlso_itemID_items_itemID;
|
||||
CREATE TRIGGER fki_itemSeeAlso_itemID_items_itemID
|
||||
|
@ -711,6 +1073,43 @@ CREATE TRIGGER fku_items_itemID_itemSeeAlso_linkedItemID
|
|||
UPDATE itemSeeAlso SET linkedItemID=NEW.itemID WHERE linkedItemID=OLD.itemID;
|
||||
END;
|
||||
|
||||
|
||||
-- itemSeeAlso libraryID
|
||||
DROP TRIGGER IF EXISTS fki_itemSeeAlso_libraryID;
|
||||
CREATE TRIGGER fki_itemSeeAlso_libraryID
|
||||
BEFORE INSERT ON itemSeeAlso
|
||||
FOR EACH ROW BEGIN
|
||||
SELECT RAISE(ABORT, 'insert on table "itemSeeAlso" violates foreign key constraint "fki_itemSeeAlso_libraryID"')
|
||||
WHERE (
|
||||
(SELECT libraryID FROM items WHERE itemID = NEW.itemID) IS NULL
|
||||
AND
|
||||
(SELECT libraryID FROM items WHERE itemID = NEW.linkedItemID) IS NOT NULL
|
||||
) OR (
|
||||
(SELECT libraryID FROM items WHERE itemID = NEW.itemID) IS NOT NULL
|
||||
AND
|
||||
(SELECT libraryID FROM items WHERE itemID = NEW.linkedItemID) IS NULL
|
||||
) OR
|
||||
(SELECT libraryID FROM items WHERE itemID = NEW.itemID) != (SELECT libraryID FROM items WHERE itemID = NEW.linkedItemID);
|
||||
END;
|
||||
|
||||
DROP TRIGGER IF EXISTS fku_itemSeeAlso_libraryID;
|
||||
CREATE TRIGGER fku_itemSeeAlso_libraryID
|
||||
BEFORE UPDATE ON itemSeeAlso
|
||||
FOR EACH ROW BEGIN
|
||||
SELECT RAISE(ABORT, 'update on table "itemSeeAlso" violates foreign key constraint "fku_itemSeeAlso_libraryID"')
|
||||
WHERE (
|
||||
(SELECT libraryID FROM items WHERE itemID = NEW.itemID) IS NULL
|
||||
AND
|
||||
(SELECT libraryID FROM items WHERE itemID = NEW.linkedItemID) IS NOT NULL
|
||||
) OR (
|
||||
(SELECT libraryID FROM items WHERE itemID = NEW.itemID) IS NOT NULL
|
||||
AND
|
||||
(SELECT libraryID FROM items WHERE itemID = NEW.linkedItemID) IS NULL
|
||||
) OR
|
||||
(SELECT libraryID FROM items WHERE itemID = NEW.itemID) != (SELECT libraryID FROM items WHERE itemID = NEW.linkedItemID);
|
||||
END;
|
||||
|
||||
|
||||
-- itemTags/itemID
|
||||
DROP TRIGGER IF EXISTS fki_itemTags_itemID_items_itemID;
|
||||
CREATE TRIGGER fki_itemTags_itemID_items_itemID
|
||||
|
@ -743,6 +1142,43 @@ CREATE TRIGGER fkd_items_itemID_itemTags_itemID
|
|||
UPDATE itemTags SET itemID=NEW.itemID WHERE itemID=OLD.itemID;
|
||||
END;
|
||||
|
||||
|
||||
-- itemTags libraryID
|
||||
DROP TRIGGER IF EXISTS fki_itemTags_libraryID;
|
||||
CREATE TRIGGER fki_itemTags_libraryID
|
||||
BEFORE INSERT ON itemTags
|
||||
FOR EACH ROW BEGIN
|
||||
SELECT RAISE(ABORT, 'insert on table "itemTags" violates foreign key constraint "fki_itemTags_libraryID"')
|
||||
WHERE (
|
||||
(SELECT libraryID FROM tags WHERE tagID = NEW.tagID) IS NULL
|
||||
AND
|
||||
(SELECT libraryID FROM items WHERE itemID = NEW.itemID) IS NOT NULL
|
||||
) OR (
|
||||
(SELECT libraryID FROM tags WHERE tagID = NEW.tagID) IS NOT NULL
|
||||
AND
|
||||
(SELECT libraryID FROM items WHERE itemID = NEW.itemID) IS NULL
|
||||
) OR
|
||||
(SELECT libraryID FROM tags WHERE tagID = NEW.tagID) != (SELECT libraryID FROM items WHERE itemID = NEW.itemID);
|
||||
END;
|
||||
|
||||
DROP TRIGGER IF EXISTS fku_itemTags_libraryID;
|
||||
CREATE TRIGGER fku_itemTags_libraryID
|
||||
BEFORE UPDATE ON itemTags
|
||||
FOR EACH ROW BEGIN
|
||||
SELECT RAISE(ABORT, 'update on table "itemTags" violates foreign key constraint "fku_itemTags_libraryID"')
|
||||
WHERE (
|
||||
(SELECT libraryID FROM tags WHERE tagID = NEW.tagID) IS NULL
|
||||
AND
|
||||
(SELECT libraryID FROM items WHERE itemID = NEW.itemID) IS NOT NULL
|
||||
) OR (
|
||||
(SELECT libraryID FROM tags WHERE tagID = NEW.tagID) IS NOT NULL
|
||||
AND
|
||||
(SELECT libraryID FROM items WHERE itemID = NEW.itemID) IS NULL
|
||||
) OR
|
||||
(SELECT libraryID FROM tags WHERE tagID = NEW.tagID) != (SELECT libraryID FROM items WHERE itemID = NEW.itemID);
|
||||
END;
|
||||
|
||||
|
||||
-- itemTags/tagID
|
||||
DROP TRIGGER IF EXISTS fki_itemTags_tagID_tags_tagID;
|
||||
CREATE TRIGGER fki_itemTags_tagID_tags_tagID
|
||||
|
@ -775,6 +1211,7 @@ CREATE TRIGGER fku_tags_tagID_itemTags_tagID
|
|||
UPDATE itemTags SET tagID=NEW.tagID WHERE tagID=OLD.tagID;
|
||||
END;
|
||||
|
||||
|
||||
-- savedSearchConditions/savedSearchID
|
||||
DROP TRIGGER IF EXISTS fki_savedSearchConditions_savedSearchID_savedSearches_savedSearchID;
|
||||
CREATE TRIGGER fki_savedSearchConditions_savedSearchID_savedSearches_savedSearchID
|
||||
|
@ -807,9 +1244,7 @@ CREATE TRIGGER fku_savedSearches_savedSearchID_savedSearchConditions_savedSearch
|
|||
UPDATE savedSearchConditions SET savedSearchID=NEW.savedSearchID WHERE savedSearchID=OLD.savedSearchID;
|
||||
END;
|
||||
|
||||
|
||||
-- deletedItems/itemID
|
||||
-- savedSearchConditions/savedSearchID
|
||||
DROP TRIGGER IF EXISTS fki_deletedItems_itemID_items_itemID;
|
||||
CREATE TRIGGER fki_deletedItems_itemID_items_itemID
|
||||
BEFORE INSERT ON deletedItems
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<RDF:Seq>
|
||||
<RDF:li>
|
||||
<RDF:Description>
|
||||
<version>1.5b2.SVN</version>
|
||||
<version>2.0b3.SVN</version>
|
||||
<targetApplication>
|
||||
<RDF:Description>
|
||||
<id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</id>
|
||||
|
|
123
userdata.sql
123
userdata.sql
|
@ -1,7 +1,7 @@
|
|||
-- 50
|
||||
-- 53
|
||||
|
||||
-- This file creates tables containing user-specific data -- any changes made
|
||||
-- here must be mirrored in transition steps in schema.js::_migrateSchema()
|
||||
-- This file creates tables containing user-specific data for new users --
|
||||
-- any changes made here must be mirrored in transition steps in schema.js::_migrateSchema()
|
||||
|
||||
|
||||
CREATE TABLE version (
|
||||
|
@ -20,12 +20,17 @@ CREATE TABLE settings (
|
|||
-- The foundational table; every item collected has a unique record here
|
||||
CREATE TABLE items (
|
||||
itemID INTEGER PRIMARY KEY,
|
||||
itemTypeID INT,
|
||||
dateAdded DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
dateModified DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
key TEXT NOT NULL UNIQUE
|
||||
itemTypeID INT NOT NULL,
|
||||
dateAdded TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
dateModified TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
clientDateModified TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
libraryID INT,
|
||||
key TEXT NOT NULL,
|
||||
UNIQUE (libraryID, key),
|
||||
FOREIGN KEY (libraryID) REFERENCES libraries(libraryID)
|
||||
);
|
||||
|
||||
|
||||
CREATE TABLE itemDataValues (
|
||||
valueID INTEGER PRIMARY KEY,
|
||||
value UNIQUE
|
||||
|
@ -42,7 +47,7 @@ CREATE TABLE itemData (
|
|||
FOREIGN KEY (valueID) REFERENCES itemDataValues(valueID)
|
||||
);
|
||||
|
||||
-- Note data for note items
|
||||
-- Note data for note and attachment items
|
||||
CREATE TABLE itemNotes (
|
||||
itemID INTEGER PRIMARY KEY,
|
||||
sourceItemID INT,
|
||||
|
@ -71,18 +76,19 @@ CREATE INDEX itemAttachments_sourceItemID ON itemAttachments(sourceItemID);
|
|||
CREATE INDEX itemAttachments_mimeType ON itemAttachments(mimeType);
|
||||
CREATE INDEX itemAttachments_syncState ON itemAttachments(syncState);
|
||||
|
||||
-- Individual entries for each tag
|
||||
CREATE TABLE tags (
|
||||
tagID INTEGER PRIMARY KEY,
|
||||
name TEXT COLLATE NOCASE,
|
||||
name TEXT NOT NULL COLLATE NOCASE,
|
||||
type INT NOT NULL,
|
||||
dateAdded DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
dateModified DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
key TEXT NOT NULL UNIQUE,
|
||||
UNIQUE (name, type)
|
||||
dateAdded TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
dateModified TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
clientDateModified TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
libraryID INT,
|
||||
key TEXT NOT NULL,
|
||||
UNIQUE (libraryID, name, type),
|
||||
UNIQUE (libraryID, key)
|
||||
);
|
||||
|
||||
-- Associates items with keywords
|
||||
CREATE TABLE itemTags (
|
||||
itemID INT,
|
||||
tagID INT,
|
||||
|
@ -101,18 +107,20 @@ CREATE TABLE itemSeeAlso (
|
|||
);
|
||||
CREATE INDEX itemSeeAlso_linkedItemID ON itemSeeAlso(linkedItemID);
|
||||
|
||||
|
||||
CREATE TABLE creators (
|
||||
creatorID INTEGER PRIMARY KEY,
|
||||
creatorDataID INT NOT NULL,
|
||||
dateAdded DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
dateModified DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
key TEXT NOT NULL UNIQUE,
|
||||
dateAdded TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
dateModified TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
clientDateModified TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
libraryID INT,
|
||||
key TEXT NOT NULL,
|
||||
UNIQUE (libraryID, key),
|
||||
FOREIGN KEY (creatorDataID) REFERENCES creatorData(creatorDataID)
|
||||
);
|
||||
CREATE INDEX creators_creatorDataID ON creators(creatorDataID);
|
||||
|
||||
-- Each individual creator
|
||||
-- Unique creator data, which can be associated with more than one creator
|
||||
CREATE TABLE creatorData (
|
||||
creatorDataID INTEGER PRIMARY KEY,
|
||||
firstName TEXT,
|
||||
|
@ -122,7 +130,6 @@ CREATE TABLE creatorData (
|
|||
birthYear INT
|
||||
);
|
||||
|
||||
-- Associates single or multiple creators to items
|
||||
CREATE TABLE itemCreators (
|
||||
itemID INT,
|
||||
creatorID INT,
|
||||
|
@ -134,18 +141,19 @@ CREATE TABLE itemCreators (
|
|||
FOREIGN KEY (creatorTypeID) REFERENCES creatorTypes(creatorTypeID)
|
||||
);
|
||||
|
||||
-- Collections for holding items
|
||||
CREATE TABLE collections (
|
||||
collectionID INTEGER PRIMARY KEY,
|
||||
collectionName TEXT,
|
||||
parentCollectionID INT,
|
||||
dateAdded DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
dateModified DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
key TEXT NOT NULL UNIQUE,
|
||||
collectionName TEXT NOT NULL,
|
||||
parentCollectionID INT DEFAULT NULL,
|
||||
dateAdded TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
dateModified TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
clientDateModified TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
libraryID INT,
|
||||
key TEXT NOT NULL,
|
||||
UNIQUE (libraryID, key),
|
||||
FOREIGN KEY (parentCollectionID) REFERENCES collections(collectionID)
|
||||
);
|
||||
|
||||
-- Associates items with the various collections they belong to
|
||||
CREATE TABLE collectionItems (
|
||||
collectionID INT,
|
||||
itemID INT,
|
||||
|
@ -158,10 +166,13 @@ CREATE INDEX itemID ON collectionItems(itemID);
|
|||
|
||||
CREATE TABLE savedSearches (
|
||||
savedSearchID INTEGER PRIMARY KEY,
|
||||
savedSearchName TEXT,
|
||||
dateAdded DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
dateModified DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
key TEXT NOT NULL UNIQUE
|
||||
savedSearchName TEXT NOT NULL,
|
||||
dateAdded TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
dateModified TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
clientDateModified TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
libraryID INT,
|
||||
key TEXT NOT NULL,
|
||||
UNIQUE (libraryID, key)
|
||||
);
|
||||
|
||||
CREATE TABLE savedSearchConditions (
|
||||
|
@ -180,6 +191,44 @@ CREATE TABLE deletedItems (
|
|||
dateDeleted DEFAULT CURRENT_TIMESTAMP NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE relations (
|
||||
libraryID INT NOT NULL,
|
||||
subject TEXT NOT NULL,
|
||||
predicate TEXT NOT NULL,
|
||||
object TEXT NOT NULL,
|
||||
clientDateModified TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (subject, predicate, object)
|
||||
);
|
||||
CREATE INDEX relations_object ON relations(object);
|
||||
|
||||
CREATE TABLE libraries (
|
||||
libraryID INTEGER PRIMARY KEY,
|
||||
libraryType TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE users (
|
||||
userID INTEGER PRIMARY KEY,
|
||||
username TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE groups (
|
||||
groupID INTEGER PRIMARY KEY,
|
||||
libraryID INT NOT NULL UNIQUE,
|
||||
name TEXT NOT NULL,
|
||||
description TEXT NOT NULL,
|
||||
editable INT NOT NULL,
|
||||
filesEditable INT NOT NULL,
|
||||
FOREIGN KEY (libraryID) REFERENCES libraries(libraryID)
|
||||
);
|
||||
|
||||
CREATE TABLE groupItems (
|
||||
itemID INTEGER PRIMARY KEY,
|
||||
createdByUserID INT NOT NULL,
|
||||
lastModifiedByUserID INT NOT NULL,
|
||||
FOREIGN KEY (createdByUserID) REFERENCES users(userID),
|
||||
FOREIGN KEY (lastModifiedByUserID) REFERENCES users(userID)
|
||||
);
|
||||
|
||||
CREATE TABLE fulltextItems (
|
||||
itemID INTEGER PRIMARY KEY,
|
||||
version INT,
|
||||
|
@ -207,15 +256,19 @@ CREATE INDEX fulltextItemWords_itemID ON fulltextItemWords(itemID);
|
|||
|
||||
CREATE TABLE syncDeleteLog (
|
||||
syncObjectTypeID INT NOT NULL,
|
||||
key TEXT NOT NULL UNIQUE,
|
||||
libraryID INT,
|
||||
key TEXT NOT NULL,
|
||||
timestamp INT NOT NULL,
|
||||
UNIQUE (libraryID, key),
|
||||
FOREIGN KEY (syncObjectTypeID) REFERENCES syncObjectTypes(syncObjectTypeID)
|
||||
);
|
||||
CREATE INDEX syncDeleteLog_timestamp ON syncDeleteLog(timestamp);
|
||||
|
||||
CREATE TABLE storageDeleteLog (
|
||||
key TEXT PRIMARY KEY,
|
||||
timestamp INT NOT NULL
|
||||
libraryID INT,
|
||||
key TEXT NOT NULL,
|
||||
timestamp INT NOT NULL,
|
||||
PRIMARY KEY (libraryID, key)
|
||||
);
|
||||
CREATE INDEX storageDeleteLog_timestamp ON storageDeleteLog(timestamp);
|
||||
|
||||
|
|
Loading…
Reference in a new issue