Replace Z.DataObjects::diff() with Z.DataObjectUtilities.diff(). Instead
of just returning two objects with the differing fields, the new diff()
generates a changeset with operations to apply with applyChanges(),
including at the array member level for collections and tags. This,
combined with cached pristine copies of objects, will allow for vastly
better conflict resolution, with automatic merging of non-conflicting
changes.
Creators currently don't show granular changes, and ordering might make
it too tough to do so. Relations diffing isn't yet implemented.
Also:
- Make .mode == 'patch' optional if .patchBase is provided.
- Remove requirement for item to be unchanged, which hopefully wasn't there for
a good reason
- Add a few tests, though more are needed
This allows calling code to do something other than call Zotero.debug()
on errors (like, say, nothing, in order to avoid logging certain
expected errors) before throwing.
Store and check the last selected items in ZoteroPane.itemSelected() to
see if it's necessary to refresh the item pane. This prevents loss of
textbox focus if another write occurs while editing a field.
Also optimize row adding/removing in itemTreeView.js
Fix a couple cases of lost text field focus after an edit, including
focusing of the Title field after using New Item when a field is already
being edited and has a changed value.
Also, in tests, select My Library and wait for items to load when using
the loadZoteroPane() support function. We could add a parameter to skip
that or move it to a separate function, but the code to detect it is a
bit convoluted and it's a prerequisite for many tests, so it's handy to
have a function for it.
If a new item is created manually when a text field is already open, the
hideEditor is run first on the html:textarea before bubbling up to the
textbox. During a normal blur, the event only happens on the textbox,
though I haven't looked into the reason for the difference.
- Add an 'exclusive' option to transactions that causes them to block other
transactions and wait for other transactions to finish before starting,
instead of nesting
- Resolve Zotero.DB.waitForTransaction() promise before returning from
executeTransaction()
- A side effect of the above: wait for a newly created item to be selected in
the middle pane and rendered in the right-hand pane before returning from
executeTransaction()
- Don't save items multiple times when adding/removing a non-final creator in
the Info pane
- Use a simpler, non-recursive method for focusing the next field in the Info
pane; this prevents "too much recursion" errors if something causes the
right-hand pane not to be rendered when expected
This fixes an issue where two transactions started around the same time
could run separately instead of nesting, causing the statements from one
to end up running not within a transaction
And use 'version' instead of 'itemVersion' for object version for items
Also add deferred foreign key checking to system.sql so that DROP TABLE
commands don't fail mid-transaction
Show a wizard after items are dragged to My Publications choosing
whether to include files and notes and choosing sharing settings for the
items. Sharing options are Creative Commons licenses, CC0, "All rights
reserved", or keeping the existing Rights field if available.
Also blocks collections, searches, linked file attachments, and
top-level attachments/notes from My Publications at the data layer, but
not yet from the UI in all places (so it can crash if you try).
Todo:
- Block certain UI actions with nice messages
- Show a nice scrollable list of items in the wizard to allow selecting
specific files/notes, instead of just having checkboxes for files and
notes that apply to all dragged items
- Show an explanation of My Publications in the right-hand pane when no
items are selected
- Maybe adjust handling when no attached files/notes, since it might be
a bit alarming at the moment to see sharing options for metadata
entries
Previously, object identifiers were registered in a commit callback, but that
meant that they wouldn't be available to getLibraryAndKeyFromID/
getIDFromLibraryAndKey within a transaction. Instead, register them before
saving and clear them in a tranasction rollback if necessary.
This changes Zotero.DataObject to call its own _finalizeSave() in addition to a
descendent one.
Object contains 'libraryID' and 'key' properties
This is due to changed array destructuring behavior in Firefox. Previously,
`var [foo, bar] = maybeArrayMaybeFalse()` always worked, leaving foo and bar
undefined if the function returned false. Now (with ES6, I assume), if the
function returns false it results in a "false[Symbol.iterator] is not a
function" error. But `var {libraryID, key} = false` works as expected, leaving
both values undefined, so instead we can just return an object with those
properties from getLibraryAndKeyFromID(). To assign to different variables, use
`var {libraryID, key: parentItemKey} = ...`.
Search condition ids are now indexed from 0, and always saved
contiguously (no more 'fixGaps' option), since they're just in an array
in the API. (They're still returned as an object from
Zotero.Search.prototype.getConditions() because it's easier for the
advanced search window to not have to deal with shifting ids between
saves.)
Also:
- Return an object from `Zotero.Search.prototype.getConditions()`
instead of an array.
- Add support function `getPromiseError(promise)` to return the error
thrown from a chain of promises, or false if none. (We could make an
`assert.throwsAsync()`, but this allows testing of various properties
such as `.name`, which even the built-in `assert.throws()` can't
test.)
- Clarify some search save errors
'b' for *b*undled files
Translators and styles take a long time to install and initialize in
source installations, and they're unnecessary for many tests.
This shaves about 10 seconds off each test run for me on one system (and
that's with some help from filesystem caching).