fx-compat: Fix search dialogs (#2631)
This commit is contained in:
parent
b78b9cad1f
commit
8face792c0
15 changed files with 1056 additions and 1217 deletions
|
@ -21,10 +21,23 @@
|
||||||
onunload="ZoteroAdvancedSearch.onUnload();"
|
onunload="ZoteroAdvancedSearch.onUnload();"
|
||||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||||
xmlns:html="http://www.w3.org/1999/xhtml"
|
xmlns:html="http://www.w3.org/1999/xhtml"
|
||||||
windowtype="zotero:search">
|
windowtype="zotero:search"
|
||||||
|
style="display: flex;">
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||||
|
Services.scriptloader.loadSubScript("chrome://zotero/content/elements/zoteroSearch.js", this);
|
||||||
|
</script>
|
||||||
|
|
||||||
<script src="include.js"/>
|
<script src="include.js"/>
|
||||||
<script src="advancedSearch.js"/>
|
<script src="advancedSearch.js"/>
|
||||||
|
|
||||||
|
<popupset>
|
||||||
|
<panel is="autocomplete-richlistbox-popup"
|
||||||
|
id="search-autocomplete-popup"
|
||||||
|
type="autocomplete-richlistbox"
|
||||||
|
noautofocus="true"/>
|
||||||
|
</popupset>
|
||||||
|
|
||||||
<vbox id="zotero-search-box-container" flex="1">
|
<vbox id="zotero-search-box-container" flex="1">
|
||||||
<vbox id="zotero-search-box-controls">
|
<vbox id="zotero-search-box-controls">
|
File diff suppressed because it is too large
Load diff
952
chrome/content/zotero/elements/zoteroSearch.js
Normal file
952
chrome/content/zotero/elements/zoteroSearch.js
Normal file
|
@ -0,0 +1,952 @@
|
||||||
|
/*
|
||||||
|
***** BEGIN LICENSE BLOCK *****
|
||||||
|
|
||||||
|
Copyright © 2022 Corporation for Digital Scholarship
|
||||||
|
Vienna, Virginia, USA
|
||||||
|
https://www.zotero.org
|
||||||
|
|
||||||
|
This file is part of Zotero.
|
||||||
|
|
||||||
|
Zotero is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Zotero is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
***** END LICENSE BLOCK *****
|
||||||
|
*/
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
{
|
||||||
|
var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||||
|
|
||||||
|
Services.scriptloader.loadSubScript("chrome://global/content/customElements.js", this);
|
||||||
|
Services.scriptloader.loadSubScript("chrome://zotero/content/elements/base.js", this);
|
||||||
|
Services.scriptloader.loadSubScript("chrome://zotero/content/elements/shadowAutocompleteInput.js", this);
|
||||||
|
|
||||||
|
class SearchElementBase extends XULElementBase {
|
||||||
|
get stylesheets() {
|
||||||
|
return [
|
||||||
|
'chrome://global/skin/global.css',
|
||||||
|
'chrome://zotero-platform/content/zoteroSearch.css'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ZoteroSearch extends SearchElementBase {
|
||||||
|
content = MozXULElement.parseXULToFragment(`
|
||||||
|
<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||||
|
id="search-box" flex="1" onkeypress="this.getRootNode().host.handleKeyPress(event)">
|
||||||
|
<hbox align="center">
|
||||||
|
<label value="&zotero.search.searchInLibrary;" control="libraryMenu"/>
|
||||||
|
<menulist id="libraryMenu" oncommand="this.getRootNode().host.updateLibrary();" native="true">
|
||||||
|
<menupopup/>
|
||||||
|
</menulist>
|
||||||
|
</hbox>
|
||||||
|
<groupbox>
|
||||||
|
<caption align="center">
|
||||||
|
<label value="&zotero.search.joinMode.prefix;"/>
|
||||||
|
<menulist id="joinModeMenu" oncommand="this.getRootNode().host.updateJoinMode();" native="true">
|
||||||
|
<menupopup>
|
||||||
|
<menuitem label="&zotero.search.joinMode.any;" value="any"/>
|
||||||
|
<menuitem label="&zotero.search.joinMode.all;" value="all" selected="true"/>
|
||||||
|
</menupopup>
|
||||||
|
</menulist>
|
||||||
|
<label value="&zotero.search.joinMode.suffix;"/>
|
||||||
|
</caption>
|
||||||
|
<vbox id="conditions"/>
|
||||||
|
</groupbox>
|
||||||
|
<hbox>
|
||||||
|
<checkbox id="recursiveCheckbox" label="&zotero.search.recursive.label;" oncommand="this.getRootNode().host.updateCheckbox('recursive');" native="true"/>
|
||||||
|
<checkbox id="noChildrenCheckbox" label="&zotero.search.noChildren;" oncommand="this.getRootNode().host.updateCheckbox('noChildren');" native="true"/>
|
||||||
|
</hbox>
|
||||||
|
<hbox>
|
||||||
|
<checkbox id="includeParentsAndChildrenCheckbox" label="&zotero.search.includeParentsAndChildren;" oncommand="this.getRootNode().host.updateCheckbox('includeParentsAndChildren');" native="true"/>
|
||||||
|
</hbox>
|
||||||
|
</vbox>
|
||||||
|
`, ['chrome://zotero/locale/zotero.dtd', 'chrome://zotero/locale/searchbox.dtd']);
|
||||||
|
|
||||||
|
get search() {
|
||||||
|
return this.searchRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
set search(val) {
|
||||||
|
this.searchRef = val;
|
||||||
|
|
||||||
|
var libraryMenu = this.shadowRoot.getElementById('libraryMenu');
|
||||||
|
var libraries = Zotero.Libraries.getAll();
|
||||||
|
Zotero.Utilities.Internal.buildLibraryMenu(
|
||||||
|
libraryMenu, libraries, this.searchRef.libraryID
|
||||||
|
);
|
||||||
|
if (this.searchRef.id) {
|
||||||
|
libraryMenu.disabled = true;
|
||||||
|
}
|
||||||
|
this.updateLibrary();
|
||||||
|
|
||||||
|
|
||||||
|
var conditionsBox = this.shadowRoot.getElementById('conditions');
|
||||||
|
while (conditionsBox.hasChildNodes())
|
||||||
|
conditionsBox.removeChild(conditionsBox.firstChild);
|
||||||
|
|
||||||
|
var conditions = this.search.getConditions();
|
||||||
|
for (let id in conditions) {
|
||||||
|
let condition = conditions[id];
|
||||||
|
// Checkboxes
|
||||||
|
switch (condition.condition) {
|
||||||
|
case 'recursive':
|
||||||
|
case 'noChildren':
|
||||||
|
case 'includeParentsAndChildren':
|
||||||
|
let checkbox = condition.condition + 'Checkbox';
|
||||||
|
this.shadowRoot.getElementById(checkbox).setAttribute('condition', id);
|
||||||
|
this.shadowRoot.getElementById(checkbox).checked = condition.operator == 'true';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (condition.condition == 'joinMode') {
|
||||||
|
this.shadowRoot.getElementById('joinModeMenu').setAttribute('condition', id);
|
||||||
|
this.shadowRoot.getElementById('joinModeMenu').value = condition.operator;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.addCondition(condition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addCondition(ref) {
|
||||||
|
var conditionsBox = this.shadowRoot.getElementById('conditions');
|
||||||
|
var condition = document.createXULElement('zoterosearchcondition');
|
||||||
|
condition.setAttribute('flex', '1');
|
||||||
|
|
||||||
|
conditionsBox.appendChild(condition);
|
||||||
|
|
||||||
|
// Default to an empty 'title' condition
|
||||||
|
if (!ref) {
|
||||||
|
ref = this.search.getCondition(this.search.addCondition("title","contains",""))
|
||||||
|
}
|
||||||
|
|
||||||
|
condition.initWithParentAndCondition(this, ref);
|
||||||
|
|
||||||
|
if (conditionsBox.childNodes.length == 2){
|
||||||
|
conditionsBox.childNodes[0].enableRemoveButton();
|
||||||
|
}
|
||||||
|
else if (conditionsBox.childNodes.length == 1){
|
||||||
|
conditionsBox.childNodes[0].disableRemoveButton();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
removeCondition(id) {
|
||||||
|
var conditionsBox = this.shadowRoot.getElementById('conditions');
|
||||||
|
|
||||||
|
this.search.removeCondition(id);
|
||||||
|
|
||||||
|
for (var i = 0, len=conditionsBox.childNodes.length; i < len; i++){
|
||||||
|
if (conditionsBox.childNodes[i].conditionID == id){
|
||||||
|
conditionsBox.removeChild(conditionsBox.childNodes[i]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conditionsBox.childNodes.length == 1){
|
||||||
|
conditionsBox.childNodes[0].disableRemoveButton();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateLibrary() {
|
||||||
|
var menu = this.shadowRoot.getElementById('libraryMenu');
|
||||||
|
var libraryID = parseInt(menu.selectedItem.value);
|
||||||
|
|
||||||
|
if (this.onLibraryChange) {
|
||||||
|
this.onLibraryChange(libraryID);
|
||||||
|
}
|
||||||
|
if (!this.searchRef.id) {
|
||||||
|
this.searchRef.libraryID = libraryID;
|
||||||
|
}
|
||||||
|
|
||||||
|
[...this.shadowRoot.getElementById('conditions').childNodes].forEach(x => x.onLibraryChange());
|
||||||
|
}
|
||||||
|
|
||||||
|
updateJoinMode() {
|
||||||
|
var menu = this.shadowRoot.getElementById('joinModeMenu');
|
||||||
|
if(menu.hasAttribute('condition'))
|
||||||
|
this.search.updateCondition(menu.getAttribute('condition'),'joinMode',menu.value,null);
|
||||||
|
else
|
||||||
|
menu.setAttribute('condition', this.search.addCondition('joinMode',menu.value,null));
|
||||||
|
}
|
||||||
|
|
||||||
|
updateCheckbox(condition) {
|
||||||
|
var checkbox = this.shadowRoot.getElementById(condition + 'Checkbox');
|
||||||
|
var value = checkbox.checked ? 'true' : 'false';
|
||||||
|
if(checkbox.hasAttribute('condition'))
|
||||||
|
{
|
||||||
|
this.search.updateCondition(checkbox.getAttribute('condition'),
|
||||||
|
condition, value, null);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
checkbox.setAttribute('condition',
|
||||||
|
this.search.addCondition(condition, value, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calls updateSearch() on all search conditions
|
||||||
|
updateSearch() {
|
||||||
|
var conditionsBox = this.shadowRoot.getElementById('conditions');
|
||||||
|
if (conditionsBox.hasChildNodes()) {
|
||||||
|
for(var i = 0, len=conditionsBox.childNodes.length; i < len; i++) {
|
||||||
|
conditionsBox.childNodes[i].updateSearch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleKeyPress(event) {
|
||||||
|
switch (event.keyCode) {
|
||||||
|
case event.DOM_VK_RETURN:
|
||||||
|
this.active = true;
|
||||||
|
|
||||||
|
if (event.shiftKey) {
|
||||||
|
this.addCondition();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.doCommand();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
customElements.define("zoterosearch", ZoteroSearch);
|
||||||
|
|
||||||
|
class ZoteroSearchCondition extends SearchElementBase {
|
||||||
|
content = MozXULElement.parseXULToFragment(`
|
||||||
|
<xul:hbox id="search-condition" xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||||
|
flex="1">
|
||||||
|
<xul:popupset id="condition-tooltips"/>
|
||||||
|
|
||||||
|
<xul:menulist id="conditionsmenu" oncommand="this.getRootNode().host.onConditionSelected(event.target.value); event.stopPropagation()" native="true">
|
||||||
|
<xul:menupopup onpopupshown="this.getRootNode().host.revealSelectedCondition()">
|
||||||
|
<xul:menu id="more-conditions-menu" label="&zotero.general.more;">
|
||||||
|
<xul:menupopup/>
|
||||||
|
</xul:menu>
|
||||||
|
</xul:menupopup>
|
||||||
|
</xul:menulist>
|
||||||
|
<xul:menulist id="operatorsmenu" oncommand="this.getRootNode().host.onOperatorSelected(); event.stopPropagation()" native="true">
|
||||||
|
<xul:menupopup/>
|
||||||
|
</xul:menulist>
|
||||||
|
<xul:zoterosearchtextbox id="valuefield" flex="1"/>
|
||||||
|
<xul:menulist id="valuemenu" flex="1" hidden="true" native="true">
|
||||||
|
<xul:menupopup/>
|
||||||
|
</xul:menulist>
|
||||||
|
<xul:zoterosearchagefield id="value-date-age" hidden="true" flex="1"/>
|
||||||
|
<xul:label id="remove" class="zotero-clicky zotero-clicky-minus" value="-" onclick="this.getRootNode().host.onRemoveClicked(event)"/>
|
||||||
|
<xul:label id="add" class="zotero-clicky zotero-clicky-plus" value="+" onclick="this.getRootNode().host.onAddClicked(event)"/>
|
||||||
|
</xul:hbox>
|
||||||
|
`, ['chrome://zotero/locale/zotero.dtd', 'chrome://zotero/locale/searchbox.dtd']);
|
||||||
|
|
||||||
|
init() {
|
||||||
|
var operators = [
|
||||||
|
'is',
|
||||||
|
'isNot',
|
||||||
|
'beginsWith',
|
||||||
|
'contains',
|
||||||
|
'doesNotContain',
|
||||||
|
'isLessThan',
|
||||||
|
'isGreaterThan',
|
||||||
|
'isBefore',
|
||||||
|
'isAfter',
|
||||||
|
'isInTheLast'
|
||||||
|
];
|
||||||
|
var operatorsList = this.shadowRoot.getElementById('operatorsmenu');
|
||||||
|
|
||||||
|
// Build operator menu
|
||||||
|
for (let operator of operators) {
|
||||||
|
operatorsList.appendItem(
|
||||||
|
Zotero.getString('searchOperator.' + operator),
|
||||||
|
operator
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build conditions menu
|
||||||
|
var conditionsMenu = this.shadowRoot.getElementById('conditionsmenu');
|
||||||
|
var moreConditionsMenu = this.shadowRoot.getElementById('more-conditions-menu');
|
||||||
|
var conditions = Zotero.SearchConditions.getStandardConditions();
|
||||||
|
|
||||||
|
for (let condition of conditions) {
|
||||||
|
if (this.isPrimaryCondition(condition.name)) {
|
||||||
|
var menuitem = document.createXULElement('menuitem');
|
||||||
|
menuitem.setAttribute('label', condition.localized);
|
||||||
|
menuitem.setAttribute('value', condition.name);
|
||||||
|
moreConditionsMenu.before(menuitem);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var menuitem = moreConditionsMenu.appendItem(
|
||||||
|
condition.localized, condition.name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
var baseFields = null;
|
||||||
|
try {
|
||||||
|
baseFields = Zotero.ItemFields.getTypeFieldsFromBase(condition.name);
|
||||||
|
}
|
||||||
|
catch (e) {}
|
||||||
|
|
||||||
|
// Add tooltip, building it if it doesn't exist
|
||||||
|
if (baseFields) {
|
||||||
|
if (!this.shadowRoot.getElementById(condition.name + '-tooltip')) {
|
||||||
|
var fieldName = null;
|
||||||
|
try {
|
||||||
|
fieldName = Zotero.ItemFields.getLocalizedString(condition.name);
|
||||||
|
}
|
||||||
|
catch (e) {}
|
||||||
|
|
||||||
|
if (fieldName) {
|
||||||
|
var localized = [fieldName];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var localized = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let baseField of baseFields) {
|
||||||
|
var str = Zotero.SearchConditions.getLocalizedName(
|
||||||
|
Zotero.ItemFields.getName(baseField)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (localized.indexOf(str) == -1) {
|
||||||
|
localized.push(str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
localized.sort();
|
||||||
|
|
||||||
|
var tt = document.createXULElement('tooltip');
|
||||||
|
tt.setAttribute('id', condition.name + '-tooltip');
|
||||||
|
tt.setAttribute('noautohide', true);
|
||||||
|
|
||||||
|
var hbox = document.createXULElement('hbox');
|
||||||
|
|
||||||
|
var label = document.createXULElement('label');
|
||||||
|
label.setAttribute('value', Zotero.getString('searchConditions.tooltip.fields'));
|
||||||
|
hbox.appendChild(label);
|
||||||
|
var vbox = document.createXULElement('vbox');
|
||||||
|
for (let str of localized) {
|
||||||
|
let label = document.createXULElement('label');
|
||||||
|
label.setAttribute('value', str);
|
||||||
|
vbox.appendChild(label);
|
||||||
|
}
|
||||||
|
hbox.appendChild(vbox);
|
||||||
|
tt.appendChild(hbox);
|
||||||
|
|
||||||
|
this.shadowRoot.getElementById('condition-tooltips').appendChild(tt);
|
||||||
|
}
|
||||||
|
|
||||||
|
menuitem.setAttribute('tooltip', condition.name + '-tooltip');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
conditionsMenu.selectedIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
isPrimaryCondition(condition) {
|
||||||
|
switch (condition) {
|
||||||
|
case 'collection':
|
||||||
|
case 'creator':
|
||||||
|
case 'title':
|
||||||
|
case 'date':
|
||||||
|
case 'dateAdded':
|
||||||
|
case 'dateModified':
|
||||||
|
case 'itemType':
|
||||||
|
case 'fileTypeID':
|
||||||
|
case 'publicationTitle':
|
||||||
|
case 'tag':
|
||||||
|
case 'note':
|
||||||
|
case 'childNote':
|
||||||
|
case 'fulltextContent':
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
onConditionSelected(conditionName, reload) {
|
||||||
|
var conditionsMenu = this.shadowRoot.getElementById('conditionsmenu');
|
||||||
|
var operatorsList = this.shadowRoot.getElementById('operatorsmenu');
|
||||||
|
|
||||||
|
// Skip if no condition or correct condition already selected
|
||||||
|
if (!conditionName || (conditionName == this.selectedCondition && !reload)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.selectedCondition = conditionName;
|
||||||
|
this.selectedOperator = operatorsList.value;
|
||||||
|
|
||||||
|
var condition = Zotero.SearchConditions.get(conditionName);
|
||||||
|
var operators = condition.operators;
|
||||||
|
|
||||||
|
conditionsMenu.value = conditionName;
|
||||||
|
// Store in attribute as well because the value doesn't get set properly when
|
||||||
|
// the value is from a menuitem in the More menu, and we need this to select
|
||||||
|
// the previous condition when creating a new row
|
||||||
|
conditionsMenu.setAttribute('data-value', conditionName);
|
||||||
|
|
||||||
|
// Parent state isn't set automatically for submenu selections
|
||||||
|
if (!this.isPrimaryCondition(conditionName)) {
|
||||||
|
conditionsMenu.selectedIndex = -1;
|
||||||
|
conditionsMenu.setAttribute(
|
||||||
|
'label',
|
||||||
|
Zotero.SearchConditions.getLocalizedName(conditionName)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updateSubmenuCheckboxes(conditionsMenu);
|
||||||
|
|
||||||
|
// Display appropriate operators for condition
|
||||||
|
var selectThis;
|
||||||
|
for(var i = 0, len = operatorsList.firstChild.childNodes.length; i < len; i++)
|
||||||
|
{
|
||||||
|
var val = operatorsList.firstChild.childNodes[i].getAttribute('value');
|
||||||
|
var hidden = !operators[val];
|
||||||
|
operatorsList.firstChild.childNodes[i].setAttribute('hidden', hidden);
|
||||||
|
if (!hidden && (selectThis == null || this.selectedOperator == val))
|
||||||
|
{
|
||||||
|
selectThis = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
operatorsList.selectedIndex = selectThis;
|
||||||
|
|
||||||
|
// Generate drop-down menu instead of textbox for certain conditions
|
||||||
|
switch (conditionName) {
|
||||||
|
case 'collection':
|
||||||
|
var rows = [];
|
||||||
|
|
||||||
|
var libraryID = this.parent.search.libraryID;
|
||||||
|
|
||||||
|
// Add collections
|
||||||
|
let cols = Zotero.Collections.getByLibrary(libraryID, true);
|
||||||
|
for (let col of cols) {
|
||||||
|
// Indent subcollections
|
||||||
|
var indent = '';
|
||||||
|
if (col.level) {
|
||||||
|
for (let j = 1; j < col.level; j++) {
|
||||||
|
indent += ' ';
|
||||||
|
}
|
||||||
|
indent += '- ';
|
||||||
|
}
|
||||||
|
rows.push({
|
||||||
|
name: indent + col.name,
|
||||||
|
value: 'C' + col.key,
|
||||||
|
image: Zotero.Collection.prototype.treeViewImage
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add saved searches
|
||||||
|
let searches = Zotero.Searches.getByLibrary(libraryID);
|
||||||
|
for (let search of searches) {
|
||||||
|
if (search.id != this.parent.search.id) {
|
||||||
|
rows.push({
|
||||||
|
name: search.name,
|
||||||
|
value: 'S' + search.key,
|
||||||
|
image: Zotero.Search.prototype.treeViewImage
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.createValueMenu(rows);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'itemType':
|
||||||
|
var rows = Zotero.ItemTypes.getTypes().map(type => ({
|
||||||
|
name: Zotero.ItemTypes.getLocalizedString(type.id),
|
||||||
|
value: type.name
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Sort by localized name
|
||||||
|
var collation = Zotero.getLocaleCollation();
|
||||||
|
rows.sort((a, b) => collation.compareString(1, a.name, b.name));
|
||||||
|
|
||||||
|
this.createValueMenu(rows);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'fileTypeID':
|
||||||
|
var rows = Zotero.FileTypes.getTypes().map(type => ({
|
||||||
|
name: Zotero.getString('fileTypes.' + type.name),
|
||||||
|
value: type.id
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Sort by localized name
|
||||||
|
var collation = Zotero.getLocaleCollation();
|
||||||
|
rows.sort((a, b) => collation.compareString(1, a.name, b.name));
|
||||||
|
|
||||||
|
this.createValueMenu(rows);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (operatorsList.value=='isInTheLast')
|
||||||
|
{
|
||||||
|
this.shadowRoot.getElementById('value-date-age').value = this.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Textbox
|
||||||
|
else {
|
||||||
|
// If switching from menu to textbox, clear value
|
||||||
|
if (this.shadowRoot.getElementById('valuefield').hidden){
|
||||||
|
this.shadowRoot.getElementById('valuefield').value = '';
|
||||||
|
}
|
||||||
|
// If switching between textbox conditions, get loaded value for new one
|
||||||
|
else {
|
||||||
|
this.shadowRoot.getElementById('valuefield').value = this.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update field drop-down if applicable
|
||||||
|
this.shadowRoot.getElementById('valuefield').update(conditionName, this.mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.onOperatorSelected();
|
||||||
|
}
|
||||||
|
|
||||||
|
onOperatorSelected() {
|
||||||
|
var operatorsList = this.shadowRoot.getElementById('operatorsmenu');
|
||||||
|
|
||||||
|
// Drop-down menu
|
||||||
|
if (this.selectedCondition == 'collection'
|
||||||
|
|| this.selectedCondition == 'itemType'
|
||||||
|
|| this.selectedCondition == 'fileTypeID') {
|
||||||
|
this.shadowRoot.getElementById('valuefield').hidden = true;
|
||||||
|
this.shadowRoot.getElementById('valuemenu').hidden = false;
|
||||||
|
this.shadowRoot.getElementById('value-date-age').hidden = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Textbox + units dropdown for isInTheLast operator
|
||||||
|
else if (operatorsList.value=='isInTheLast')
|
||||||
|
{
|
||||||
|
// If switching from text field, clear value
|
||||||
|
if (this.shadowRoot.getElementById('value-date-age').hidden){
|
||||||
|
this.value = '';
|
||||||
|
}
|
||||||
|
this.shadowRoot.getElementById('valuefield').hidden = true;
|
||||||
|
this.shadowRoot.getElementById('valuemenu').hidden = true;
|
||||||
|
this.shadowRoot.getElementById('value-date-age').hidden = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Textbox
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If switching from date age, clear value
|
||||||
|
if (this.shadowRoot.getElementById('valuefield').hidden){
|
||||||
|
this.value = '';
|
||||||
|
}
|
||||||
|
this.shadowRoot.getElementById('valuefield').hidden = false;
|
||||||
|
this.shadowRoot.getElementById('valuemenu').hidden = true;
|
||||||
|
this.shadowRoot.getElementById('value-date-age').hidden = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
createValueMenu(rows) {
|
||||||
|
let valueMenu = this.shadowRoot.getElementById('valuemenu');
|
||||||
|
|
||||||
|
while (valueMenu.hasChildNodes()){
|
||||||
|
valueMenu.removeChild(valueMenu.firstChild);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let row of rows) {
|
||||||
|
let menuitem = valueMenu.appendItem(row.name, row.value);
|
||||||
|
if (row.image) {
|
||||||
|
menuitem.className = 'menuitem-iconic';
|
||||||
|
menuitem.setAttribute('image', row.image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
valueMenu.selectedIndex = 0;
|
||||||
|
|
||||||
|
if (this.value)
|
||||||
|
{
|
||||||
|
valueMenu.value = this.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
valueMenu.shadowRoot.querySelector('#label-box > image').style.maxHeight = '16px';
|
||||||
|
}
|
||||||
|
|
||||||
|
initWithParentAndCondition(parent, condition) {
|
||||||
|
this.parent = parent;
|
||||||
|
this.conditionID = condition['id'];
|
||||||
|
var menu = this.shadowRoot.getElementById('conditionsmenu');
|
||||||
|
|
||||||
|
if(this.parent.search)
|
||||||
|
{
|
||||||
|
this.dontupdate = true; //so that the search doesn't get updated while we are creating controls.
|
||||||
|
var prefix = '';
|
||||||
|
|
||||||
|
// Handle special conditions
|
||||||
|
switch (condition.condition) {
|
||||||
|
case 'savedSearch':
|
||||||
|
prefix = 'S';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'collection':
|
||||||
|
prefix = 'C';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map certain conditions to other menu items
|
||||||
|
let uiCondition = condition.condition;
|
||||||
|
switch (condition.condition) {
|
||||||
|
case 'savedSearch':
|
||||||
|
uiCondition = 'collection';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
menu.setAttribute('value', uiCondition);
|
||||||
|
|
||||||
|
// Convert datetimes from UTC to localtime
|
||||||
|
if ((condition['condition']=='accessDate' ||
|
||||||
|
condition['condition']=='dateAdded' ||
|
||||||
|
condition['condition']=='dateModified') &&
|
||||||
|
Zotero.Date.isSQLDateTime(condition['value'])){
|
||||||
|
|
||||||
|
condition['value'] =
|
||||||
|
Zotero.Date.dateToSQL(Zotero.Date.sqlToDate(condition['value'], true));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.mode = condition['mode'];
|
||||||
|
this.shadowRoot.getElementById('operatorsmenu').value = condition['operator'];
|
||||||
|
this.value = prefix +
|
||||||
|
(condition.value ? condition.value : '');
|
||||||
|
|
||||||
|
this.dontupdate = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.onConditionSelected(menu.value);
|
||||||
|
|
||||||
|
this.shadowRoot.getElementById('conditionsmenu').focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateSearch() {
|
||||||
|
if(this.parent && this.parent.search && !this.dontupdate)
|
||||||
|
{
|
||||||
|
var condition = this.selectedCondition;
|
||||||
|
var operator = this.shadowRoot.getElementById('operatorsmenu').value;
|
||||||
|
|
||||||
|
// Regular text field
|
||||||
|
if (!this.shadowRoot.getElementById('valuefield').hidden)
|
||||||
|
{
|
||||||
|
var value = this.shadowRoot.getElementById('valuefield').value;
|
||||||
|
|
||||||
|
// Convert datetimes to UTC before saving
|
||||||
|
switch (condition) {
|
||||||
|
case 'accessDate':
|
||||||
|
case 'dateAdded':
|
||||||
|
case 'dateModified':
|
||||||
|
if (Zotero.Date.isSQLDateTime(value)) {
|
||||||
|
var value = Zotero.Date.dateToSQL(Zotero.Date.sqlToDate(value), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append mode to condition
|
||||||
|
if (this.shadowRoot.getElementById('valuefield').mode){
|
||||||
|
condition += '/' + this.shadowRoot.getElementById('valuefield').mode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// isInTheLast operator
|
||||||
|
else if (!this.shadowRoot.getElementById('value-date-age').hidden)
|
||||||
|
{
|
||||||
|
var value = this.shadowRoot.getElementById('value-date-age').value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle special C1234 and S5678 form for
|
||||||
|
// collections and searches
|
||||||
|
else if (condition == 'collection') {
|
||||||
|
var letter = this.shadowRoot.getElementById('valuemenu').value.substr(0,1);
|
||||||
|
if (letter=='C')
|
||||||
|
{
|
||||||
|
condition = 'collection';
|
||||||
|
}
|
||||||
|
else if (letter=='S')
|
||||||
|
{
|
||||||
|
condition = 'savedSearch';
|
||||||
|
}
|
||||||
|
var value = this.shadowRoot.getElementById('valuemenu').value.substr(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Regular drop-down menu
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var value = this.shadowRoot.getElementById('valuemenu').value;
|
||||||
|
}
|
||||||
|
this.parent.search.updateCondition(this.conditionID, condition, operator, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateSubmenuCheckboxes(menu) {
|
||||||
|
for (let i = 0; i < menu.itemCount; i++) {
|
||||||
|
let item = menu.getItemAtIndex(i);
|
||||||
|
if (item.localName == 'menuitem') {
|
||||||
|
if (item.getAttribute('value') == this.selectedCondition) {
|
||||||
|
item.setAttribute('checked', true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
item.removeAttribute('checked');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.updateSubmenuCheckboxes(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
revealSelectedCondition(menu) {
|
||||||
|
if (!this.selectedCondition || this.isPrimaryCondition(this.selectedCondition)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!menu) {
|
||||||
|
menu = this.shadowRoot.getElementById('conditionsmenu');
|
||||||
|
}
|
||||||
|
for (let i = 0; i < menu.itemCount; i++) {
|
||||||
|
let item = menu.getItemAtIndex(i);
|
||||||
|
if (item.localName == 'menuitem') {
|
||||||
|
if (item.getAttribute('value') == this.selectedCondition) {
|
||||||
|
menu.open = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var opened = this.revealSelectedCondition(item);
|
||||||
|
if (opened) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
onLibraryChange() {
|
||||||
|
switch (this.selectedCondition) {
|
||||||
|
case 'collection':
|
||||||
|
this.onConditionSelected(this.selectedCondition, true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onRemoveClicked() {
|
||||||
|
if (this.parent){
|
||||||
|
this.parent.removeCondition(this.conditionID);
|
||||||
|
window.sizeToContent()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onAddClicked() {
|
||||||
|
if (this.parent){
|
||||||
|
let ref = this.parent.search.getCondition(
|
||||||
|
this.parent.search.addCondition(
|
||||||
|
this.shadowRoot.getElementById('conditionsmenu').getAttribute('data-value'),
|
||||||
|
this.shadowRoot.getElementById('operatorsmenu').value,
|
||||||
|
""
|
||||||
|
)
|
||||||
|
)
|
||||||
|
this.parent.addCondition(ref);
|
||||||
|
window.sizeToContent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
disableRemoveButton() {
|
||||||
|
var button = this.shadowRoot.getElementById("remove");
|
||||||
|
button.setAttribute('disabled', true);
|
||||||
|
button.removeAttribute('onclick');
|
||||||
|
}
|
||||||
|
|
||||||
|
enableRemoveButton() {
|
||||||
|
var button = this.shadowRoot.getElementById("remove");
|
||||||
|
button.setAttribute('disabled', false);
|
||||||
|
button.setAttribute('onclick', "this.getRootNode().host.onRemoveClicked(event)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
customElements.define("zoterosearchcondition", ZoteroSearchCondition);
|
||||||
|
|
||||||
|
class ZoteroSearchTextbox extends SearchElementBase {
|
||||||
|
content = MozXULElement.parseXULToFragment(`
|
||||||
|
<xul:stack
|
||||||
|
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||||
|
xmlns:html="http://www.w3.org/1999/xhtml"
|
||||||
|
flex="1">
|
||||||
|
<html:input id="search-textbox"
|
||||||
|
is="shadow-autocomplete-input"
|
||||||
|
autocompletesearch="zotero"
|
||||||
|
autocompletepopup="search-autocomplete-popup"
|
||||||
|
timeout="250"
|
||||||
|
type="search"/>
|
||||||
|
|
||||||
|
<xul:toolbarbutton
|
||||||
|
id="textbox-button"
|
||||||
|
type="menu">
|
||||||
|
<dropmarker type="menu" class="toolbarbutton-menu-dropmarker"/>
|
||||||
|
<xul:menupopup id="textbox-fulltext-menu">
|
||||||
|
<xul:menuitem type="radio" label="&zotero.search.textModes.phrase;"/>
|
||||||
|
<xul:menuitem type="radio" label="&zotero.search.textModes.phraseBinary;"/>
|
||||||
|
<xul:menuitem type="radio" label="&zotero.search.textModes.regexp;"/>
|
||||||
|
<xul:menuitem type="radio" label="&zotero.search.textModes.regexpCS;"/>
|
||||||
|
</xul:menupopup>
|
||||||
|
</xul:toolbarbutton>
|
||||||
|
</xul:stack>
|
||||||
|
`, ['chrome://zotero/locale/zotero.dtd', 'chrome://zotero/locale/searchbox.dtd']);
|
||||||
|
|
||||||
|
get value() {
|
||||||
|
return this.shadowRoot.getElementById('search-textbox').value;
|
||||||
|
}
|
||||||
|
|
||||||
|
set value(val) {
|
||||||
|
this.shadowRoot.getElementById('search-textbox').value = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
get mode() {
|
||||||
|
if (this.getAttribute('hasOptions')!='true'){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var menu = this.shadowRoot.getElementById('textbox-fulltext-menu');
|
||||||
|
|
||||||
|
var selectedIndex = -1;
|
||||||
|
for (var i=0; i<menu.childNodes.length; i++){
|
||||||
|
if (menu.childNodes[i].getAttribute('checked')=='true'){
|
||||||
|
selectedIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (selectedIndex){
|
||||||
|
case 0:
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
return 'phraseBinary';
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
return 'regexp';
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
return 'regexpCS';
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error('Invalid search textbox popup');
|
||||||
|
}
|
||||||
|
|
||||||
|
update(condition, mode) {
|
||||||
|
var textbox = this.shadowRoot.getElementById('search-textbox');
|
||||||
|
var button = this.shadowRoot.getElementById('textbox-button');
|
||||||
|
|
||||||
|
switch (condition){
|
||||||
|
case 'fulltextContent':
|
||||||
|
var menu = this.shadowRoot.getElementById('textbox-fulltext-menu');
|
||||||
|
this.setAttribute('hasOptions', true);
|
||||||
|
button.setAttribute('hidden', false);
|
||||||
|
|
||||||
|
var selectedIndex = 0;
|
||||||
|
if (mode){
|
||||||
|
switch (mode){
|
||||||
|
case 'phrase':
|
||||||
|
selectedIndex = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'phraseBinary':
|
||||||
|
selectedIndex = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'regexp':
|
||||||
|
selectedIndex = 2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'regexpCS':
|
||||||
|
selectedIndex = 3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
menu.childNodes[selectedIndex].setAttribute('checked', true);
|
||||||
|
textbox.setAttribute('disableautocomplete', 'true');
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
this.setAttribute('hasOptions', false);
|
||||||
|
button.setAttribute('hidden', true);
|
||||||
|
|
||||||
|
// Set textbox to autocomplete mode
|
||||||
|
switch (condition)
|
||||||
|
{
|
||||||
|
// Skip autocomplete for these fields
|
||||||
|
case 'date':
|
||||||
|
case 'note':
|
||||||
|
case 'extra':
|
||||||
|
textbox.setAttribute('disableautocomplete', 'true');
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
textbox.setAttribute('disableautocomplete', 'false');
|
||||||
|
|
||||||
|
// TODO: Provide current libraryID
|
||||||
|
var autocompleteParams = {
|
||||||
|
fieldName: condition
|
||||||
|
};
|
||||||
|
switch (condition) {
|
||||||
|
case 'creator':
|
||||||
|
case 'author':
|
||||||
|
case 'bookAuthor':
|
||||||
|
case 'editor':
|
||||||
|
autocompleteParams.fieldMode = 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
textbox.setAttribute(
|
||||||
|
'autocompletesearchparam',
|
||||||
|
JSON.stringify(autocompleteParams)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
customElements.define("zoterosearchtextbox", ZoteroSearchTextbox);
|
||||||
|
|
||||||
|
class ZoteroSearchAgeField extends SearchElementBase {
|
||||||
|
content = MozXULElement.parseXULToFragment(`
|
||||||
|
<xul:hbox id="search-in-the-last" flex="1"
|
||||||
|
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||||
|
xmlns:html="http://www.w3.org/1999/xhtml">
|
||||||
|
<html:input id="input" style="-moz-box-flex: 1"/>
|
||||||
|
<xul:menulist id="age-list" native="true">
|
||||||
|
<xul:menupopup flex="1">
|
||||||
|
<xul:menuitem label="&zotero.search.date.units.days;" value="days" selected="true"/>
|
||||||
|
<xul:menuitem label="&zotero.search.date.units.months;" value="months"/>
|
||||||
|
<xul:menuitem label="&zotero.search.date.units.years;" value="years"/>
|
||||||
|
</xul:menupopup>
|
||||||
|
</xul:menulist>
|
||||||
|
</xul:hbox>
|
||||||
|
`, ['chrome://zotero/locale/zotero.dtd', 'chrome://zotero/locale/searchbox.dtd']);
|
||||||
|
|
||||||
|
get value() {
|
||||||
|
var input = this.shadowRoot.getElementById('input');
|
||||||
|
var menulist = this.shadowRoot.getElementById('age-list');
|
||||||
|
return input.value + ' '
|
||||||
|
+ menulist.firstChild.childNodes[menulist.selectedIndex].getAttribute('value');
|
||||||
|
}
|
||||||
|
|
||||||
|
set value(val) {
|
||||||
|
var input = this.shadowRoot.getElementById('input');
|
||||||
|
|
||||||
|
var [num, units] = val.split(' ');
|
||||||
|
input.setAttribute('value', num);
|
||||||
|
|
||||||
|
var menulist = this.shadowRoot.getElementById('age-list');
|
||||||
|
var menupopup = menulist.firstChild;
|
||||||
|
|
||||||
|
var selectThis = 0;
|
||||||
|
for (var i=0; i<menupopup.childNodes.length; i++){
|
||||||
|
if (menupopup.childNodes[i].value == units)
|
||||||
|
{
|
||||||
|
selectThis = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
menulist.selectedIndex = selectThis;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
customElements.define("zoterosearchagefield", ZoteroSearchAgeField);
|
||||||
|
}
|
|
@ -41,6 +41,8 @@ function doLoad()
|
||||||
searchBox.groups = io.dataIn.groups;
|
searchBox.groups = io.dataIn.groups;
|
||||||
searchBox.search = io.dataIn.search;
|
searchBox.search = io.dataIn.search;
|
||||||
document.getElementById('search-name').value = io.dataIn.name;
|
document.getElementById('search-name').value = io.dataIn.name;
|
||||||
|
|
||||||
|
document.addEventListener('dialogaccept', doAccept);
|
||||||
}
|
}
|
||||||
|
|
||||||
function doUnload()
|
function doUnload()
|
||||||
|
|
|
@ -5,25 +5,39 @@
|
||||||
|
|
||||||
<!DOCTYPE bindings SYSTEM "chrome://zotero/locale/searchbox.dtd">
|
<!DOCTYPE bindings SYSTEM "chrome://zotero/locale/searchbox.dtd">
|
||||||
|
|
||||||
<dialog
|
<window
|
||||||
id="zotero-search-dialog"
|
|
||||||
title="Search"
|
title="Search"
|
||||||
orient="vertical"
|
orient="vertical"
|
||||||
buttons="cancel,accept"
|
|
||||||
ondialogaccept="doAccept();"
|
|
||||||
onload="doLoad();"
|
onload="doLoad();"
|
||||||
onunload="doUnload();"
|
onunload="doUnload();"
|
||||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||||
|
xmlns:html="http://www.w3.org/1999/xhtml"
|
||||||
style="padding:2em">
|
style="padding:2em">
|
||||||
|
<dialog
|
||||||
|
id="zotero-search-dialog"
|
||||||
|
buttons="cancel,accept">
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||||
|
Services.scriptloader.loadSubScript("chrome://zotero/content/elements/zoteroSearch.js", this);
|
||||||
|
</script>
|
||||||
|
|
||||||
<script src="include.js"/>
|
<script src="include.js"/>
|
||||||
<script src="searchDialog.js"/>
|
<script src="searchDialog.js"/>
|
||||||
|
|
||||||
|
<popupset>
|
||||||
|
<panel is="autocomplete-richlistbox-popup"
|
||||||
|
id="search-autocomplete-popup"
|
||||||
|
type="autocomplete-richlistbox"
|
||||||
|
noautofocus="true"/>
|
||||||
|
</popupset>
|
||||||
|
|
||||||
<vbox id="zotero-search-box-container" flex="1">
|
<vbox id="zotero-search-box-container" flex="1">
|
||||||
<hbox align="center">
|
<hbox align="center">
|
||||||
<label value="&zotero.search.name;"/>
|
<label value="&zotero.search.name;"/>
|
||||||
<textbox id="search-name" width="275" maxlength="80"/>
|
<html:input id="search-name" type="text" width="275" maxlength="80"/>
|
||||||
</hbox>
|
</hbox>
|
||||||
<zoterosearch id="search-box" flex="1"/>
|
<zoterosearch id="search-box" flex="1"/>
|
||||||
</vbox>
|
</vbox>
|
||||||
</dialog>
|
</dialog>
|
||||||
|
</window>
|
|
@ -1124,7 +1124,7 @@ var ZoteroPane = new function()
|
||||||
);
|
);
|
||||||
|
|
||||||
var io = { dataIn: { search: s, name }, dataOut: null };
|
var io = { dataIn: { search: s, name }, dataOut: null };
|
||||||
window.openDialog('chrome://zotero/content/searchDialog.xul','','chrome,modal',io);
|
window.openDialog('chrome://zotero/content/searchDialog.xhtml','','chrome,modal',io);
|
||||||
if (!io.dataOut) {
|
if (!io.dataOut) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1155,7 +1155,7 @@ var ZoteroPane = new function()
|
||||||
s.addCondition('title', 'contains', '');
|
s.addCondition('title', 'contains', '');
|
||||||
|
|
||||||
var io = {dataIn: {search: s}, dataOut: null};
|
var io = {dataIn: {search: s}, dataOut: null};
|
||||||
window.openDialog('chrome://zotero/content/advancedSearch.xul', '', 'chrome,dialog=no,centerscreen', io);
|
window.openDialog('chrome://zotero/content/advancedSearch.xhtml', '', 'chrome,dialog=no,centerscreen', io);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.initItemsTree = async function () {
|
this.initItemsTree = async function () {
|
||||||
|
@ -2161,7 +2161,7 @@ var ZoteroPane = new function()
|
||||||
},
|
},
|
||||||
dataOut: null
|
dataOut: null
|
||||||
};
|
};
|
||||||
window.openDialog('chrome://zotero/content/searchDialog.xul','','chrome,modal',io);
|
window.openDialog('chrome://zotero/content/searchDialog.xhtml','','chrome,modal',io);
|
||||||
if (io.dataOut) {
|
if (io.dataOut) {
|
||||||
row.ref.fromJSON(io.dataOut.json);
|
row.ref.fromJSON(io.dataOut.json);
|
||||||
yield row.ref.saveTx();
|
yield row.ref.saveTx();
|
||||||
|
|
|
@ -1,69 +0,0 @@
|
||||||
#search-box
|
|
||||||
{
|
|
||||||
width: 60em;
|
|
||||||
}
|
|
||||||
|
|
||||||
#search-box > hbox {
|
|
||||||
margin-left: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
groupbox {
|
|
||||||
margin-top: 0;
|
|
||||||
padding-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
caption {
|
|
||||||
font: inherit;
|
|
||||||
padding-left: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
label:first-child, checkbox:first-child {
|
|
||||||
margin-left: 0 !important;
|
|
||||||
padding-left: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
checkbox {
|
|
||||||
margin-right: .5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
#search-condition menulist[id="operatorsmenu"]
|
|
||||||
{
|
|
||||||
width: 15em;
|
|
||||||
}
|
|
||||||
|
|
||||||
#condition-tooltips tooltip
|
|
||||||
{
|
|
||||||
background: red !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
#condition-tooltips row > label
|
|
||||||
{
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
#search-textbox toolbarbutton
|
|
||||||
{
|
|
||||||
padding: 0;
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
|
|
||||||
#search-textbox:not([hasOptions=true]) toolbarbutton
|
|
||||||
{
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#search-textbox .toolbarbutton-text
|
|
||||||
{
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#search-textbox .toolbarbutton-menu-dropmarker
|
|
||||||
{
|
|
||||||
padding: 0 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#search-in-the-last textbox
|
|
||||||
{
|
|
||||||
min-width: 3em;
|
|
||||||
}
|
|
|
@ -60,28 +60,6 @@ relatedbox
|
||||||
-moz-user-focus: ignore;
|
-moz-user-focus: ignore;
|
||||||
}
|
}
|
||||||
|
|
||||||
zoterosearch
|
|
||||||
{
|
|
||||||
-moz-binding: url('chrome://zotero/content/bindings/zoterosearch.xml#search-box');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
zoterosearchcondition
|
|
||||||
{
|
|
||||||
-moz-binding: url('chrome://zotero/content/bindings/zoterosearch.xml#search-condition');
|
|
||||||
}
|
|
||||||
|
|
||||||
zoterosearchtextbox
|
|
||||||
{
|
|
||||||
-moz-binding: url('chrome://zotero/content/bindings/zoterosearch.xml#search-textbox');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
zoterosearchagefield
|
|
||||||
{
|
|
||||||
-moz-binding: url('chrome://zotero/content/bindings/zoterosearch.xml#search-in-the-last');
|
|
||||||
}
|
|
||||||
|
|
||||||
zoteromergegroup {
|
zoteromergegroup {
|
||||||
-moz-binding: url('chrome://zotero/content/bindings/merge.xml#merge-group');
|
-moz-binding: url('chrome://zotero/content/bindings/merge.xml#merge-group');
|
||||||
}
|
}
|
||||||
|
|
2
scss/_zoteroSearch.scss
Normal file
2
scss/_zoteroSearch.scss
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
@import "components/zoteroSearch";
|
||||||
|
@import "components/clicky";
|
55
scss/components/_zoteroSearch.scss
Normal file
55
scss/components/_zoteroSearch.scss
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
#search-box > hbox, #search-box > groupbox {
|
||||||
|
margin-left: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
groupbox {
|
||||||
|
margin-top: 0;
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
caption {
|
||||||
|
font: inherit;
|
||||||
|
padding-left: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
label:first-child:not(tooltip label), checkbox:first-child {
|
||||||
|
margin-left: 0 !important;
|
||||||
|
padding-left: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
checkbox {
|
||||||
|
margin-right: .5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#operatorsmenu {
|
||||||
|
width: 15em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#condition-tooltips tooltip
|
||||||
|
{
|
||||||
|
background: red !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#condition-tooltips hbox > label
|
||||||
|
{
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbarbutton-text
|
||||||
|
{
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#textbox-button {
|
||||||
|
cursor: default;
|
||||||
|
appearance: none;
|
||||||
|
justify-self: end;
|
||||||
|
margin-inline-end: 8px;
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#search-in-the-last input
|
||||||
|
{
|
||||||
|
min-width: 3em;
|
||||||
|
}
|
1
scss/zoteroSearch-mac.scss
Normal file
1
scss/zoteroSearch-mac.scss
Normal file
|
@ -0,0 +1 @@
|
||||||
|
@import "zoteroSearch";
|
1
scss/zoteroSearch-unix.scss
Normal file
1
scss/zoteroSearch-unix.scss
Normal file
|
@ -0,0 +1 @@
|
||||||
|
@import "zoteroSearch";
|
1
scss/zoteroSearch-win.scss
Normal file
1
scss/zoteroSearch-win.scss
Normal file
|
@ -0,0 +1 @@
|
||||||
|
@import "zoteroSearch";
|
|
@ -19,7 +19,7 @@ describe("Advanced Search", function () {
|
||||||
it("should perform a search", function* () {
|
it("should perform a search", function* () {
|
||||||
var item = yield createDataObject('item', { setTitle: true });
|
var item = yield createDataObject('item', { setTitle: true });
|
||||||
|
|
||||||
var promise = waitForWindow('chrome://zotero/content/advancedSearch.xul');
|
var promise = waitForWindow('chrome://zotero/content/advancedSearch.xhtml');
|
||||||
zp.openAdvancedSearchWindow();
|
zp.openAdvancedSearchWindow();
|
||||||
var searchWin = yield promise;
|
var searchWin = yield promise;
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ describe("Advanced Search", function () {
|
||||||
var searchWin, searchBox, conditions;
|
var searchWin, searchBox, conditions;
|
||||||
|
|
||||||
before(function* () {
|
before(function* () {
|
||||||
var promise = waitForWindow('chrome://zotero/content/advancedSearch.xul');
|
var promise = waitForWindow('chrome://zotero/content/advancedSearch.xhtml');
|
||||||
zp.openAdvancedSearchWindow();
|
zp.openAdvancedSearchWindow();
|
||||||
searchWin = yield promise;
|
searchWin = yield promise;
|
||||||
searchBox = searchWin.document.getElementById('zotero-search-box');
|
searchBox = searchWin.document.getElementById('zotero-search-box');
|
||||||
|
|
|
@ -73,7 +73,7 @@ describe("ZoteroPane", function() {
|
||||||
// TODO: Test changing a condition
|
// TODO: Test changing a condition
|
||||||
function (dialog) {},
|
function (dialog) {},
|
||||||
'accept',
|
'accept',
|
||||||
'chrome://zotero/content/searchDialog.xul'
|
'chrome://zotero/content/searchDialog.xhtml'
|
||||||
);
|
);
|
||||||
var id = yield zp.newSearch();
|
var id = yield zp.newSearch();
|
||||||
yield promise;
|
yield promise;
|
||||||
|
@ -86,7 +86,7 @@ describe("ZoteroPane", function() {
|
||||||
var promise = waitForDialog(
|
var promise = waitForDialog(
|
||||||
function (dialog) {},
|
function (dialog) {},
|
||||||
'cancel',
|
'cancel',
|
||||||
'chrome://zotero/content/searchDialog.xul'
|
'chrome://zotero/content/searchDialog.xhtml'
|
||||||
);
|
);
|
||||||
var id = yield zp.newSearch();
|
var id = yield zp.newSearch();
|
||||||
yield promise;
|
yield promise;
|
||||||
|
@ -766,7 +766,7 @@ describe("ZoteroPane", function() {
|
||||||
describe("#editSelectedCollection()", function () {
|
describe("#editSelectedCollection()", function () {
|
||||||
it("should edit a saved search", function* () {
|
it("should edit a saved search", function* () {
|
||||||
var search = yield createDataObject('search');
|
var search = yield createDataObject('search');
|
||||||
var promise = waitForWindow('chrome://zotero/content/searchDialog.xul', function (win) {
|
var promise = waitForWindow('chrome://zotero/content/searchDialog.xhtml', function (win) {
|
||||||
let searchBox = win.document.getElementById('search-box');
|
let searchBox = win.document.getElementById('search-box');
|
||||||
var c = searchBox.search.getCondition(
|
var c = searchBox.search.getCondition(
|
||||||
searchBox.search.addCondition("title", "contains", "foo")
|
searchBox.search.addCondition("title", "contains", "foo")
|
||||||
|
@ -783,7 +783,7 @@ describe("ZoteroPane", function() {
|
||||||
it("should edit a saved search in a group", function* () {
|
it("should edit a saved search in a group", function* () {
|
||||||
var group = yield getGroup();
|
var group = yield getGroup();
|
||||||
var search = yield createDataObject('search', { libraryID: group.libraryID });
|
var search = yield createDataObject('search', { libraryID: group.libraryID });
|
||||||
var promise = waitForWindow('chrome://zotero/content/searchDialog.xul', function (win) {
|
var promise = waitForWindow('chrome://zotero/content/searchDialog.xhtml', function (win) {
|
||||||
let searchBox = win.document.getElementById('search-box');
|
let searchBox = win.document.getElementById('search-box');
|
||||||
var c = searchBox.search.getCondition(
|
var c = searchBox.search.getCondition(
|
||||||
searchBox.search.addCondition("title", "contains", "foo")
|
searchBox.search.addCondition("title", "contains", "foo")
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue