www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | Submodules | README | LICENSE

commit 8d5f1e62b695672953609b2b59bde3ef5ba8a2b2
parent d7990b0e0354bf054eb88e248ca21bb3ac608add
Author: David Norton <david@nortoncrew.com>
Date:   Wed,  9 Aug 2006 11:43:33 +0000

Closes #47, advanced search
Closes #152, Saved Searches (interface layer)

For now, advanced search IS a saved search.

There are still bugs. The 'search' icon is ugly. I wanted to get it out there, however.

Diffstat:
Achrome/chromeFiles/content/scholar/bindings/scholarsearch.xml | 232+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mchrome/chromeFiles/content/scholar/collectionTreeView.js | 76++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
Mchrome/chromeFiles/content/scholar/overlay.js | 39++++++++++++++++++++++++++++++++-------
Mchrome/chromeFiles/content/scholar/overlay.xul | 1+
Achrome/chromeFiles/content/scholar/searchDialog.js | 45+++++++++++++++++++++++++++++++++++++++++++++
Achrome/chromeFiles/content/scholar/searchDialog.xul | 44++++++++++++++++++++++++++++++++++++++++++++
Mchrome/chromeFiles/skin/default/scholar/scholar.css | 10++++++++++
Achrome/chromeFiles/skin/default/scholar/treesource-search.png | 0
8 files changed, 418 insertions(+), 29 deletions(-)

diff --git a/chrome/chromeFiles/content/scholar/bindings/scholarsearch.xml b/chrome/chromeFiles/content/scholar/bindings/scholarsearch.xml @@ -0,0 +1,231 @@ +<?xml version="1.0"?> +<!-- + Scholar + Copyright (C) 2006 Center for History and New Media, George Mason University, Fairfax, VA + http://chnm.gmu.edu/ + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +--> +<bindings xmlns="http://www.mozilla.org/xbl" + xmlns:xbl="http://www.mozilla.org/xbl" + xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <binding id="search-box"> + <implementation> + <field name="searchRef"/> + <property name="search" onget="return this.searchRef;"> + <setter> + <![CDATA[ + this.searchRef = val; + + var conditionsBox = this.id('conditions'); + while(conditionsBox.hasChildNodes()) + conditionsBox.removeChild(conditionsBox.firstChild); + + var conditions = this.search.getSearchConditions(); + if(conditions.length) + { + for(var i = 0, len = conditions.length; i<len; i++) + { + this.addCondition(i); + } + } + ]]> + </setter> + </property> + <method name="onAddClicked"> + <body> + <![CDATA[ + this.search.addCondition("itemType","is","1"); + this.addCondition(); + ]]> + </body> + </method> + <method name="addCondition"> + <body> + <![CDATA[ + var conditionsBox = this.id('conditions'); + var condition = document.createElement('searchcondition'); + condition.setAttribute('flex','1'); + + conditionsBox.appendChild(condition); + + condition.initWithParentAndConditionID(this, conditionsBox.childNodes.length-1); + + conditionsBox.childNodes[0].id('remove').hidden = (conditionsBox.childNodes.length == 1); + ]]> + </body> + </method> + <method name="removeCondition"> + <parameter name="idx"/> + <body> + <![CDATA[ + var conditionsBox = this.id('conditions'); + this.search.removeCondition(idx); + conditionsBox.removeChild(conditionsBox.childNodes[idx]); + for(var i = idx, len=conditionsBox.childNodes.length; i < len; i++) + conditionsBox.childNodes[i].conditionID = i; + + conditionsBox.childNodes[0].id('remove').hidden = (conditionsBox.childNodes.length == 1); + ]]> + </body> + </method> + <method name="id"> + <parameter name="id"/> + <body> + <![CDATA[ + return document.getAnonymousNodes(this)[0].getElementsByAttribute('id',id)[0]; + ]]> + </body> + </method> + </implementation> + <handlers> + </handlers> + <content> + <xul:groupbox xbl:inherits="flex"> + <xul:caption align="center"> + <xul:label value="Match"/> + <xul:menulist> + <xul:menupopup> + <xul:menuitem label="Any" value="any"/> + <xul:menuitem label="All" value="all"/> + </xul:menupopup> + </xul:menulist> + <xul:label value="of the following:"/> + </xul:caption> + <xul:vbox id="conditions" style="overflow: auto;"/> + </xul:groupbox> + </content> + </binding> + + <binding id="search-condition"> + <implementation> + <constructor> + <![CDATA[ + this.operators = new Array('is', 'isNot', 'contains', 'doesNotContain'); + var conditionsList = this.id('conditionsmenu'); + conditionsList.removeAllItems; + + var conditions = Scholar.SearchConditions.getStandardConditions(); + + for(var i=0, len=conditions.length; i<len; i++) + conditionsList.appendItem(conditions[i]['name'], conditions[i]['name']); + conditionsList.selectedIndex = 0; + ]]> + </constructor> + <method name="onConditionSelected"> + <body> + <![CDATA[ + var operatorsList = this.id('operatorsmenu'); + + var condition = Scholar.SearchConditions.get(this.id('conditionsmenu').value); + var operators = condition['operators']; + + var selectThis; + for(var i = 0, len = operatorsList.firstChild.childNodes.length; i < len; i++) + { + var hidden = !operators[operatorsList.firstChild.childNodes[i].value]; + operatorsList.firstChild.childNodes[i].setAttribute('hidden', hidden); + if(selectThis == null && !hidden) + selectThis = i; + } + + operatorsList.selectedIndex = selectThis; + ]]> + </body> + </method> + <field name="operators"/> + <field name="dontupdate"/> + <field name="parent"/> + <field name="conditionID"/> + <method name="initWithParentAndConditionID"> + <parameter name="parent"/> + <parameter name="id"/> + <body> + <![CDATA[ + this.parent = parent; + this.conditionID = id; + + if(this.parent.search) + { + this.dontupdate = true; //so that the search doesn't get updated while we are creating controls. + var condition = this.parent.search.getSearchCondition(this.conditionID); + + this.id('conditionsmenu').value = condition['condition']; + this.id('operatorsmenu').value = condition['operator']; + this.id('valuefield').value = condition['value']; + + this.dontupdate = false; + } + ]]> + </body> + </method> + <method name="updateSearch"> + <body> + <![CDATA[ + if(this.parent && this.parent.search && !this.dontupdate) + { + var condition = this.id('conditionsmenu').value; + var operator = this.id('operatorsmenu').value; + var value = this.id('valuefield').value; + this.parent.search.updateCondition(this.conditionID, condition, operator, value); + } + ]]> + </body> + </method> + <method name="onRemoveClicked"> + <body> + <![CDATA[ + if(this.parent) + this.parent.removeCondition(this.conditionID); + ]]> + </body> + </method> + <method name="onAddClicked"> + <body> + <![CDATA[ + if(this.parent) + this.parent.onAddClicked(); + ]]> + </body> + </method> + <method name="id"> + <parameter name="id"/> + <body> + <![CDATA[ + return document.getAnonymousNodes(this)[0].getElementsByAttribute('id',id)[0]; + ]]> + </body> + </method> + </implementation> + <content> + <xul:hbox xbl:inherits="flex"> + <xul:menulist id="conditionsmenu" oncommand="this.parentNode.parentNode.onConditionSelected();"> + <xul:menupopup/> + </xul:menulist> + <xul:menulist id="operatorsmenu" oncommand="this.parentNode.parentNode.updateSearch();"> + <xul:menupopup> + <xul:menuitem label="is" value="is"/> + <xul:menuitem label="isNot" value="isNot"/> + <xul:menuitem label="contains" value="contains"/> + <xul:menuitem label="doesNotContain" value="doesNotContain"/> + </xul:menupopup> + </xul:menulist> + <xul:textbox id="valuefield" type="timed" timeout="1000" flex="1" oncommand="this.parentNode.parentNode.updateSearch();"/> + <xul:toolbarbutton id="remove" class="clicky" label="-" oncommand="this.parentNode.parentNode.onRemoveClicked();"/> + <xul:toolbarbutton id="add" class="clicky" label="+" oncommand="this.parentNode.parentNode.onAddClicked();"/> + </xul:hbox> + </content> + </binding> +</bindings> +\ No newline at end of file diff --git a/chrome/chromeFiles/content/scholar/collectionTreeView.js b/chrome/chromeFiles/content/scholar/collectionTreeView.js @@ -61,12 +61,45 @@ Scholar.CollectionTreeView.prototype.refresh = function() var newRows = Scholar.getCollections(); for(var i = 0; i < newRows.length; i++) - this._showItem(new Scholar.ItemGroup('collection',newRows[i]), 0, this._dataItems.length); //item ref, level, beforeRow - + this._showItem(new Scholar.ItemGroup('collection',newRows[i]), 0, this._dataItems.length); //itemgroup ref, level, beforeRow + + var savedSearches = Scholar.Searches.getAll(); + for(var i = 0; i < savedSearches.length; i++) + { + this._showItem(new Scholar.ItemGroup('search',savedSearches[i]), 0, this._dataItems.length); //itemgroup ref, level, beforeRow + Scholar.debug(i); + } + this._refreshHashMap(); } /* + * Redisplay everything + */ +Scholar.CollectionTreeView.prototype.reload = function() +{ + var openCollections = new Array(); + + for(var i = 0; i < this.rowCount; i++) + if(this.isContainer(i) && this.isContainerOpen(i)) + openCollections.push(this._getItemAtRow(i).ref.getID()); + + var oldCount = this.rowCount; + this._treebox.beginUpdateBatch(); + this.refresh(); + this._treebox.rowCountChanged(0,this.rowCount - oldCount); + + for(var i = 0; i < openCollections.length; i++) + { + var row = this._collectionRowMap[openCollections[i]]; + if(row != null) + this.toggleOpenState(row); + } + this._treebox.invalidate(); + this._treebox.endUpdateBatch(); +} + +/* * Called by Scholar.Notifier on any changes to collections in the data layer */ Scholar.CollectionTreeView.prototype.notify = function(action, type, ids) @@ -101,25 +134,7 @@ Scholar.CollectionTreeView.prototype.notify = function(action, type, ids) } else if(action == 'move') { - var openCollections = new Array(); - - for(var i = 0; i < this.rowCount; i++) - if(this.isContainer(i) && this.isContainerOpen(i)) - openCollections.push(this._getItemAtRow(i).ref.getID()); - - var oldCount = this.rowCount; - this._treebox.beginUpdateBatch(); - this.refresh(); - this._treebox.rowCountChanged(0,this.rowCount - oldCount); - - for(var i = 0; i < openCollections.length; i++) - { - var row = this._collectionRowMap[openCollections[i]]; - if(row != null) - this.toggleOpenState(row); - } - this._treebox.invalidate(); - this._treebox.endUpdateBatch(); + this.reload(); } else if(action == 'modify') { @@ -291,7 +306,11 @@ Scholar.CollectionTreeView.prototype.deleteSelection = function() for (var i=0; i<rows.length; i++) { //erase collection from DB: - this._getItemAtRow(rows[i]-i).ref.erase(); + var group = this._getItemAtRow(rows[i]-i); + if(group.isCollection()) + group.ref.erase(); + else if(group.isSearch()) + Scholar.Searches.erase(group.ref['id']); } this._treebox.endUpdateBatch(); @@ -541,12 +560,19 @@ Scholar.ItemGroup.prototype.isCollection = function() return this.type == 'collection'; } +Scholar.ItemGroup.prototype.isSearch = function() +{ + return this.type == 'search'; +} + Scholar.ItemGroup.prototype.getName = function() { if(this.isCollection()) return this.ref.getName(); else if(this.isLibrary()) return Scholar.getString('pane.collections.library'); + else if(this.isSearch()) + return this.ref['name']; else return ""; } @@ -563,6 +589,12 @@ Scholar.ItemGroup.prototype.getChildItems = function() return Scholar.getItems(this.ref.getID()); else if(this.isLibrary()) return Scholar.getItems(); + else if(this.isSearch()) + { + var s = new Scholar.Search(); + s.load(this.ref['id']); + return Scholar.Items.get(s.search()); + } else return null; } diff --git a/chrome/chromeFiles/content/scholar/overlay.js b/chrome/chromeFiles/content/scholar/overlay.js @@ -33,6 +33,7 @@ var ScholarPane = new function() this.fullScreen = fullScreen; this.newItem = newItem; this.newCollection = newCollection; + this.newSearch = newSearch; this.onCollectionSelected = onCollectionSelected; this.itemSelected = itemSelected; this.deleteSelectedItem = deleteSelectedItem; @@ -167,6 +168,18 @@ var ScholarPane = new function() Scholar.Collections.add(Scholar.getString('pane.collections.untitled')); } + function newSearch() + { + var s = new Scholar.Search(); + s.addCondition('title','contains',''); + + var io = {dataIn: {search: s, name: 'Untitled'}, dataOut: null}; + window.openDialog('chrome://scholar/content/searchDialog.xul','','chrome,modal',io); + + if(io.dataOut) + getCollectionsView().reload(); + } + function onCollectionSelected() { if(itemsView) @@ -177,12 +190,12 @@ var ScholarPane = new function() if(collectionsView.selection.count == 1 && collectionsView.selection.currentIndex != -1) { - var collection = collectionsView._getItemAtRow(collectionsView.selection.currentIndex); - collection.setSearch(''); + var itemgroup = collectionsView._getItemAtRow(collectionsView.selection.currentIndex); + itemgroup.setSearch(''); - itemsView = new Scholar.ItemTreeView(collection); + itemsView = new Scholar.ItemTreeView(itemgroup); document.getElementById('items-tree').view = itemsView; - document.getElementById('tb-collection-rename').disabled = collection.isLibrary(); + document.getElementById('tb-collection-rename').disabled = itemgroup.isLibrary(); itemsView.selection.clearSelection(); } else @@ -275,9 +288,21 @@ var ScholarPane = new function() { var collection = collectionsView._getItemAtRow(collectionsView.selection.currentIndex); - var newName = prompt(Scholar.getString('pane.collections.rename'),collection.getName()); - if(newName) - collection.ref.rename(newName); + if(collection.isCollection()) + { + var newName = prompt(Scholar.getString('pane.collections.rename'),collection.getName()); + if(newName) + collection.ref.rename(newName); + } + else + { + var s = new Scholar.Search(); + s.load(collection.ref['id']); + var io = {dataIn: {search: s, name: collection.getName()}, dataOut: null}; + window.openDialog('chrome://scholar/content/searchDialog.xul','','chrome,modal',io); + if(io.dataOut) + onCollectionSelected(); + } } } diff --git a/chrome/chromeFiles/content/scholar/overlay.xul b/chrome/chromeFiles/content/scholar/overlay.xul @@ -70,6 +70,7 @@ <toolbar> <toolbarbutton id="tb-collection-add" tooltiptext="&toolbar.newCollection.label;" command="cmd_scholar_newCollection"/> <toolbarbutton id="tb-collection-rename" tooltiptext="&toolbar.renameCollection.label;" oncommand="ScholarPane.renameSelectedCollection();" disabled="true"/> + <toolbarbutton id="tb-collection-addsearch" label="Add Search" oncommand="ScholarPane.newSearch();"/> <spacer flex="1"/> <toolbarbutton id="tb-collection-menu" type="menu"> <menupopup> diff --git a/chrome/chromeFiles/content/scholar/searchDialog.js b/chrome/chromeFiles/content/scholar/searchDialog.js @@ -0,0 +1,44 @@ +/* + Scholar + Copyright (C) 2006 Center for History and New Media, George Mason University, Fairfax, VA + http://chnm.gmu.edu/ + http://chnm.gmu.edu/ + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +var itemsView; +var collectionsView; +var io; + +function doLoad() +{ + io = window.arguments[0]; + + document.getElementById('search-box').search = io.dataIn.search; + document.getElementById('search-name').value = io.dataIn.name; +} + +function doUnload() +{ + +} + +function doAccept() +{ + document.getElementById('search-box').search.setName(document.getElementById('search-name').value); + document.getElementById('search-box').search.save(); + io.dataOut = true; +} +\ No newline at end of file diff --git a/chrome/chromeFiles/content/scholar/searchDialog.xul b/chrome/chromeFiles/content/scholar/searchDialog.xul @@ -0,0 +1,44 @@ +<?xml version="1.0"?> +<!-- + Scholar + Copyright (C) 2006 Center for History and New Media, George Mason University, Fairfax, VA + http://chnm.gmu.edu/ + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +--> +<?xml-stylesheet href="chrome://global/skin/" type="text/css"?> +<?xml-stylesheet href="chrome://scholar/skin/scholar.css" type="text/css"?> +<?xml-stylesheet href="chrome://scholar/skin/overlay.css" type="text/css"?> +<!DOCTYPE window SYSTEM "chrome://scholar/locale/scholar.dtd"> + +<dialog + id="scholar-search-dialog" + title="Search" + orient="vertical" + width="600" flex="1" + persist="width height screenX screenY" + buttons="cancel,accept" + ondialogaccept="doAccept();" + onload="doLoad();" + onunload="doUnload();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + style="padding:2em"> + + <script src="include.js"/> + <script src="searchDialog.js"/> + + <hbox align="center"><label value="Name:"/><textbox id="search-name" flex="1"/></hbox> + <scholarsearch id="search-box" flex="1"/> +</dialog> diff --git a/chrome/chromeFiles/skin/default/scholar/scholar.css b/chrome/chromeFiles/skin/default/scholar/scholar.css @@ -63,6 +63,16 @@ seealsobox -moz-binding: url('chrome://scholar/content/bindings/relatedbox.xml#seealso-box'); } +scholarsearch +{ + -moz-binding: url('chrome://scholar/content/bindings/scholarsearch.xml#search-box'); +} + +searchcondition +{ + -moz-binding: url('chrome://scholar/content/bindings/scholarsearch.xml#search-condition'); +} + .clicky { -moz-border-radius: 6px; diff --git a/chrome/chromeFiles/skin/default/scholar/treesource-search.png b/chrome/chromeFiles/skin/default/scholar/treesource-search.png Binary files differ.