Closes #331, Allow phrase searching from quicksearch

Closes #318, Use word index if available to narrow search scope of fulltext scanner
Closes #420, Delete local version of remote scrapers with priority 0 on update

- Changed ZoteroPane.buildItemContextMenu() to make updates easier
- Changed inTransaction repository update delay to 10 minutes
- Fix fulltext search of text files with MIME types that don't begin with 'text/'
- ZoteroPane.setItemsPaneMessage(msg) and ZoteroPane.clearItemsPaneMessage()
- New textbox binding conditional-timed-textbox to run a test (e.g. on the value) before triggering command
- Fulltext content search now supports ANY/ALL instead of just AND (I think)
This commit is contained in:
Dan Stillman 2006-12-15 21:29:40 +00:00
parent 875ceea852
commit edfe4b73be
9 changed files with 372 additions and 109 deletions

View file

@ -0,0 +1,69 @@
<?xml version="1.0"?>
<!--
***** 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 *****
-->
<bindings xmlns="http://www.mozilla.org/xbl"
xmlns:html="http://www.w3.org/1999/xhtml"
xmlns:xbl="http://www.mozilla.org/xbl"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<binding id="conditional-timed-textbox" extends="chrome://global/content/bindings/textbox.xml#timed-textbox">
<implementation>
<field name="skipTimeout"/>
<field name="testcode"/>
<field name="onbeforefire"/>
<field name="onafterfire"/>
<field name="ontestfail"/>
<method name="_fireCommand">
<parameter name="me"/>
<body>
<![CDATA[
if (me.skipTimeout) {
me.skipTimeout = false;
return;
}
var code = me.getAttribute('testcode');
if (!code.length) {
code = true;
}
if (eval(code)) {
if (me.getAttribute('onbeforefire')) {
eval(me.getAttribute('onbeforefire'));
}
me._timer = null;
me.doCommand();
if (me.getAttribute('onafterfire')) {
eval(me.getAttribute('onafterfire'));
}
}
else {
eval(me.getAttribute('ontestfail'));
}
]]>
</body>
</method>
</implementation>
</binding>
</bindings>

View file

@ -44,6 +44,8 @@ var ZoteroPane = new function()
this.deleteSelectedItem = deleteSelectedItem;
this.deleteSelectedCollection = deleteSelectedCollection;
this.editSelectedCollection = editSelectedCollection;
this.handleSearchKeypress = handleSearchKeypress;
this.handleSearchInput = handleSearchInput;
this.search = search;
this.getCollectionsView = getCollectionsView;
this.getItemsView = getItemsView;
@ -56,6 +58,8 @@ var ZoteroPane = new function()
this.buildCollectionContextMenu = buildCollectionContextMenu;
this.buildItemContextMenu = buildItemContextMenu;
this.onDoubleClick = onDoubleClick;
this.setItemsPaneMessage = setItemsPaneMessage;
this.clearItemsPaneMessage = clearItemsPaneMessage;
this.contextPopupShowing = contextPopupShowing;
this.openNoteWindow = openNoteWindow;
this.toggleAbstractForSelectedItem = toggleAbstractForSelectedItem
@ -230,7 +234,6 @@ var ZoteroPane = new function()
function newSearch()
{
var s = new Zotero.Search();
s.addCondition('title','contains','');
var untitled = Zotero.getString('pane.collections.untitled');
untitled = Zotero.DB.getNextName('savedSearches', 'savedSearchName',
@ -527,6 +530,36 @@ var ZoteroPane = new function()
}
function handleSearchKeypress(textbox, event) {
// Events that turn find-as-you-type on
if (event.keyCode == event.DOM_VK_ESCAPE) {
textbox.value = '';
ZoteroPane.setItemsPaneMessage(Zotero.getString('searchInProgress'));
setTimeout("document.getElementById('zotero-tb-search').doCommand('cmd_zotero_search'); ZoteroPane.clearItemsPaneMessage();", 1);
}
else if (event.keyCode == event.DOM_VK_RETURN ||
event.keyCode == event.DOM_VK_ENTER) {
textbox.skipTimeout = true;
ZoteroPane.setItemsPaneMessage(Zotero.getString('searchInProgress'));
setTimeout("document.getElementById('zotero-tb-search').doCommand('cmd_zotero_search'); ZoteroPane.clearItemsPaneMessage();", 1);
}
}
function handleSearchInput(textbox, event) {
// This is the new length, except, it seems, when the change is a
// result of Undo or Redo
if (!textbox.value.length) {
textbox.skipTimeout = true;
ZoteroPane.setItemsPaneMessage(Zotero.getString('searchInProgress'));
setTimeout("document.getElementById('zotero-tb-search').doCommand('cmd_zotero_search'); ZoteroPane.clearItemsPaneMessage();", 1);
}
else if (textbox.value.indexOf('"') != -1) {
ZoteroPane.setItemsPaneMessage(Zotero.getString('advancedSearchMode'));
}
}
function search()
{
if(itemsView)
@ -564,7 +597,7 @@ var ZoteroPane = new function()
function selectItem(itemID, inLibrary)
{
if (!itemID) {
return false;
return;
}
if(itemsView)
{
@ -769,19 +802,37 @@ var ZoteroPane = new function()
function buildItemContextMenu()
{
var m = {
showInLibrary: 0,
sep1: 1,
addNote: 2,
attachSnapshot: 3,
attachLink: 4,
toggleAbstract: 5,
sep2: 6,
deleteItem: 7,
deleteFromLibrary: 8,
sep3: 9,
exportItems: 10,
createBib: 11,
loadReport: 12
};
var menu = document.getElementById('zotero-itemmenu');
var enable = [], disable = [], show = [], hide = [], multiple = '';
if(itemsView && itemsView.selection.count > 0)
{
enable.push(0,2,3,4,6,7,8,10,11,12);
enable.push(m.showInLibrary, m.addNote, m.attachSnapshot, m.attachLink, m.sep2,
m.deleteItem, m.deleteFromLibrary, m.exportItems, m.createBib, m.loadReport);
// Multiple items selected
if (itemsView.selection.count > 1)
{
var multiple = '.multiple';
hide.push(0,1,2,3,4,5,6);
hide.push(m.showInLibrary, m.sep1, m.addNote, m.attachSnapshot,
m.attachLink, m.toggleAbstract, m.sep2);
}
// Single item selected
else
@ -792,33 +843,33 @@ var ZoteroPane = new function()
// Show in Library
if (!itemsView._itemGroup.isLibrary()) {
show.push(0,1);
show.push(m.showInLibrary, m.sep1);
}
else {
hide.push(0,1);
hide.push(m.showInLibrary, m.sep1);
}
if (item.isRegularItem())
{
show.push(2,3,4,6);
hide.push(5); // abstract
show.push(m.addNote, m.attachSnapshot, m.attachLink, m.sep2);
hide.push(m.toggleAbstract);
}
else
{
hide.push(2,3,4);
hide.push(m.addNote, m.attachSnapshot, m.attachLink);
// Abstract
if (item.isNote() && item.getSource()) {
show.push(5,6);
show.push(m.toggleAbstract, m.sep2);
if (item.isAbstract()) {
menu.childNodes[5].setAttribute('label', Zotero.getString('pane.items.menu.abstract.unset'));
menu.childNodes[m.toggleAbstract].setAttribute('label', Zotero.getString('pane.items.menu.abstract.unset'));
}
else {
menu.childNodes[5].setAttribute('label', Zotero.getString('pane.items.menu.abstract.set'));
menu.childNodes[m.toggleAbstract].setAttribute('label', Zotero.getString('pane.items.menu.abstract.set'));
}
}
else {
hide.push(5,6);
hide.push(m.toggleAbstract, m.sep2);
}
}
}
@ -827,33 +878,34 @@ var ZoteroPane = new function()
{
// Show in Library
if (!itemsView._itemGroup.isLibrary()) {
show.push(0,1);
show.push(m.showInLibrary, m.sep1);
}
else {
hide.push(0,1);
hide.push(m.showInLibrary, m.sep1);
}
disable.push(0,2,3,4,7,8,10,11,12);
hide.push(5); // abstract
show.push(6); // separator
disable.push(m.showInLibrary, m.addNote, m.attachSnapshot, m.attachLink,
m.deleteItem, m.deleteFromLibrary, m.exportItems, m.createBib, m.loadReport);
hide.push(m.toggleAbstract);
show.push(m.sep2);
}
// Remove from collection
if (itemsView._itemGroup.isCollection())
{
menu.childNodes[7].setAttribute('label', Zotero.getString('pane.items.menu.remove' + multiple));
show.push(7);
menu.childNodes[m.deleteItem].setAttribute('label', Zotero.getString('pane.items.menu.remove' + multiple));
show.push(m.deleteItem);
}
else
{
hide.push(7);
hide.push(m.deleteItem);
}
// Plural if necessary
menu.childNodes[8].setAttribute('label', Zotero.getString('pane.items.menu.erase' + multiple));
menu.childNodes[10].setAttribute('label', Zotero.getString('pane.items.menu.export' + multiple));
menu.childNodes[11].setAttribute('label', Zotero.getString('pane.items.menu.createBib' + multiple));
menu.childNodes[12].setAttribute('label', Zotero.getString('pane.items.menu.generateReport' + multiple));
menu.childNodes[m.deleteFromLibrary].setAttribute('label', Zotero.getString('pane.items.menu.erase' + multiple));
menu.childNodes[m.exportItems].setAttribute('label', Zotero.getString('pane.items.menu.export' + multiple));
menu.childNodes[m.createBib].setAttribute('label', Zotero.getString('pane.items.menu.createBib' + multiple));
menu.childNodes[m.loadReport].setAttribute('label', Zotero.getString('pane.items.menu.generateReport' + multiple));
for (var i in disable)
{
@ -876,6 +928,7 @@ var ZoteroPane = new function()
}
}
// Adapted from: http://www.xulplanet.com/references/elemref/ref_tree.html#cmnote-9
function onDoubleClick(event, tree)
{
@ -901,6 +954,19 @@ var ZoteroPane = new function()
}
function setItemsPaneMessage(msg) {
document.getElementById('zotero-items-pane-content').selectedIndex = 1;
var elem = document.getElementById('zotero-items-pane-message');
elem.value = msg;
}
function clearItemsPaneMessage() {
document.getElementById('zotero-items-pane-content').selectedIndex = 0;
document.getElementById('zotero-items-pane-message').value = '';
}
// Updates browser context menu options
function contextPopupShowing()
{

View file

@ -94,6 +94,7 @@
<menuitem oncommand="Zotero_Report_Interface.loadItemReport()"/>
</popup>
</popupset>
<vbox id="zotero-collections-pane" persist="width" flex="1">
<toolbar>
<toolbarbutton id="zotero-tb-collection-add" tooltiptext="&zotero.toolbar.newCollection.label;" oncommand="ZoteroPane.newCollection()"/>
@ -129,7 +130,9 @@
<splitter id="zotero-tags-splitter"/>
<zoterotagselector id="zotero-tag-selector" persist="height,collapsed" oncommand="ZoteroPane.updateTagFilter()"/>
</vbox>
<splitter id="zotero-tree-splitter" resizebefore="closest" resizeafter="closest"/>
<vbox id="zotero-items-pane" persist="width" flex="1">
<toolbar align="center">
<toolbarbutton id="zotero-tb-add" tooltiptext="&zotero.toolbar.newItem.label;" type="menu">
@ -151,62 +154,77 @@
<toolbarbutton id="zotero-tb-note-add" tooltiptext="&zotero.toolbar.note.standalone;" oncommand="ZoteroPane.newNote(event.shiftKey);"/>
<spacer flex="1"/>
<label value="&zotero.toolbar.search.label;" control="zotero-tb-search"/>
<textbox id="zotero-tb-search" type="timed" timeout="250" command="cmd_zotero_search" dir="reverse"
onkeypress="if (event.keyCode == event.DOM_VK_ESCAPE) { this.value = ''; this.doCommand('cmd_zotero_search'); }">
<textbox id="zotero-tb-search" type="conditional-timed" timeout="250" command="cmd_zotero_search" dir="reverse"
onkeypress="ZoteroPane.handleSearchKeypress(this, event)"
oninput="ZoteroPane.handleSearchInput(this, event)"
testcode="me.value.indexOf('&quot;') == -1"
prefire="ZoteroPane.clearItemsPaneMessage()"
ontestfail="ZoteroPane.setItemsPaneMessage(Zotero.getString('advancedSearchMode'))">
<toolbarbutton id="zotero-tb-search-cancel" oncommand="this.parentNode.value='';" hidden="true"/>
</textbox>
</toolbar>
<tree
id="zotero-items-tree" context="zotero-itemmenu"
ondblclick="ZoteroPane.onDoubleClick(event, this);"
enableColumnDrag="true"
onfocus="if (ZoteroPane.getItemsView().rowCount &amp;&amp; !ZoteroPane.getItemsView().selection.count) { ZoteroPane.getItemsView().selection.select(0); }"
onkeypress="if (event.keyCode == event.DOM_VK_BACK_SPACE || event.keyCode == event.DOM_VK_DELETE){ ZoteroPane.deleteSelectedItem(); event.preventDefault(); }"
onselect="ZoteroPane.itemSelected();"
ondraggesture="if (event.target.localName == 'treechildren') nsDragAndDrop.startDrag(event,ZoteroPane.getItemsView());"
ondragover="nsDragAndDrop.dragOver(event,ZoteroPane.getItemsView())"
ondragdrop="nsDragAndDrop.drop(event,ZoteroPane.getItemsView())"
flex="1">
<treecols>
<treecol
id="zotero-items-title-column" primary="true"
label="&zotero.items.title_column;"
flex="4" persist="width ordinal hidden sortActive sortDirection"/>
<splitter class="tree-splitter"/>
<treecol
id="zotero-items-firstCreator-column"
label="&zotero.items.creator_column;"
flex="1" persist="width ordinal hidden sortActive sortDirection"/>
<splitter class="tree-splitter"/>
<treecol
id="zotero-items-numChildren-column"
label="&zotero.items.numChildren_column;"
persist="width ordinal hidden sortActive sortDirection"/>
<splitter class="tree-splitter"/>
<treecol
id="zotero-items-typeIcon-column" hidden="true"
label="&zotero.items.type_column;"
width="40" persist="width ordinal hidden sortActive sortDirection"/>
<splitter class="tree-splitter"/>
<treecol
id="zotero-items-rights-column" hidden="true"
label="&zotero.items.rights_column;"
flex="1" persist="width ordinal hidden sortActive sortDirection"/>
<splitter class="tree-splitter"/>
<treecol
id="zotero-items-dateAdded-column" hidden="true"
label="&zotero.items.dateAdded_column;"
flex="1" persist="width ordinal hidden sortActive sortDirection"/>
<splitter class="tree-splitter"/>
<treecol
id="zotero-items-dateModified-column" hidden="true"
label="&zotero.items.dateModified_column;"
flex="1" persist="width ordinal hidden sortActive sortDirection"/>
</treecols>
<treechildren/>
</tree>
<deck id="zotero-items-pane-content" selectedIndex="0" flex="1">
<tree
id="zotero-items-tree" context="zotero-itemmenu"
ondblclick="ZoteroPane.onDoubleClick(event, this);"
enableColumnDrag="true"
onfocus="if (ZoteroPane.getItemsView().rowCount &amp;&amp; !ZoteroPane.getItemsView().selection.count) { ZoteroPane.getItemsView().selection.select(0); }"
onkeypress="if (event.keyCode == event.DOM_VK_BACK_SPACE || event.keyCode == event.DOM_VK_DELETE){ ZoteroPane.deleteSelectedItem(); event.preventDefault(); }"
onselect="ZoteroPane.itemSelected();"
ondraggesture="if (event.target.localName == 'treechildren') nsDragAndDrop.startDrag(event,ZoteroPane.getItemsView());"
ondragover="nsDragAndDrop.dragOver(event,ZoteroPane.getItemsView())"
ondragdrop="nsDragAndDrop.drop(event,ZoteroPane.getItemsView())"
flex="1">
<treecols>
<treecol
id="zotero-items-title-column" primary="true"
label="&zotero.items.title_column;"
flex="4" persist="width ordinal hidden sortActive sortDirection"/>
<splitter class="tree-splitter"/>
<treecol
id="zotero-items-firstCreator-column"
label="&zotero.items.creator_column;"
flex="1" persist="width ordinal hidden sortActive sortDirection"/>
<splitter class="tree-splitter"/>
<treecol
id="zotero-items-numChildren-column"
label="&zotero.items.numChildren_column;"
persist="width ordinal hidden sortActive sortDirection"/>
<splitter class="tree-splitter"/>
<treecol
id="zotero-items-typeIcon-column" hidden="true"
label="&zotero.items.type_column;"
width="40" persist="width ordinal hidden sortActive sortDirection"/>
<splitter class="tree-splitter"/>
<treecol
id="zotero-items-rights-column" hidden="true"
label="&zotero.items.rights_column;"
flex="1" persist="width ordinal hidden sortActive sortDirection"/>
<splitter class="tree-splitter"/>
<treecol
id="zotero-items-dateAdded-column" hidden="true"
label="&zotero.items.dateAdded_column;"
flex="1" persist="width ordinal hidden sortActive sortDirection"/>
<splitter class="tree-splitter"/>
<treecol
id="zotero-items-dateModified-column" hidden="true"
label="&zotero.items.dateModified_column;"
flex="1" persist="width ordinal hidden sortActive sortDirection"/>
</treecols>
<treechildren/>
</tree>
<!-- Label for displaying messages when items pane is hidden
(e.g. "Advanced search mode — press Enter to search.")-->
<box pack="center" align="center">
<label id="zotero-items-pane-message" />
</box>
</deck>
</vbox>
<splitter id="zotero-view-splitter" resizebefore="closest" resizeafter="closest"/>
<vbox id="zotero-item-pane" persist="width">
<toolbar align="right">
<toolbarbutton id="zotero-tb-fullscreen" tooltiptext="&zotero.toolbar.fullscreen.tooltip;" oncommand="ZoteroPane.fullScreen();"/>

View file

@ -330,7 +330,8 @@ Zotero.Fulltext = new function(){
// If not binary mode, only scan plaintext files
if (!mode || mode.indexOf('Binary')==-1){
if (i.getAttachmentMimeType().substr(0,5)!='text/'){
if (!Zotero.MIME.isTextType(i.getAttachmentMimeType())) {
Zotero.debug('Not scanning MIME type ' + mimeType, 4);
continue;
}
}

View file

@ -21,6 +21,7 @@
*/
Zotero.MIME = new function(){
this.isTextType = isTextType;
this.isExternalTextExtension = isExternalTextExtension;
this.sniffForMIMEType = sniffForMIMEType;
this.sniffForBinary = sniffForBinary;
@ -41,6 +42,12 @@ Zotero.MIME = new function(){
["<?xml", 'text/xml']
];
var _textTypes = {
'application/xhtml+xml': true,
'application/xml': true,
'application/x-javascript': true
};
// MIME types handled natively by Gecko
// DEBUG: There's definitely a better way of getting these
var _nativeMIMETypes = {
@ -61,6 +68,12 @@ Zotero.MIME = new function(){
};
function isTextType(mimeType) {
return mimeType.substr(0, 5) == 'text/' || _textTypes[mimeType];
}
/*
* Check if file extension should be forced to open externally
*/

View file

@ -112,10 +112,10 @@ Zotero.Schema = new function(){
}
}
// If transaction already in progress, delay by a few seconds
// If transaction already in progress, delay by ten minutes
if (Zotero.DB.transactionInProgress()){
Zotero.debug('Transaction in progress -- delaying repository check', 4)
_setRepositoryTimer(30);
_setRepositoryTimer(600);
return false;
}
@ -530,6 +530,12 @@ Zotero.Schema = new function(){
// https://bugzilla.mozilla.org/show_bug.cgi?id=194231
xmlnode.normalize();
// Delete local version of remote translators with priority 0
if (xmlnode.getElementsByTagName('priority')[0].firstChild.nodeValue === "0") {
var sql = "DELETE FROM translators WHERE translatorID=?";
return Zotero.DB.query(sql, {string: xmlnode.getAttribute('id')});
}
var sqlValues = [
{string: xmlnode.getAttribute('id')},
{string: xmlnode.getAttribute('minVersion')},

View file

@ -176,18 +176,29 @@ Zotero.Search.prototype.addCondition = function(condition, operator, value, requ
if (condition=='quicksearch'){
this.addCondition('joinMode', 'any');
// Quicksearch words don't need to be phrases
var words = Zotero.Fulltext.semanticSplitter(value);
for each(var i in words){
var parts = Zotero.SearchConditions.parseSearchString(value);
for each(var part in parts) {
this.addCondition('blockStart');
this.addCondition('title', operator, i, false);
this.addCondition('field', operator, i, false);
this.addCondition('numberfield', operator, i, false);
this.addCondition('creator', operator, i, false);
this.addCondition('tag', operator, i, false);
this.addCondition('note', operator, i, false);
this.addCondition('fulltextWord', operator, i, false);
this.addCondition('title', operator, part.text, false);
this.addCondition('field', operator, part.text, false);
this.addCondition('numberfield', operator, part.text, false);
this.addCondition('creator', operator, part.text, false);
this.addCondition('tag', operator, part.text, false);
this.addCondition('note', operator, part.text, false);
if (part.inQuotes) {
this.addCondition('fulltextContent', operator, part.text, false);
}
else {
var splits = Zotero.Fulltext.semanticSplitter(part.text);
for each(var split in splits) {
this.addCondition('fulltextWord', operator, split, false);
}
}
this.addCondition('blockEnd');
}
return false;
}
@ -271,14 +282,53 @@ Zotero.Search.prototype.search = function(){
var ids = Zotero.DB.columnQuery(this._sql, this._sqlParams);
if (!ids){
return false;
var joinMode = 'all';
for each(var condition in this._conditions) {
if (condition.condition == 'joinMode') {
if (condition.operator == 'any') {
joinMode = 'any';
}
break;
}
}
// Filter results with fulltext search
//
// If join mode ANY, return the superset of the main search and
// (a separate fulltext word search filtered by fulltext content)
//
// If join mode ALL, return the (union of SQL and fulltext word search)
// filtered by fulltext content
for each(var condition in this._conditions){
if (condition['condition']=='fulltextContent'){
var fulltextIDs = Zotero.Fulltext.findTextInItems(ids,
// Run a new search against the fulltext word index
// for words in this phrase
var s = new Zotero.Search();
var splits = Zotero.Fulltext.semanticSplitter(condition.value);
for each(var split in splits){
s.addCondition('fulltextWord', condition.operator, split, false);
}
var fulltextWordIDs = s.search();
var filter = function(val, index, array) {
return hash[val] ?
(condition.operator == 'contains') :
(condition.operator == 'doesNotContain');
}
// If ALL mode, get union of main search and fulltext word index
if (joinMode == 'all') {
var hash = {};
for each(var id in fulltextWordIDs){
hash[id] = true;
}
}
else {
var scopeIDs = fulltextWordIDs;
}
var fulltextIDs = Zotero.Fulltext.findTextInItems(scopeIDs,
condition['value'], condition['mode']);
var hash = {};
@ -286,24 +336,20 @@ Zotero.Search.prototype.search = function(){
hash[val.id] = true;
}
switch (condition['operator']){
case 'contains':
var filter = function(val, index, array){
return hash[val] ? true : false;
}
break;
case 'doesNotContain':
var filter = function(val, index, array){
return hash[val] ? false : true;
}
break;
default:
continue;
}
var filteredIDs = scopeIDs ? scopeIDs.filter(filter) : [];
var ids = ids.filter(filter);
// If join mode ANY, add any new items from the fulltext content
// search to the main search results
if (joinMode == 'any' && ids) {
for each(var id in filteredIDs) {
if (ids.indexOf(id) == -1) {
ids.push(id);
}
}
}
else {
ids = filteredIDs;
}
}
}
@ -801,6 +847,7 @@ Zotero.SearchConditions = new function(){
this.get = get;
this.getStandardConditions = getStandardConditions;
this.hasOperator = hasOperator;
this.parseSearchString = parseSearchString;
this.parseCondition = parseCondition;
var _initialized = false;
@ -1173,6 +1220,41 @@ Zotero.SearchConditions = new function(){
}
/*
* Parses a search into words and "double-quoted phrases"
*
* Also strips unpaired quotes at the beginning and end of words
*
* Returns array of objects containing 'text' and 'inQuotes'
*/
function parseSearchString(str) {
var parts = str.split(/\s*("[^"]*")\s*|"\s|\s"|^"|"$|'\s|\s'|^'|'$|\s/m);
var parsed = [];
for (var i in parts) {
var part = parts[i];
if (!part.length) {
continue;
}
if (part.charAt(0)=='"' && part.charAt(part.length-1)=='"') {
parsed.push({
text: part.substring(1, part.length-1),
inQuotes: true
});
}
else {
parsed.push({
text: part,
inQuotes: false
});
}
}
return parsed;
}
function parseCondition(condition){
var mode = false;
var pos = condition.indexOf('/');

View file

@ -228,6 +228,9 @@ fileInterface.noReferencesError = The items you have selected contain no referen
fileInterface.bibliographyGenerationError = An error occurred generating your bibliography. Please try again.
fileInterface.exportError = An error occurred while trying to export the selected file.
advancedSearchMode = Advanced search mode — press Enter to search.
searchInProgress = Search in progress — press wait.
searchOperator.is = is
searchOperator.isNot = is not
searchOperator.contains = contains

View file

@ -31,6 +31,11 @@ toolbar[iconsize="small"] #zotero-toolbar-button:active
/* Bindings */
textbox[type="conditional-timed"]
{
-moz-binding: url('chrome://zotero/content/bindings/conditional-timed-textbox.xml#conditional-timed-textbox');
}
textbox[multiline="true"][type="timed"]
{
-moz-binding: url('chrome://zotero/content/bindings/timedtextarea.xml#timed-textarea');