From 9285b0cfb146fff6a7d1d1ca79a76892daf52559 Mon Sep 17 00:00:00 2001 From: Will S Date: Tue, 6 Dec 2011 16:59:11 -0500 Subject: [PATCH 1/7] Allow delimited entry of multiple authors or tags --- chrome/content/zotero/bindings/itembox.xml | 75 +++++++++++++++++++++- chrome/content/zotero/bindings/tagsbox.xml | 14 +++- chrome/content/zotero/xpcom/data/item.js | 27 +++++++- 3 files changed, 110 insertions(+), 6 deletions(-) diff --git a/chrome/content/zotero/bindings/itembox.xml b/chrome/content/zotero/bindings/itembox.xml index d976e33ca9..a93e9853fc 100644 --- a/chrome/content/zotero/bindings/itembox.xml +++ b/chrome/content/zotero/bindings/itembox.xml @@ -1421,6 +1421,7 @@ if (creatorField=='lastName') { t.setAttribute('fieldMode', elem.getAttribute('fieldMode')); + t.setAttribute('newlines','pasteintact'); } if (Zotero.ItemFields.isMultiline(fieldName) || Zotero.ItemFields.isLong(fieldName)) { @@ -1695,9 +1696,79 @@ var otherFields = this.getCreatorFields(row); otherFields[creatorField] = value; + var lastName = otherFields.lastName; - this.modifyCreator(creatorIndex, otherFields); - + //Handle \n\r delimited entries + if (lastName.search('\r') > -1 || lastName.search('\n') > -1) { + lastName = lastName.replace('\r\n','\n'); + lastName = lastName.replace('\r','\n'); + var rawNameArray = lastName.split('\n'); + + //Save tab direction and add creator flags since they are reset in the + //process of adding multiple authors + var tabDirectionBuffer = this._tabDirection; + var addCreatorRowBuffer = this._addCreatorRow; + var tabIndexBuffer = this._lastTabIndex; + this._tabDirection = false; + this._addCreatorRow = false; + + //Filter out bad names + var nameArray = new Array(); + var counter = 0; + var tempName = ''; + for each(tempName in rawNameArray) { + if (tempName.length > 0) { + //Put further error checking of tempName here + nameArray[counter] = tempName; + counter++; + } + } + + //If not adding names at the end of the creator list, make new creator + //entries and then shift down existing creators. + var initNumCreators = this.item.numCreators(); + var creatorsToShift = initNumCreators - creatorIndex; + if (creatorsToShift > 0) { + //Add extra creators + for (var i=0;i=creatorIndex; i--) { + var shiftedCreator = this.item.getCreator(i); + this.item.setCreator(nameArray.length+i,shiftedCreator.ref,shiftedCreator.creatorTypeID); + } + } + + //Add the creators in lastNameArray one at a time + var tempFields=otherFields; + for each(tempName in nameArray) { + // Check for comma to determine creator name format + tempFields.fieldMode = (tempName.indexOf('\t') == -1) ? 1 : 0; + if (tempFields.fieldMode == 0) { + tempFields.lastName=tempName.split('\t')[0]; + tempFields.firstName=tempName.split('\t')[1]; + } + else { + tempFields.lastName=tempName; + } + this.modifyCreator(creatorIndex,tempFields); + creatorIndex++; + } + this._tabDirection = tabDirectionBuffer; + this._addCreatorRow = (creatorsToShift==0) ? addCreatorRowBuffer : false; + if (this._tabDirection == 1) { + this._lastTabIndex = parseInt(tabIndexBuffer,10) + 2*(nameArray.length-1); + if (tempFields.fieldMode == 0) { + this._lastTabIndex++; + } + } + } + else { + this.modifyCreator(creatorIndex, otherFields); + } + var val = this.item.getCreator(creatorIndex); val = val ? val.ref[creatorField] : null; diff --git a/chrome/content/zotero/bindings/tagsbox.xml b/chrome/content/zotero/bindings/tagsbox.xml index a859616cbd..eba3b99f5e 100644 --- a/chrome/content/zotero/bindings/tagsbox.xml +++ b/chrome/content/zotero/bindings/tagsbox.xml @@ -293,6 +293,7 @@ t.setAttribute('fieldname', fieldName); t.setAttribute('ztabindex', tabindex); t.setAttribute('flex', '1'); + t.setAttribute('newlines','pasteintact'); // Add auto-complete t.setAttribute('type', 'autocomplete'); @@ -481,8 +482,19 @@ var focusMode = 'tags'; var focusBox = tagsbox; + //Move at least one field even if no entry was added because of + //the way bookkeeping is done above + var fieldsToMove = 1; + //Check if id is an array and, if so, how many new entries + //were added at once + if (Object.prototype.toString.call(id) === '[object Array]') { + fieldsToMove = id.length; + } + if (this._tabDirection) { - this._focusNextField(focusBox, this._lastTabIndex, this._tabDirection == -1); + for (var i = 0; i < fieldsToMove; i++) { + this._focusNextField(focusBox, this._lastTabIndex, this._tabDirection == -1); + } } ]]> diff --git a/chrome/content/zotero/xpcom/data/item.js b/chrome/content/zotero/xpcom/data/item.js index 8b6e957237..90609b8a2b 100644 --- a/chrome/content/zotero/xpcom/data/item.js +++ b/chrome/content/zotero/xpcom/data/item.js @@ -1593,7 +1593,7 @@ Zotero.Item.prototype.save = function() { 'libraryID', 'key' ]; - for each(field in updateFields) { + for each(var field in updateFields) { if (this._changedPrimaryData && this._changedPrimaryData[field]) { sql += field + '=?, '; sqlValues.push(this.getField(field)); @@ -3478,6 +3478,16 @@ Zotero.Item.prototype.addTag = function(name, type) { if (!this.id) { throw ('Cannot add tag to unsaved item in Item.addTag()'); } + + //Check for newlines or carriage returns used as delimiters + //in a series of tags added at once. Add each tag + //separately. + if (name.search('\r') > -1 || name.search('\n') > -1) { + name = name.replace('\r\n','\n'); + name = name.replace('\r','\n'); + var nameArray = name.split('\n'); + return this.addTags(nameArray,type); + } name = Zotero.Utilities.trim(name); @@ -3541,10 +3551,21 @@ Zotero.Item.prototype.addTag = function(name, type) { Zotero.Item.prototype.addTags = function (tags, type) { Zotero.DB.beginTransaction(); try { - for each(var tag in tags) { - this.addTag(tag, type); + var tagIDarray = []; + var counter = 0; + var tempID = false; + for (var i = 0; i < tags.length; i++) { + tempID = this.addTag(tags[i], type); + if (tempID) { + tagIDarray[counter] = tempID; + counter++; + } } + + tagIDarray = (tagIDarray.length>0) ? tagIDarray : false; + Zotero.DB.commitTransaction(); + return tagIDarray; } catch (e) { Zotero.DB.rollbackTransaction(); From 86fa29bf140d9fa63d4f22f5bbefdb91cb3911bd Mon Sep 17 00:00:00 2001 From: Will S Date: Wed, 14 Dec 2011 19:59:57 -0500 Subject: [PATCH 2/7] Same functionality as previous commit, but newlines now parsed in tagsbox.xml instead of addTag() function, just like creator newlines are parsed in itembox.xml --- chrome/content/zotero/bindings/tagsbox.xml | 17 +++++++++++++++-- chrome/content/zotero/xpcom/data/item.js | 10 ---------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/chrome/content/zotero/bindings/tagsbox.xml b/chrome/content/zotero/bindings/tagsbox.xml index eba3b99f5e..7717665146 100644 --- a/chrome/content/zotero/bindings/tagsbox.xml +++ b/chrome/content/zotero/bindings/tagsbox.xml @@ -430,8 +430,10 @@ // Tag id encoded as 'tag-1234' var id = row.getAttribute('id').split('-')[1]; + var newlinePresent = (value.search('\r') > -1 || value.search('\n') > -1); + if (saveChanges) { - if (id) { + if (id && newlinePresent != true) { if (value) { // If trying to replace with another existing tag // (which causes a delete of the row), @@ -453,7 +455,18 @@ } // New tag else { - var id = tagsbox.add(value); + //Check for newlines or carriage returns used as delimiters + //in a series of tags added at once. Add each tag + //separately. + if (newlinePresent) { + value = value.replace('\r\n','\n'); + value = value.replace('\r','\n'); + var nameArray = value.split('\n'); + id = this.item.addTags(nameArray); + } + else { + id = tagsbox.add(value); + } if (!id) { this._lastTabIndex--; } diff --git a/chrome/content/zotero/xpcom/data/item.js b/chrome/content/zotero/xpcom/data/item.js index 90609b8a2b..263215ca93 100644 --- a/chrome/content/zotero/xpcom/data/item.js +++ b/chrome/content/zotero/xpcom/data/item.js @@ -3478,16 +3478,6 @@ Zotero.Item.prototype.addTag = function(name, type) { if (!this.id) { throw ('Cannot add tag to unsaved item in Item.addTag()'); } - - //Check for newlines or carriage returns used as delimiters - //in a series of tags added at once. Add each tag - //separately. - if (name.search('\r') > -1 || name.search('\n') > -1) { - name = name.replace('\r\n','\n'); - name = name.replace('\r','\n'); - var nameArray = name.split('\n'); - return this.addTags(nameArray,type); - } name = Zotero.Utilities.trim(name); From e10d049428c38008035f79b46c1edd384b0a4da1 Mon Sep 17 00:00:00 2001 From: Will S Date: Thu, 15 Dec 2011 19:36:43 -0500 Subject: [PATCH 3/7] Fix minor bug that made shift+tab on a final, blank tab jump back two indices instead of one --- chrome/content/zotero/bindings/tagsbox.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chrome/content/zotero/bindings/tagsbox.xml b/chrome/content/zotero/bindings/tagsbox.xml index 7717665146..8ee7d5f943 100644 --- a/chrome/content/zotero/bindings/tagsbox.xml +++ b/chrome/content/zotero/bindings/tagsbox.xml @@ -467,7 +467,7 @@ else { id = tagsbox.add(value); } - if (!id) { + if (!id && (this._tabDirection==1)) { this._lastTabIndex--; } } @@ -752,4 +752,4 @@ - + \ No newline at end of file From 87c47c0615bc84f0e92ef37e817277a9cf2acc2d Mon Sep 17 00:00:00 2001 From: Will S Date: Tue, 27 Dec 2011 09:02:06 -0500 Subject: [PATCH 4/7] Select next logical tag when adding multiple tags at once. --- chrome/content/zotero/bindings/tagsbox.xml | 50 ++++++++++++++-------- chrome/content/zotero/xpcom/data/item.js | 20 ++++++++- 2 files changed, 49 insertions(+), 21 deletions(-) diff --git a/chrome/content/zotero/bindings/tagsbox.xml b/chrome/content/zotero/bindings/tagsbox.xml index 8ee7d5f943..fe7bf61115 100644 --- a/chrome/content/zotero/bindings/tagsbox.xml +++ b/chrome/content/zotero/bindings/tagsbox.xml @@ -411,12 +411,9 @@ var fieldName = 'tag'; var tabindex = textbox.getAttribute('ztabindex'); - - //var value = t.value; + var value = textbox.value; - var elem; - var tagsbox = Zotero.getAncestorByTagName(textbox, 'tagsbox'); if (!tagsbox) { @@ -462,7 +459,34 @@ value = value.replace('\r\n','\n'); value = value.replace('\r','\n'); var nameArray = value.split('\n'); + + var extremeTag = false; + var nextTag = false; + if (this._tabDirection == -1) { + if (this._lastTabIndex == 1) { + extremeTag = true; + } else { + nextTag = row.previousSibling.getAttribute('id').split('-')[1]; + } + } else if (this._tabDirection == 1) { + if (this._lastTabIndex >= this.item.getTags().length) { + extremeTag = true; + } else { + nextTag = row.nextSibling.getAttribute('id').split('-')[1]; + } + } + id = this.item.addTags(nameArray); + + if (extremeTag) { + if (this._tabDirection == 1) { + this._lastTabIndex = this.item.getTags().length; + } else if (this._tabDirection == -1) { + this._lastTabIndex = 2; + } + } else { + this._lastTabIndex = this.item.getTagIndex(nextTag)+1-this._tabDirection; + } } else { id = tagsbox.add(value); @@ -474,7 +498,7 @@ } if (id) { - elem = this.createValueElement( + var elem = this.createValueElement( value, tabindex ); @@ -492,22 +516,10 @@ catch (e) {} } - var focusMode = 'tags'; var focusBox = tagsbox; - //Move at least one field even if no entry was added because of - //the way bookkeeping is done above - var fieldsToMove = 1; - //Check if id is an array and, if so, how many new entries - //were added at once - if (Object.prototype.toString.call(id) === '[object Array]') { - fieldsToMove = id.length; - } - if (this._tabDirection) { - for (var i = 0; i < fieldsToMove; i++) { - this._focusNextField(focusBox, this._lastTabIndex, this._tabDirection == -1); - } + this._focusNextField(focusBox, this._lastTabIndex, this._tabDirection == -1); } ]]> @@ -752,4 +764,4 @@ - \ No newline at end of file + diff --git a/chrome/content/zotero/xpcom/data/item.js b/chrome/content/zotero/xpcom/data/item.js index 263215ca93..fd06240484 100644 --- a/chrome/content/zotero/xpcom/data/item.js +++ b/chrome/content/zotero/xpcom/data/item.js @@ -1,7 +1,7 @@ /* ***** BEGIN LICENSE BLOCK ***** - Copyright © 2009 Center for History and New Media + Copyright ¬© 2009 Center for History and New Media George Mason University, Fairfax, Virginia, USA http://zotero.org @@ -2703,7 +2703,7 @@ Zotero.Item.prototype.getFile = function(row, skipExistsCheck) { // Strip "storage:" var path = row.path.substr(8); // setRelativeDescriptor() silently uses the parent directory on Windows - // if the filename contains certain characters, so strip them — + // if the filename contains certain characters, so strip them ‚Äî // but don't skip characters outside of XML range, since they may be // correct in the opaque relative descriptor string // @@ -3637,6 +3637,22 @@ Zotero.Item.prototype.getTagIDs = function() { return Zotero.DB.columnQuery(sql, this.id); } +//Return the index of tagID in the list of the item's tags +//sorted in alphabetical order. +Zotero.Item.prototype.getTagIndex = function(tagID) { + var tags = this.getTags(); + + var tagIndex=-1; + for (var i=0;i Date: Tue, 27 Dec 2011 09:06:50 -0500 Subject: [PATCH 5/7] Select appropriate tag when moving from changed tag using enter or tab (not for mouse click) --- chrome/content/zotero/bindings/tagsbox.xml | 25 ++++++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/chrome/content/zotero/bindings/tagsbox.xml b/chrome/content/zotero/bindings/tagsbox.xml index fe7bf61115..375e42a8f9 100644 --- a/chrome/content/zotero/bindings/tagsbox.xml +++ b/chrome/content/zotero/bindings/tagsbox.xml @@ -438,18 +438,29 @@ // when the notifier kicks in var existing = Zotero.Tags.getID(value, 0); if (existing && id != existing) { - this._tabDirection = false; + // this._tabDirection = false; } + var origTagIndex = this.item.getTagIndex(id); var changed = tagsbox.replace(id, value); if (changed) { - return; + var newTagIndex = this.item.getTagIndex(changed); + if (newTagIndex>origTagIndex) { + if (this._tabDirection == 1) { + this._lastTabIndex--; + } + } + else if (newTagIndex Date: Tue, 27 Dec 2011 14:57:46 -0500 Subject: [PATCH 6/7] Remove lines from tagsbox.xml that are no longer used --- chrome/content/zotero/bindings/tagsbox.xml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/chrome/content/zotero/bindings/tagsbox.xml b/chrome/content/zotero/bindings/tagsbox.xml index 375e42a8f9..2ca4cd030c 100644 --- a/chrome/content/zotero/bindings/tagsbox.xml +++ b/chrome/content/zotero/bindings/tagsbox.xml @@ -432,14 +432,6 @@ if (saveChanges) { if (id && newlinePresent != true) { if (value) { - // If trying to replace with another existing tag - // (which causes a delete of the row), - // clear the tab direction so we don't advance - // when the notifier kicks in - var existing = Zotero.Tags.getID(value, 0); - if (existing && id != existing) { - // this._tabDirection = false; - } var origTagIndex = this.item.getTagIndex(id); var changed = tagsbox.replace(id, value); if (changed) { From 139884b99e67b0472895beac15906231f5dfd1bd Mon Sep 17 00:00:00 2001 From: Will S Date: Fri, 30 Dec 2011 02:59:35 -0500 Subject: [PATCH 7/7] Addressed issues pointed out by simonster --- chrome/content/zotero/bindings/itembox.xml | 38 ++++++++-------------- chrome/content/zotero/bindings/tagsbox.xml | 13 +++----- chrome/content/zotero/xpcom/data/item.js | 25 +++++++------- 3 files changed, 29 insertions(+), 47 deletions(-) diff --git a/chrome/content/zotero/bindings/itembox.xml b/chrome/content/zotero/bindings/itembox.xml index a93e9853fc..b892670d21 100644 --- a/chrome/content/zotero/bindings/itembox.xml +++ b/chrome/content/zotero/bindings/itembox.xml @@ -1698,12 +1698,9 @@ otherFields[creatorField] = value; var lastName = otherFields.lastName; - //Handle \n\r delimited entries - if (lastName.search('\r') > -1 || lastName.search('\n') > -1) { - lastName = lastName.replace('\r\n','\n'); - lastName = lastName.replace('\r','\n'); - var rawNameArray = lastName.split('\n'); - + //Handle \n\r and \n delimited entries + var rawNameArray = lastName.split(/\r\n?|\n/); + if (rawNameArray.length > 1) { //Save tab direction and add creator flags since they are reset in the //process of adding multiple authors var tabDirectionBuffer = this._tabDirection; @@ -1713,16 +1710,7 @@ this._addCreatorRow = false; //Filter out bad names - var nameArray = new Array(); - var counter = 0; - var tempName = ''; - for each(tempName in rawNameArray) { - if (tempName.length > 0) { - //Put further error checking of tempName here - nameArray[counter] = tempName; - counter++; - } - } + var nameArray = [tempName for each(tempName in rawNameArray) if(tempName)]; //If not adding names at the end of the creator list, make new creator //entries and then shift down existing creators. @@ -1742,25 +1730,25 @@ } //Add the creators in lastNameArray one at a time - var tempFields=otherFields; for each(tempName in nameArray) { - // Check for comma to determine creator name format - tempFields.fieldMode = (tempName.indexOf('\t') == -1) ? 1 : 0; - if (tempFields.fieldMode == 0) { - tempFields.lastName=tempName.split('\t')[0]; - tempFields.firstName=tempName.split('\t')[1]; + // Check for tab to determine creator name format + otherFields.fieldMode = (tempName.indexOf('\t') == -1) ? 1 : 0; + if (otherFields.fieldMode == 0) { + otherFields.lastName=tempName.split('\t')[0]; + otherFields.firstName=tempName.split('\t')[1]; } else { - tempFields.lastName=tempName; + otherFields.lastName=tempName; + otherFields.firstName=''; } - this.modifyCreator(creatorIndex,tempFields); + this.modifyCreator(creatorIndex,otherFields); creatorIndex++; } this._tabDirection = tabDirectionBuffer; this._addCreatorRow = (creatorsToShift==0) ? addCreatorRowBuffer : false; if (this._tabDirection == 1) { this._lastTabIndex = parseInt(tabIndexBuffer,10) + 2*(nameArray.length-1); - if (tempFields.fieldMode == 0) { + if (otherFields.fieldMode == 0) { this._lastTabIndex++; } } diff --git a/chrome/content/zotero/bindings/tagsbox.xml b/chrome/content/zotero/bindings/tagsbox.xml index 2ca4cd030c..50ef77e363 100644 --- a/chrome/content/zotero/bindings/tagsbox.xml +++ b/chrome/content/zotero/bindings/tagsbox.xml @@ -427,10 +427,10 @@ // Tag id encoded as 'tag-1234' var id = row.getAttribute('id').split('-')[1]; - var newlinePresent = (value.search('\r') > -1 || value.search('\n') > -1); + var tagArray = value.split(/\r\n?|\n/); if (saveChanges) { - if (id && newlinePresent != true) { + if (id && (tagArray.length < 2)) { if (value) { var origTagIndex = this.item.getTagIndex(id); var changed = tagsbox.replace(id, value); @@ -453,16 +453,13 @@ } } } + } // New tag else { //Check for newlines or carriage returns used as delimiters //in a series of tags added at once. Add each tag //separately. - if (newlinePresent) { - value = value.replace('\r\n','\n'); - value = value.replace('\r','\n'); - var nameArray = value.split('\n'); - + if (tagArray.length > 1) { var extremeTag = false; var nextTag = false; if (this._tabDirection == -1) { @@ -479,7 +476,7 @@ } } - id = this.item.addTags(nameArray); + id = this.item.addTags(tagArray); if (extremeTag) { if (this._tabDirection == 1) { diff --git a/chrome/content/zotero/xpcom/data/item.js b/chrome/content/zotero/xpcom/data/item.js index fd06240484..e09fdfcc58 100644 --- a/chrome/content/zotero/xpcom/data/item.js +++ b/chrome/content/zotero/xpcom/data/item.js @@ -1,7 +1,7 @@ /* ***** BEGIN LICENSE BLOCK ***** - Copyright ¬© 2009 Center for History and New Media + Copyright © 2009 Center for History and New Media George Mason University, Fairfax, Virginia, USA http://zotero.org @@ -2703,7 +2703,7 @@ Zotero.Item.prototype.getFile = function(row, skipExistsCheck) { // Strip "storage:" var path = row.path.substr(8); // setRelativeDescriptor() silently uses the parent directory on Windows - // if the filename contains certain characters, so strip them ‚Äî + // if the filename contains certain characters, so strip them — // but don't skip characters outside of XML range, since they may be // correct in the opaque relative descriptor string // @@ -3541,21 +3541,19 @@ Zotero.Item.prototype.addTag = function(name, type) { Zotero.Item.prototype.addTags = function (tags, type) { Zotero.DB.beginTransaction(); try { - var tagIDarray = []; - var counter = 0; + var tagIDArray = []; var tempID = false; for (var i = 0; i < tags.length; i++) { tempID = this.addTag(tags[i], type); if (tempID) { - tagIDarray[counter] = tempID; - counter++; + tagIDArray.push(tempID); } } - tagIDarray = (tagIDarray.length>0) ? tagIDarray : false; + tagIDArray = (tagIDArray.length>0) ? tagIDArray : false; Zotero.DB.commitTransaction(); - return tagIDarray; + return tagIDArray; } catch (e) { Zotero.DB.rollbackTransaction(); @@ -3637,20 +3635,19 @@ Zotero.Item.prototype.getTagIDs = function() { return Zotero.DB.columnQuery(sql, this.id); } -//Return the index of tagID in the list of the item's tags -//sorted in alphabetical order. +/** +* Return the index of tagID in the list of the item's tags sorted in alphabetical order. +*/ Zotero.Item.prototype.getTagIndex = function(tagID) { var tags = this.getTags(); - var tagIndex=-1; for (var i=0;i