[MERGE] new searchview

fp orders

bzr revid: xmo@openerp.com-20120406120250-dlwt0kvt0y1e2snr
This commit is contained in:
Xavier Morel 2012-04-06 14:02:50 +02:00
commit e7e7548869
20 changed files with 6282 additions and 632 deletions

View File

@ -10,3 +10,5 @@ RE:^include/
RE:^share/
RE:^man/
RE:^lib/
RE:^doc/_build/

View File

@ -35,6 +35,21 @@
"static/lib/qweb/qweb2.js",
"static/lib/underscore/underscore.js",
"static/lib/underscore/underscore.string.js",
"static/lib/backbone/backbone.js",
"static/lib/visualsearch/lib/js/visualsearch.js",
"static/lib/visualsearch/lib/js/utils/backbone_extensions.js",
"static/lib/visualsearch/lib/js/utils/hotkeys.js",
"static/lib/visualsearch/lib/js/utils/inflector.js",
"static/lib/visualsearch/lib/js/utils/jquery_extensions.js",
"static/lib/visualsearch/lib/js/utils/search_parser.js",
"static/lib/visualsearch/lib/js/models/search_facets.js",
"static/lib/visualsearch/lib/js/models/search_query.js",
"static/lib/visualsearch/lib/js/templates/templates.js",
"static/lib/visualsearch/lib/js/views/search_facet.js",
"static/lib/visualsearch/lib/js/views/search_input.js",
"static/lib/visualsearch/lib/js/views/search_box.js",
"static/lib/labjs/LAB.src.js",
"static/lib/py.js/lib/py.js",
"static/lib/novajs/src/nova.js",
@ -61,6 +76,9 @@
"static/lib/jquery.ui.timepicker/css/jquery-ui-timepicker-addon.css",
"static/lib/jquery.ui.notify/css/ui.notify.css",
"static/lib/jquery.tipsy/tipsy.css",
"static/lib/visualsearch/lib/css/reset.css",
"static/lib/visualsearch/lib/css/workspace.css",
"static/lib/visualsearch/lib/css/icons.css",
"static/src/css/base_old.css",
"static/src/css/base.css",
"static/src/css/data_export.css",

View File

@ -79,7 +79,7 @@ def concat_files(file_list, reader=None, intersperse=""):
if reader is None:
def reader(f):
with open(f) as fp:
with open(f, 'rb') as fp:
return fp.read()
files_content = []
@ -261,8 +261,8 @@ class WebClient(openerpweb.Controller):
def reader(f):
"""read the a css file and absolutify all relative uris"""
with open(f) as fp:
data = fp.read()
with open(f, 'rb') as fp:
data = fp.read().decode('utf-8')
path = file_map[f]
# convert FS path into web path
@ -279,7 +279,7 @@ class WebClient(openerpweb.Controller):
r"""url(\1%s/""" % (web_dir,),
data,
)
return data
return data.encode('utf-8')
content, checksum = concat_files((f[0] for f in files), reader)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,22 @@
Copyright (c) 2011 Samuel Clay, @samuelclay, DocumentCloud
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,16 @@
__ ___ _ _____ _ _
\ \ / (_) | |/ ____| | | (_)
\ \ / / _ ___ _ _ __ _| | (___ ___ __ _ _ __ ___| |__ _ ___
\ \/ / | / __| | | |/ _` | |\___ \ / _ \/ _` | '__/ __| '_ \ | / __|
\ / | \__ \ |_| | (_| | |____) | __/ (_| | | | (__| | | |_| \__ \
\/ |_|___/\__,_|\__,_|_|_____/ \___|\__,_|_| \___|_| |_(_) |___/
_/ |
|__/
VisualSearch.js enhances ordinary search boxes with the ability to autocomplete
faceted search queries. Specify the facets for completion, along with the
completable values for any facet. You can retrieve the search query as a
structured object, so you don't have to parse the query string yourself.
For documentation, pre-packed downloads, demos, and tests, see:
http://documentcloud.github.com/visualsearch

View File

@ -0,0 +1,37 @@
require 'rubygems'
require 'jammit'
require 'fileutils'
desc "Use Jammit to compile the multiple versions of Visual Search"
task :build do
$VS_MIN = false
Jammit.package!({
:config_path => "assets.yml",
:output_folder => "build"
})
$VS_MIN = true
Jammit.package!({
:config_path => "assets.yml",
:output_folder => "build-min"
})
# Move the JSTs back to lib to accomodate the demo page.
FileUtils.mv("build/visualsearch_templates.js", "lib/js/templates/templates.js")
# Fix image url paths.
['build', 'build-min'].each do |build|
File.open("#{build}/visualsearch.css", 'r+') do |file|
css = file.read
css.gsub!(/url\((.*?)images\/embed\/icons/, 'url(../images/embed/icons')
file.rewind
file.write(css)
file.truncate(css.length)
end
end
end
desc "Build the docco documentation"
task :docs do
sh "docco lib/js/*.js lib/js/**/*.js"
end

View File

@ -0,0 +1,28 @@
embed_assets: datauri
javascript_compressor: closure
template_function: _.template
gzip_assets: <% if $VS_MIN %>on<% else %>off<% end %>
compress_assets: <% if $VS_MIN %>on<% else %>off<% end %>
javascripts:
dependencies:
- vendor/jquery-*.js
- vendor/jquery.ui.core.js
- vendor/jquery.ui.widget.js
- vendor/jquery.ui.position.js
- vendor/jquery.ui.*.js
- vendor/underscore-*.js
- vendor/backbone-*.js
visualsearch:
- lib/js/visualsearch.js
- lib/js/views/*.js
- lib/js/utils/*.js
- lib/js/models/*.js
- lib/js/templates/*.jst
<% unless $VS_MIN %>visualsearch_templates:
- lib/js/templates/*.jst
<% end %>
stylesheets:
visualsearch:
- lib/css/*.css

View File

@ -0,0 +1,310 @@
.VS-search .VS-icon {
background-repeat: no-repeat;
background-position: center center;
vertical-align: middle;
width: 16px; height: 16px;
}
.VS-search .VS-icon-cancel {
width: 11px; height: 11px;
background-position: center 0;
background-image: url("data:image/png;charset=utf-8;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAWCAYAAAAW5GZjAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAb9JREFUeNqUUr1qAkEQ3j0khQp6kihaeGgEEa18gTQR0iRY+BaBSMDGwidIEUKqFL6BopgqBAJ5AMFGjUU0d4WHEvwJarvZ77gRIzGYgb1hZr+Z75vZ40IIzqTNZrPj8Xicn0wmmcViEXS73aaqqq+BQODG6/W+A8MBNk3zfDAY3C6Xy0O2ZS6X6zMSiVwHg8FHLjtq7Xb7RQKj7BeTzVCgJ5PJU2U0GhUk7REuMpkMi8fjFggeMeecrVYrFRId0CgTAgDDMFg4HLbA8IjJgHNgGEr0er0fQIphUmZAwdSUADUB4RFDsz3oSMF6CLzZkQqgGebz+Z75dDqNdTqdp13bgDmdTj2VSp0oWHg0Gr2UNH2Z/9o+yMv7K4/HY/C/XhDUfr//jl7QQVT9fp/V63VWqVRYt9tliUSCZbPZg1wux9Lp9PqFeK1Wu9A0DdXz7YM87i0FrVZLs4Fi1wmFQh/NZjOmVKvVgq7rR/QflMtlixGedjwcDlUpMQ9tbzalkAAB2/R297mNW+sT2wUbUnA//V/nYrH4QOBNABUQuFQq3TNMuc82sDVrz41G42yvPeODAwZQ0QzwiJEnzLcAAwBJ6WXlwoBgZAAAAABJRU5ErkJggg==");
cursor: pointer;
}
.VS-search .VS-icon-cancel:hover {
background-position: center -11px;
}
.VS-search .VS-icon-search {
width: 12px; height: 12px;
background-image: url("data:image/png;charset=utf-8;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAUZJREFUeNpUUM2qgmAQzS8NiUgLzTIXLZQW1QuI9AY9QPSW9gQ9QiriwpJQEBVrVWT2d7p2L9xZzDdzZs7M+YYqy/J8Ptu2vd/v4zgeDAaqqk4mE47jar9GnU6nzWbjOA5FUa/Xq0Jns9l8Pud5vkpp58cwAOzhcBhFkeu6GNztdg3D+Db5vo9nOp2iiWGYTqdDCMFe4LquI0aVpGmKR9M0lmUbjQY8YiBJklTb4YkoilBzOBzq9TogeMQIJEmqmlAlo9EIyXa7tSyrKAp4xEBkWUb5q2k8Hh+PR8/zwjCEgufz+aESstvtoKnVan2GgY31kBkEAfT1ej1FUZDiNIIgrFYr9H1ug3teLpfH43G/3/FBUJGu1+s8z8FZLpc0mmiabrfbf5fEumazuVgsTNO8Xq+3242qRNT+G0CMz7IMzH6//xZgAA60tj6rqzxpAAAAAElFTkSuQmCC");
}
/*------------------------------ RESET + DEFAULT STYLES ---------------------------------*/
/*
Eric Meyer's final reset.css
Source: http://meyerweb.com/eric/thoughts/2007/05/01/reset-reloaded/
*/
.VS-search div, .VS-search span, .VS-search a, .VS-search img,
.VS-search ul, .VS-search li, .VS-search form, .VS-search label,
.VS-interface ul, .VS-interface li, .VS-interface {
margin: 0;
padding: 0;
border: 0;
outline: 0;
font-weight: inherit;
font-style: inherit;
font-size: 100%;
font-family: inherit;
vertical-align: baseline;
}
.VS-search :focus {
outline: 0;
}
.VS-search {
line-height: 1;
color: black;
}
.VS-search ol, .VS-search ul {
list-style: none;
}
/* ===================== */
/* = General and Reset = */
/* ===================== */
.VS-search {
font-family: Arial, sans-serif;
color: #373737;
font-size: 12px;
}
.VS-search input {
display: block;
border: none;
-moz-box-shadow: none;
-webkit-box-shadow: none;
box-shadow: none;
outline: none;
margin: 0; padding: 4px;
background: transparent;
font-size: 16px;
line-height: 20px;
width: 100%;
}
.VS-interface, .VS-search .dialog, .VS-search input {
font-family: "Lucida Grande", "Lucida Sans Unicode", Helvetica, Arial, sans-serif !important;
line-height: 1.1em;
}
/* ========== */
/* = Layout = */
/* ========== */
.VS-search .VS-search-box {
cursor: text;
position: relative;
background: transparent;
border: 2px solid #ccc;
border-radius: 16px; -webkit-border-radius: 16px; -moz-border-radius: 16px;
background-color: #fafafa;
-webkit-box-shadow: inset 0px 0px 3px #ccc;
-moz-box-shadow: inset 0px 0px 3px #ccc;
box-shadow: inset 0px 0px 3px #ccc;
min-height: 28px;
height: auto;
}
.VS-search .VS-search-box.VS-focus {
border-color: #acf;
-webkit-box-shadow: inset 0px 0px 3px #acf;
-moz-box-shadow: inset 0px 0px 3px #acf;
box-shadow: inset 0px 0px 3px #acf;
}
.VS-search .VS-search-inner {
position: relative;
margin: 0 20px 0 22px;
overflow: hidden;
}
.VS-search input {
width: 100px;
}
.VS-search input,
.VS-search .VS-input-width-tester {
padding: 6px 0;
float: left;
color: #808080;
font: 13px/17px Helvetica, Arial;
}
.VS-search.VS-focus input {
color: #606060;
}
.VS-search .VS-icon-search {
position: absolute;
left: 9px; top: 8px;
}
.VS-search .VS-icon-cancel {
position: absolute;
right: 9px; top: 8px;
}
/* ================ */
/* = Search Facet = */
/* ================ */
.VS-search .search_facet {
float: left;
margin: 0;
padding: 0 0 0 14px;
position: relative;
border: 1px solid transparent;
height: 20px;
margin: 3px -3px 3px 0;
}
.VS-search .search_facet.is_selected {
margin-left: -3px;
-webkit-border-radius: 16px;
-moz-border-radius: 16px;
border-radius: 16px;
background-color: #d2e6fd;
background-image: -moz-linear-gradient(top, #d2e6fd, #b0d1f9); /* FF3.6 */
background-image: -webkit-gradient(linear, left top, left bottom, from(#d2e6fd), to(#b0d1f9)); /* Saf4+, Chrome */
background-image: linear-gradient(top, #d2e6fd, #b0d1f9);
border: 1px solid #6eadf5;
}
.VS-search .search_facet .category {
float: left;
text-transform: uppercase;
font-weight: bold;
font-size: 10px;
color: #808080;
padding: 8px 0 5px;
line-height: 13px;
cursor: pointer;
padding: 4px 0 0;
}
.VS-search .search_facet.is_selected .category {
margin-left: 3px;
}
.VS-search .search_facet .search_facet_input_container {
float: left;
}
.VS-search .search_facet input {
margin: 0;
padding: 0;
color: #000;
font-size: 13px;
line-height: 16px;
padding: 5px 0 5px 4px;
height: 16px;
width: auto;
z-index: 100;
position: relative;
padding-top: 1px;
padding-bottom: 2px;
padding-right: 3px;
}
.VS-search .search_facet.is_editing input,
.VS-search .search_facet.is_selected input {
color: #000;
}
.VS-search .search_facet .search_facet_remove {
position: absolute;
left: 0;
top: 4px;
}
.VS-search .search_facet.is_selected .search_facet_remove {
opacity: 0.4;
left: 3px;
filter: alpha(opacity=40);
background-position: center -11px;
}
.VS-search .search_facet .search_facet_remove:hover {
opacity: 1;
}
.VS-search .search_facet.is_editing .category,
.VS-search .search_facet.is_selected .category {
color: #000;
}
.VS-search .search_facet.search_facet_maybe_delete .category,
.VS-search .search_facet.search_facet_maybe_delete input {
color: darkred;
}
/* ================ */
/* = Search Input = */
/* ================ */
.VS-search .search_input {
height: 28px;
float: left;
margin-left: -1px;
}
.VS-search .search_input input {
padding: 6px 3px 6px 2px;
line-height: 10px;
height: 22px;
margin-top: -4px;
width: 10px;
z-index: 100;
min-width: 4px;
position: relative;
}
.VS-search .search_input.is_editing input {
color: #202020;
}
/* ================ */
/* = Autocomplete = */
/* ================ */
.VS-interface.ui-autocomplete {
position: absolute;
border: 1px solid #C0C0C0;
border-top: 1px solid #D9D9D9;
background-color: #F6F6F6;
cursor: pointer;
z-index: 10000;
padding: 0;
margin: 0;
width: auto;
min-width: 80px;
max-width: 220px;
max-height: 240px;
overflow-y: auto;
overflow-x: hidden;
font-size: 13px;
top: 5px;
opacity: 0.97;
box-shadow: 3px 4px 5px -2px rgba(0, 0, 0, 0.5); -webkit-box-shadow: 3px 4px 5px -2px rgba(0, 0, 0, 0.5); -moz-box-shadow: 3px 4px 5px -2px rgba(0, 0, 0, 0.5);
}
.VS-interface.ui-autocomplete .ui-autocomplete-category {
text-transform: capitalize;
font-size: 11px;
padding: 4px 4px 4px;
border-top: 1px solid #A2A2A2;
border-bottom: 1px solid #A2A2A2;
background-color: #B7B7B7;
text-shadow: 0 -1px 0 #999;
font-weight: bold;
color: white;
cursor: default;
}
.VS-interface.ui-autocomplete .ui-menu-item {
float: none;
}
.VS-interface.ui-autocomplete .ui-menu-item a {
color: #000;
outline: none;
display: block;
padding: 3px 4px 5px;
border-radius: none;
line-height: 1;
background-color: #F8F8F8;
background-image: -moz-linear-gradient(top, #F8F8F8, #F3F3F3); /* FF3.6 */
background-image: -webkit-gradient(linear, left top, left bottom, from(#F8F8F8), to(#F3F3F3)); /* Saf4+, Chrome */
background-image: linear-gradient(top, #F8F8F8, #F3F3F3);
border-top: 1px solid #FAFAFA;
border-bottom: 1px solid #f0f0f0;
}
.VS-interface.ui-autocomplete .ui-menu-item a:active {
outline: none;
}
.VS-interface.ui-autocomplete .ui-menu-item .ui-state-hover {
background-color: #6483F7;
background-image: -moz-linear-gradient(top, #648bF5, #2465f3); /* FF3.6 */
background-image: -webkit-gradient(linear, left top, left bottom, from(#648bF5), to(#2465f3)); /* Saf4+, Chrome */
background-image: linear-gradient(top, #648bF5, #2465f3);
border-top: 1px solid #5b83ec;
border-bottom: 1px solid #1459e9;
border-left: none;
border-right: none;
color: white;
margin: 0;
}
.VS-interface.ui-autocomplete .ui-corner-all {
border-radius: 0;
}
.VS-interface.ui-autocomplete li {
list-style: none;
width: auto;
}

View File

@ -0,0 +1,310 @@
.VS-search .VS-icon {
background-repeat: no-repeat;
background-position: center center;
vertical-align: middle;
width: 16px; height: 16px;
}
.VS-search .VS-icon-cancel {
width: 11px; height: 11px;
background-position: center 0;
background-image: url(../images/embed/icons/cancel_search.png?1311104738);
cursor: pointer;
}
.VS-search .VS-icon-cancel:hover {
background-position: center -11px;
}
.VS-search .VS-icon-search {
width: 12px; height: 12px;
background-image: url(../images/embed/icons/search_glyph.png?1311104738);
}
/*------------------------------ RESET + DEFAULT STYLES ---------------------------------*/
/*
Eric Meyer's final reset.css
Source: http://meyerweb.com/eric/thoughts/2007/05/01/reset-reloaded/
*/
.VS-search div, .VS-search span, .VS-search a, .VS-search img,
.VS-search ul, .VS-search li, .VS-search form, .VS-search label,
.VS-interface ul, .VS-interface li, .VS-interface {
margin: 0;
padding: 0;
border: 0;
outline: 0;
font-weight: inherit;
font-style: inherit;
font-size: 100%;
font-family: inherit;
vertical-align: baseline;
}
.VS-search :focus {
outline: 0;
}
.VS-search {
line-height: 1;
color: black;
}
.VS-search ol, .VS-search ul {
list-style: none;
}
/* ===================== */
/* = General and Reset = */
/* ===================== */
.VS-search {
font-family: Arial, sans-serif;
color: #373737;
font-size: 12px;
}
.VS-search input {
display: block;
border: none;
-moz-box-shadow: none;
-webkit-box-shadow: none;
box-shadow: none;
outline: none;
margin: 0; padding: 4px;
background: transparent;
font-size: 16px;
line-height: 20px;
width: 100%;
}
.VS-interface, .VS-search .dialog, .VS-search input {
font-family: "Lucida Grande", "Lucida Sans Unicode", Helvetica, Arial, sans-serif !important;
line-height: 1.1em;
}
/* ========== */
/* = Layout = */
/* ========== */
.VS-search .VS-search-box {
cursor: text;
position: relative;
background: transparent;
border: 2px solid #ccc;
border-radius: 16px; -webkit-border-radius: 16px; -moz-border-radius: 16px;
background-color: #fafafa;
-webkit-box-shadow: inset 0px 0px 3px #ccc;
-moz-box-shadow: inset 0px 0px 3px #ccc;
box-shadow: inset 0px 0px 3px #ccc;
min-height: 28px;
height: auto;
}
.VS-search .VS-search-box.VS-focus {
border-color: #acf;
-webkit-box-shadow: inset 0px 0px 3px #acf;
-moz-box-shadow: inset 0px 0px 3px #acf;
box-shadow: inset 0px 0px 3px #acf;
}
.VS-search .VS-search-inner {
position: relative;
margin: 0 20px 0 22px;
overflow: hidden;
}
.VS-search input {
width: 100px;
}
.VS-search input,
.VS-search .VS-input-width-tester {
padding: 6px 0;
float: left;
color: #808080;
font: 13px/17px Helvetica, Arial;
}
.VS-search.VS-focus input {
color: #606060;
}
.VS-search .VS-icon-search {
position: absolute;
left: 9px; top: 8px;
}
.VS-search .VS-icon-cancel {
position: absolute;
right: 9px; top: 8px;
}
/* ================ */
/* = Search Facet = */
/* ================ */
.VS-search .search_facet {
float: left;
margin: 0;
padding: 0 0 0 14px;
position: relative;
border: 1px solid transparent;
height: 20px;
margin: 3px -3px 3px 0;
}
.VS-search .search_facet.is_selected {
margin-left: -3px;
-webkit-border-radius: 16px;
-moz-border-radius: 16px;
border-radius: 16px;
background-color: #d2e6fd;
background-image: -moz-linear-gradient(top, #d2e6fd, #b0d1f9); /* FF3.6 */
background-image: -webkit-gradient(linear, left top, left bottom, from(#d2e6fd), to(#b0d1f9)); /* Saf4+, Chrome */
background-image: linear-gradient(top, #d2e6fd, #b0d1f9);
border: 1px solid #6eadf5;
}
.VS-search .search_facet .category {
float: left;
text-transform: uppercase;
font-weight: bold;
font-size: 10px;
color: #808080;
padding: 8px 0 5px;
line-height: 13px;
cursor: pointer;
padding: 4px 0 0;
}
.VS-search .search_facet.is_selected .category {
margin-left: 3px;
}
.VS-search .search_facet .search_facet_input_container {
float: left;
}
.VS-search .search_facet input {
margin: 0;
padding: 0;
color: #000;
font-size: 13px;
line-height: 16px;
padding: 5px 0 5px 4px;
height: 16px;
width: auto;
z-index: 100;
position: relative;
padding-top: 1px;
padding-bottom: 2px;
padding-right: 3px;
}
.VS-search .search_facet.is_editing input,
.VS-search .search_facet.is_selected input {
color: #000;
}
.VS-search .search_facet .search_facet_remove {
position: absolute;
left: 0;
top: 4px;
}
.VS-search .search_facet.is_selected .search_facet_remove {
opacity: 0.4;
left: 3px;
filter: alpha(opacity=40);
background-position: center -11px;
}
.VS-search .search_facet .search_facet_remove:hover {
opacity: 1;
}
.VS-search .search_facet.is_editing .category,
.VS-search .search_facet.is_selected .category {
color: #000;
}
.VS-search .search_facet.search_facet_maybe_delete .category,
.VS-search .search_facet.search_facet_maybe_delete input {
color: darkred;
}
/* ================ */
/* = Search Input = */
/* ================ */
.VS-search .search_input {
height: 28px;
float: left;
margin-left: -1px;
}
.VS-search .search_input input {
padding: 6px 3px 6px 2px;
line-height: 10px;
height: 22px;
margin-top: -4px;
width: 10px;
z-index: 100;
min-width: 4px;
position: relative;
}
.VS-search .search_input.is_editing input {
color: #202020;
}
/* ================ */
/* = Autocomplete = */
/* ================ */
.VS-interface.ui-autocomplete {
position: absolute;
border: 1px solid #C0C0C0;
border-top: 1px solid #D9D9D9;
background-color: #F6F6F6;
cursor: pointer;
z-index: 10000;
padding: 0;
margin: 0;
width: auto;
min-width: 80px;
max-width: 220px;
max-height: 240px;
overflow-y: auto;
overflow-x: hidden;
font-size: 13px;
top: 5px;
opacity: 0.97;
box-shadow: 3px 4px 5px -2px rgba(0, 0, 0, 0.5); -webkit-box-shadow: 3px 4px 5px -2px rgba(0, 0, 0, 0.5); -moz-box-shadow: 3px 4px 5px -2px rgba(0, 0, 0, 0.5);
}
.VS-interface.ui-autocomplete .ui-autocomplete-category {
text-transform: capitalize;
font-size: 11px;
padding: 4px 4px 4px;
border-top: 1px solid #A2A2A2;
border-bottom: 1px solid #A2A2A2;
background-color: #B7B7B7;
text-shadow: 0 -1px 0 #999;
font-weight: bold;
color: white;
cursor: default;
}
.VS-interface.ui-autocomplete .ui-menu-item {
float: none;
}
.VS-interface.ui-autocomplete .ui-menu-item a {
color: #000;
outline: none;
display: block;
padding: 3px 4px 5px;
border-radius: none;
line-height: 1;
background-color: #F8F8F8;
background-image: -moz-linear-gradient(top, #F8F8F8, #F3F3F3); /* FF3.6 */
background-image: -webkit-gradient(linear, left top, left bottom, from(#F8F8F8), to(#F3F3F3)); /* Saf4+, Chrome */
background-image: linear-gradient(top, #F8F8F8, #F3F3F3);
border-top: 1px solid #FAFAFA;
border-bottom: 1px solid #f0f0f0;
}
.VS-interface.ui-autocomplete .ui-menu-item a:active {
outline: none;
}
.VS-interface.ui-autocomplete .ui-menu-item .ui-state-hover {
background-color: #6483F7;
background-image: -moz-linear-gradient(top, #648bF5, #2465f3); /* FF3.6 */
background-image: -webkit-gradient(linear, left top, left bottom, from(#648bF5), to(#2465f3)); /* Saf4+, Chrome */
background-image: linear-gradient(top, #648bF5, #2465f3);
border-top: 1px solid #5b83ec;
border-bottom: 1px solid #1459e9;
border-left: none;
border-right: none;
color: white;
margin: 0;
}
.VS-interface.ui-autocomplete .ui-corner-all {
border-radius: 0;
}
.VS-interface.ui-autocomplete li {
list-style: none;
width: auto;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,453 @@
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=UTF-8" />
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<title>DocumentCloud's VisualSearch.js</title>
<style>
body {
font-size: 16px;
line-height: 24px;
background: #FEF3CA;
color: #022;
height: 100%;
font-family: "Palatino Linotype", "Book Antiqua", Palatino, FreeSerif, serif;
}
div.container {
width: 720px;
margin: 50px 0 50px 50px;
}
p, li {
margin: 16px 0 16px 0;
width: 550px;
}
p.break {
margin-top: 35px;
}
ol {
padding-left: 24px;
}
ol li {
font-weight: bold;
margin-left: 0;
}
a, a:visited {
padding: 0 2px;
text-decoration: none;
background: #f0c095;
color: #252519;
}
a:active, a:hover {
color: #FFF;
background: #C25D00;
}
h1, h2, h3, h4, h5, h6 {
margin-top: 40px;
}
b.header {
font-size: 18px;
}
span.alias {
font-size: 14px;
font-style: italic;
margin-left: 20px;
}
table {
margin: 16px 0; padding: 0;
}
tr, td, th {
margin: 0; padding: 0;
text-align: left;
}
th {
padding: 24px 0 0;
}
tr:first-child th {
padding-top: 0;
}
td {
padding: 6px 15px 6px 0;
}
td.definition {
line-height: 18px;
font-size: 14px;
}
table.downloads td {
padding-left: 18px;
}
.demo-hint {
font-size: 13px;
margin: 0 0 12px 12px;
font-weight: normal;
}
#VS code, #VS pre, #VS tt {
font-family: Monaco, Consolas, "Lucida Console", monospace;
font-size: 12px;
line-height: 18px;
color: #444;
background: none;
}
#VS code {
margin-left: 8px;
padding: 0 0 0 12px;
font-weight: normal;
}
#VS pre {
font-size: 12px;
padding: 2px 0 2px 0;
border-left: 6px solid #829C37;
margin: 12px 0;
}
#search_query {
margin: 18px 0;
opacity: 0;
}
#search_query .raquo {
font-size: 18px;
line-height: 12px;
font-weight: bold;
margin-right: 4px;
}
#search_query2 {
margin: 18px 0;
opacity: 0;
}
#search_query2 .raquo {
font-size: 18px;
line-height: 12px;
font-weight: bold;
margin-right: 4px;
}
</style>
<link rel="stylesheet" href="lib/css/reset.css" type="text/css" media="screen" charset="utf-8">
<link rel="stylesheet" href="lib/css/icons.css" type="text/css" media="screen" charset="utf-8">
<link rel="stylesheet" href="lib/css/workspace.css" type="text/css" media="screen" charset="utf-8">
<script src="vendor/jquery-1.6.1.js" type="text/javascript" charset="utf-8"></script>
<!-- <script src="vendor/backported/jquery-1.4.4.js" type="text/javascript" charset="utf-8"></script> -->
<script src="vendor/jquery.ui.core.js" type="text/javascript" charset="utf-8"></script>
<script src="vendor/jquery.ui.widget.js" type="text/javascript" charset="utf-8"></script>
<script src="vendor/jquery.ui.position.js" type="text/javascript" charset="utf-8"></script>
<script src="vendor/jquery.ui.autocomplete.js" type="text/javascript" charset="utf-8"></script>
<script src="vendor/underscore-1.1.5.js" type="text/javascript" charset="utf-8"></script>
<script src="vendor/backbone-0.5.0.js" type="text/javascript" charset="utf-8"></script>
<script src="lib/js/visualsearch.js" type="text/javascript" charset="utf-8"></script>
<script src="lib/js/views/search_box.js" type="text/javascript" charset="utf-8"></script>
<script src="lib/js/views/search_facet.js" type="text/javascript" charset="utf-8"></script>
<script src="lib/js/views/search_input.js" type="text/javascript" charset="utf-8"></script>
<script src="lib/js/models/search_facets.js" type="text/javascript" charset="utf-8"></script>
<script src="lib/js/models/search_query.js" type="text/javascript" charset="utf-8"></script>
<script src="lib/js/utils/backbone_extensions.js" type="text/javascript" charset="utf-8"></script>
<script src="lib/js/utils/hotkeys.js" type="text/javascript" charset="utf-8"></script>
<script src="lib/js/utils/jquery_extensions.js" type="text/javascript" charset="utf-8"></script>
<script src="lib/js/utils/search_parser.js" type="text/javascript" charset="utf-8"></script>
<script src="lib/js/utils/inflector.js" type="text/javascript" charset="utf-8"></script>
<script src="lib/js/templates/templates.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div class="container" id="VS">
<h1><a href="index.html">VisualSearch.js</a></h1>
<p>
<a href="http://github.com/documentcloud/visualsearch">VisualSearch.js</a>
enhances ordinary search boxes with the ability to autocomplete
faceted search queries. Specify the facets for completion, along with the
completable values for any facet. You can retrieve the search query as a
structured object, so you don't have to parse the query string yourself.
</p>
<p>
<a href="docs/visualsearch.html">The complete annotated source code</a>
is also available.
</p>
<p>
The project is
<a href="http://github.com/documentcloud/visualsearch/">hosted on GitHub</a>.
You can report bugs and discuss features on the
<a href="http://github.com/documentcloud/visualsearch/issues">issues page</a>,
on Freenode in the <tt>#documentcloud</tt> channel,
or send tweets to <a href="http://twitter.com/documentcloud">@documentcloud</a>.
</p>
<p>
<i>VisualSearch.js is an open-source component of <a href="http://documentcloud.org/">DocumentCloud</a>.</i>
</p>
<h2 id="demo">Demo <span class="demo-hint"><i>Try searching for: <b>account</b>, <b>filter</b>, <b>access</b>, <b>title</b>, <b>city</b>, <b>state</b>, or <b>country</b>.</i></span></h2>
<div id="search_box_container"></div>
<div id="search_query">&nbsp;</div>
<script type="text/javascript" charset="utf-8">
$(document).ready(function() {
window.visualSearch = VS.init({
container : $('#search_box_container'),
query : 'country: "South Africa" account: 5-samuel title: "Pentagon Papers"',
// query : '',
unquotable : [
'text',
'account',
'filter',
'access'
],
callbacks : {
search : function(query, searchCollection) {
var $query = $('#search_query');
$query.stop().animate({opacity : 1}, {duration: 300, queue: false});
$query.html('<span class="raquo">&raquo;</span> You searched for: <b>' + searchCollection.serialize() + '</b>');
clearTimeout(window.queryHideDelay);
window.queryHideDelay = setTimeout(function() {
$query.animate({
opacity : 0
}, {
duration: 1000,
queue: false
});
}, 2000);
},
valueMatches : function(category, searchTerm, callback) {
switch (category) {
case 'account':
callback([
{ value: '1-amanda', label: 'Amanda' },
{ value: '2-aron', label: 'Aron' },
{ value: '3-eric', label: 'Eric' },
{ value: '4-jeremy', label: 'Jeremy' },
{ value: '5-samuel', label: 'Samuel' },
{ value: '6-scott', label: 'Scott' }
]);
break;
case 'filter':
callback(['published', 'unpublished', 'draft']);
break;
case 'access':
callback(['public', 'private', 'protected']);
break;
case 'title':
callback([
'Pentagon Papers',
'CoffeeScript Manual',
'Laboratory for Object Oriented Thinking',
'A Repository Grows in Brooklyn'
]);
break;
case 'city':
callback([
'Cleveland',
'New York City',
'Brooklyn',
'Manhattan',
'Queens',
'The Bronx',
'Staten Island',
'San Francisco',
'Los Angeles',
'Seattle',
'London',
'Portland',
'Chicago',
'Boston'
])
break;
case 'state':
callback([
"Alabama", "Alaska", "Arizona", "Arkansas", "California",
"Colorado", "Connecticut", "Delaware", "District of Columbia", "Florida",
"Georgia", "Guam", "Hawaii", "Idaho", "Illinois",
"Indiana", "Iowa", "Kansas", "Kentucky", "Louisiana",
"Maine", "Maryland", "Massachusetts", "Michigan", "Minnesota",
"Mississippi", "Missouri", "Montana", "Nebraska", "Nevada",
"New Hampshire", "New Jersey", "New Mexico", "New York", "North Carolina",
"North Dakota", "Ohio", "Oklahoma", "Oregon", "Pennsylvania",
"Puerto Rico", "Rhode Island", "South Carolina", "South Dakota", "Tennessee",
"Texas", "Utah", "Vermont", "Virginia", "Virgin Islands",
"Washington", "West Virginia", "Wisconsin", "Wyoming"
]);
break
case 'country':
callback([
"China", "India", "United States", "Indonesia", "Brazil",
"Pakistan", "Bangladesh", "Nigeria", "Russia", "Japan",
"Mexico", "Philippines", "Vietnam", "Ethiopia", "Egypt",
"Germany", "Turkey", "Iran", "Thailand", "D. R. of Congo",
"France", "United Kingdom", "Italy", "Myanmar", "South Africa",
"South Korea", "Colombia", "Ukraine", "Spain", "Tanzania",
"Sudan", "Kenya", "Argentina", "Poland", "Algeria",
"Canada", "Uganda", "Morocco", "Iraq", "Nepal",
"Peru", "Afghanistan", "Venezuela", "Malaysia", "Uzbekistan",
"Saudi Arabia", "Ghana", "Yemen", "North Korea", "Mozambique",
"Taiwan", "Syria", "Ivory Coast", "Australia", "Romania",
"Sri Lanka", "Madagascar", "Cameroon", "Angola", "Chile",
"Netherlands", "Burkina Faso", "Niger", "Kazakhstan", "Malawi",
"Cambodia", "Guatemala", "Ecuador", "Mali", "Zambia",
"Senegal", "Zimbabwe", "Chad", "Cuba", "Greece",
"Portugal", "Belgium", "Czech Republic", "Tunisia", "Guinea",
"Rwanda", "Dominican Republic", "Haiti", "Bolivia", "Hungary",
"Belarus", "Somalia", "Sweden", "Benin", "Azerbaijan",
"Burundi", "Austria", "Honduras", "Switzerland", "Bulgaria",
"Serbia", "Israel", "Tajikistan", "Hong Kong", "Papua New Guinea",
"Togo", "Libya", "Jordan", "Paraguay", "Laos",
"El Salvador", "Sierra Leone", "Nicaragua", "Kyrgyzstan", "Denmark",
"Slovakia", "Finland", "Eritrea", "Turkmenistan"
], {preserveOrder: true});
break;
}
},
facetMatches : function(callback) {
callback([
'account', 'filter', 'access', 'title',
{ label: 'city', category: 'location' },
{ label: 'address', category: 'location' },
{ label: 'country', category: 'location' },
{ label: 'state', category: 'location' },
]);
}
}
});
});
</script>
<div id="search_box_container2"></div>
<div id="search_query2">&nbsp;</div>
<script type="text/javascript" charset="utf-8">
$(document).ready(function() {
var visualSearch = VS.init({
container : $('#search_box_container2'),
query : '',
// query : '',
unquotable : [
'text',
'account',
'filter',
'access'
],
callbacks : {
search : function(query, searchCollection) {
console.log(["query", searchCollection.facets(), query]);
var $query = $('#search_query2');
$query.stop().animate({opacity : 1}, {duration: 300, queue: false});
$query.html('<span class="raquo">&raquo;</span> You searched for: <b>' + searchCollection.serialize() + '</b>');
clearTimeout(window.queryHideDelay2);
window.queryHideDelay2 = setTimeout(function() {
$query.animate({
opacity : 0
}, {
duration: 1000,
queue: false
});
}, 2000);
},
valueMatches : function(category, searchTerm, callback) {
switch (category) {
case 'account':
callback([
{ value: '1-amanda', label: 'Amanda' },
{ value: '2-aron', label: 'Aron' },
{ value: '3-eric', label: 'Eric' },
{ value: '4-jeremy', label: 'Jeremy' },
{ value: '5-samuel', label: 'Samuel' },
{ value: '6-scott', label: 'Scott' }
]);
break;
case 'filter':
callback(['published', 'unpublished', 'draft']);
break;
case 'access':
callback(['public', 'private', 'protected']);
break;
case 'title':
callback([
'Pentagon Papers',
'CoffeeScript Manual',
'Laboratory for Object Oriented Thinking',
'A Repository Grows in Brooklyn'
]);
break;
case 'city':
callback([
'Cleveland',
'New York City',
'Brooklyn',
'Manhattan',
'Queens',
'The Bronx',
'Staten Island',
'San Francisco',
'Los Angeles',
'Seattle',
'London',
'Portland',
'Chicago',
'Boston'
])
break;
case 'state':
callback([
"Alabama", "Alaska", "Arizona", "Arkansas", "California",
"Colorado", "Connecticut", "Delaware", "District of Columbia", "Florida",
"Georgia", "Guam", "Hawaii", "Idaho", "Illinois",
"Indiana", "Iowa", "Kansas", "Kentucky", "Louisiana",
"Maine", "Maryland", "Massachusetts", "Michigan", "Minnesota",
"Mississippi", "Missouri", "Montana", "Nebraska", "Nevada",
"New Hampshire", "New Jersey", "New Mexico", "New York", "North Carolina",
"North Dakota", "Ohio", "Oklahoma", "Oregon", "Pennsylvania",
"Puerto Rico", "Rhode Island", "South Carolina", "South Dakota", "Tennessee",
"Texas", "Utah", "Vermont", "Virginia", "Virgin Islands",
"Washington", "West Virginia", "Wisconsin", "Wyoming"
]);
break
case 'country':
callback([
"China", "India", "United States", "Indonesia", "Brazil",
"Pakistan", "Bangladesh", "Nigeria", "Russia", "Japan",
"Mexico", "Philippines", "Vietnam", "Ethiopia", "Egypt",
"Germany", "Turkey", "Iran", "Thailand", "D. R. of Congo",
"France", "United Kingdom", "Italy", "Myanmar", "South Africa",
"South Korea", "Colombia", "Ukraine", "Spain", "Tanzania",
"Sudan", "Kenya", "Argentina", "Poland", "Algeria",
"Canada", "Uganda", "Morocco", "Iraq", "Nepal",
"Peru", "Afghanistan", "Venezuela", "Malaysia", "Uzbekistan",
"Saudi Arabia", "Ghana", "Yemen", "North Korea", "Mozambique",
"Taiwan", "Syria", "Ivory Coast", "Australia", "Romania",
"Sri Lanka", "Madagascar", "Cameroon", "Angola", "Chile",
"Netherlands", "Burkina Faso", "Niger", "Kazakhstan", "Malawi",
"Cambodia", "Guatemala", "Ecuador", "Mali", "Zambia",
"Senegal", "Zimbabwe", "Chad", "Cuba", "Greece",
"Portugal", "Belgium", "Czech Republic", "Tunisia", "Guinea",
"Rwanda", "Dominican Republic", "Haiti", "Bolivia", "Hungary",
"Belarus", "Somalia", "Sweden", "Benin", "Azerbaijan",
"Burundi", "Austria", "Honduras", "Switzerland", "Bulgaria",
"Serbia", "Israel", "Tajikistan", "Hong Kong", "Papua New Guinea",
"Togo", "Libya", "Jordan", "Paraguay", "Laos",
"El Salvador", "Sierra Leone", "Nicaragua", "Kyrgyzstan", "Denmark",
"Slovakia", "Finland", "Eritrea", "Turkmenistan"
]);
break;
}
},
facetMatches : function(callback) {
callback([
'account', 'filter', 'access', 'title',
{ label: 'city', category: 'location' },
{ label: 'address', category: 'location' },
{ label: 'country', category: 'location' },
{ label: 'state', category: 'location' },
], {
preserveOrder: true
});
}
}
});
});
</script>
</div>
</body>
</html>

View File

@ -0,0 +1,537 @@
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=UTF-8" />
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<title>DocumentCloud's VisualSearch.js</title>
<style>
body {
font-size: 16px;
line-height: 24px;
background: #FEF3CA;
height: 100%;
color: #022;
font-family: Arial;
font-family: "Palatino Linotype", "Book Antiqua", Palatino, FreeSerif, serif;
}
div.container {
width: 720px;
margin: 50px 0 50px 50px;
}
p, li {
margin: 16px 0 16px 0;
width: 550px;
}
p.break {
margin-top: 35px;
}
ol {
padding-left: 24px;
}
ol li {
font-weight: bold;
margin-left: 0;
}
a, a:visited {
padding: 0 2px;
text-decoration: none;
background: #f0c095;
color: #252519;
}
a:active, a:hover {
color: #000;
background: #e0a070;
}
h1, h2, h3, h4, h5, h6 {
margin-top: 40px;
}
b.header {
font-size: 18px;
}
span.alias {
font-size: 14px;
font-style: italic;
margin-left: 20px;
}
table {
margin: 16px 0; padding: 0;
}
tr, td, th {
margin: 0; padding: 0;
text-align: left;
}
th {
padding: 24px 0 0;
}
tr:first-child th {
padding-top: 0;
}
td {
padding: 6px 15px 6px 0;
}
td.definition {
line-height: 18px;
font-size: 14px;
}
table.downloads td {
padding-left: 18px;
}
.demo-hint {
font-size: 13px;
margin: 0 0 12px 12px;
font-weight: normal;
}
#VS code, #VS pre, #VS tt {
font-family: Monaco, Consolas, "Lucida Console", monospace;
font-size: 12px;
line-height: 18px;
color: #444;
background: none;
}
#VS code {
margin-left: 8px;
padding: 0 0 0 12px;
font-weight: normal;
}
#VS pre {
font-size: 12px;
padding: 2px 0 2px 0;
border-left: 6px solid #829C37;
margin: 12px 0;
}
#search_query {
margin: 18px 0 -24px;
opacity: 0;
}
#search_query .raquo {
font-size: 18px;
line-height: 12px;
font-weight: bold;
margin-right: 4px;
}
.attribution {
margin: -12px 0 24px;
font-size: 14px;
}
</style>
<link rel="stylesheet" href="build-min/visualsearch-datauri.css" type="text/css" media="screen" charset="utf-8">
<link rel="stylesheet" href="docs/assets/github.css" type="text/css" media="screen" charset="utf-8">
<script src="build-min/dependencies.js" type="text/javascript" charset="utf-8"></script>
<script src="build-min/visualsearch.js" type="text/javascript" charset="utf-8"></script>
<script src="docs/assets/highlight.js" type="text/javascript" charset="utf-8"></script>
<script src="docs/assets/javascript.js" type="text/javascript" charset="utf-8"></script>
<script src="docs/assets/xml.js" type="text/javascript" charset="utf-8"></script>
<script>
hljs.initHighlightingOnLoad();
</script>
</head>
<body>
<div class="container" id="VS">
<h1>VisualSearch.js</h1>
<p class="attribution">
<i>
Created by <a href="http://github.com/samuelclay">Samuel Clay</a>,
<a href="http://twitter.com/samuelclay">@samuelclay</a>.
</i>
</p>
<p>
<a href="http://github.com/documentcloud/visualsearch">VisualSearch.js</a>
enhances ordinary search boxes with the ability to autocomplete
faceted search queries. Specify the facets for completion, along with the
completable values for any facet. You can retrieve the search query as a
structured object, so you don't have to parse the query string yourself.
</p>
<p>
<a href="https://www.documentcloud.org/public/#search/group%3A%20dcloud%20chair%3A%20%22Christopher%20Dodd%22%20TARP">Here's an example of a search on DocumentCloud.org that uses facets.</a>
</p>
<p>
The project is
<a href="http://github.com/documentcloud/visualsearch/">hosted on GitHub</a>.
You can report bugs and discuss features on the
<a href="http://github.com/documentcloud/visualsearch/issues">issues page</a>,
on Freenode in the <tt>#documentcloud</tt> channel,
or send tweets to <a href="http://twitter.com/documentcloud">@documentcloud</a>.
</p>
<p>
<i>VisualSearch.js is an open-source component of <a href="http://documentcloud.org/">DocumentCloud</a>.
<br />
<a href="docs/visualsearch.html">The complete annotated source code</a>
is also available.</i>
</p>
<h2>Table of Contents</h2>
<a href="#demo">Demo</a> | <a href="#downloads">Downloads</a> | <a href="#usage">Usage</a> | <a href="#changelog">Change Log</a>
<h2 id="demo">Demo <span class="demo-hint"><i>Try searching for: <b>account</b>, <b>filter</b>, <b>access</b>, <b>title</b>, <b>city</b>, <b>state</b>, or <b>country</b>.</i></span></h2>
<div id="search_box_container"></div>
<div id="search_query">&nbsp;</div>
<script type="text/javascript" charset="utf-8">
$(document).ready(function() {
var visualSearch = VS.init({
container : $('#search_box_container'),
query : 'country: "United States" state: "New York" account: 5-samuel title: "Pentagon Papers"',
unquotable : [
'text',
'account',
'filter',
'access'
],
callbacks : {
search : function(query, searchCollection) {
var $query = $('#search_query');
var count = searchCollection.size();
$query.stop().animate({opacity : 1}, {duration: 300, queue: false});
$query.html('<span class="raquo">&raquo;</span> You searched for: ' +
'<b>' + (query || '<i>nothing</i>') + '</b>. ' +
'(' + count + ' facet' + (count==1 ? '' : 's') + ')');
clearTimeout(window.queryHideDelay);
window.queryHideDelay = setTimeout(function() {
$query.animate({
opacity : 0
}, {
duration: 1000,
queue: false
});
}, 2000);
},
facetMatches : function(callback) {
callback([
'account', 'filter', 'access', 'title',
{ label: 'city', category: 'location' },
{ label: 'country', category: 'location' },
{ label: 'state', category: 'location' },
]);
},
valueMatches : function(facet, searchTerm, callback) {
switch (facet) {
case 'account':
callback([
{ value: '1-amanda', label: 'Amanda' },
{ value: '2-aron', label: 'Aron' },
{ value: '3-eric', label: 'Eric' },
{ value: '4-jeremy', label: 'Jeremy' },
{ value: '5-samuel', label: 'Samuel' },
{ value: '6-scott', label: 'Scott' }
]);
break;
case 'filter':
callback(['published', 'unpublished', 'draft']);
break;
case 'access':
callback(['public', 'private', 'protected']);
break;
case 'title':
callback([
'Pentagon Papers',
'CoffeeScript Manual',
'Laboratory for Object Oriented Thinking',
'A Repository Grows in Brooklyn'
]);
break;
case 'city':
callback([
'Cleveland',
'New York City',
'Brooklyn',
'Manhattan',
'Queens',
'The Bronx',
'Staten Island',
'San Francisco',
'Los Angeles',
'Seattle',
'London',
'Portland',
'Chicago',
'Boston'
]);
break;
case 'state':
callback([
"Alabama", "Alaska", "Arizona", "Arkansas", "California",
"Colorado", "Connecticut", "Delaware", "District of Columbia", "Florida",
"Georgia", "Guam", "Hawaii", "Idaho", "Illinois",
"Indiana", "Iowa", "Kansas", "Kentucky", "Louisiana",
"Maine", "Maryland", "Massachusetts", "Michigan", "Minnesota",
"Mississippi", "Missouri", "Montana", "Nebraska", "Nevada",
"New Hampshire", "New Jersey", "New Mexico", "New York", "North Carolina",
"North Dakota", "Ohio", "Oklahoma", "Oregon", "Pennsylvania",
"Puerto Rico", "Rhode Island", "South Carolina", "South Dakota", "Tennessee",
"Texas", "Utah", "Vermont", "Virginia", "Virgin Islands",
"Washington", "West Virginia", "Wisconsin", "Wyoming"
]);
break;
case 'country':
callback([
"China", "India", "United States", "Indonesia", "Brazil",
"Pakistan", "Bangladesh", "Nigeria", "Russia", "Japan",
"Mexico", "Philippines", "Vietnam", "Ethiopia", "Egypt",
"Germany", "Turkey", "Iran", "Thailand", "D. R. of Congo",
"France", "United Kingdom", "Italy", "Myanmar", "South Africa",
"South Korea", "Colombia", "Ukraine", "Spain", "Tanzania",
"Sudan", "Kenya", "Argentina", "Poland", "Algeria",
"Canada", "Uganda", "Morocco", "Iraq", "Nepal",
"Peru", "Afghanistan", "Venezuela", "Malaysia", "Uzbekistan",
"Saudi Arabia", "Ghana", "Yemen", "North Korea", "Mozambique",
"Taiwan", "Syria", "Ivory Coast", "Australia", "Romania",
"Sri Lanka", "Madagascar", "Cameroon", "Angola", "Chile",
"Netherlands", "Burkina Faso", "Niger", "Kazakhstan", "Malawi",
"Cambodia", "Guatemala", "Ecuador", "Mali", "Zambia",
"Senegal", "Zimbabwe", "Chad", "Cuba", "Greece",
"Portugal", "Belgium", "Czech Republic", "Tunisia", "Guinea",
"Rwanda", "Dominican Republic", "Haiti", "Bolivia", "Hungary",
"Belarus", "Somalia", "Sweden", "Benin", "Azerbaijan",
"Burundi", "Austria", "Honduras", "Switzerland", "Bulgaria",
"Serbia", "Israel", "Tajikistan", "Hong Kong", "Papua New Guinea",
"Togo", "Libya", "Jordan", "Paraguay", "Laos",
"El Salvador", "Sierra Leone", "Nicaragua", "Kyrgyzstan", "Denmark",
"Slovakia", "Finland", "Eritrea", "Turkmenistan"
], {preserveOrder: true});
break;
}
}
}
});
});
</script>
<h2 id="downloads">Downloads <i style="padding-left: 12px; font-size:12px;">(Right-click, and use "Save As")</i></h2>
<table class="downloads">
<tr>
<th colspan="2">0. Everything (<tt>visualsearch.zip</tt>)</th>
</tr>
<tr>
<td><a href="https://github.com/documentcloud/visualsearch/zipball/master">Download everything</a></td>
</tr>
<tr>
<th colspan="2">1. VisualSearch JavaScript (<tt>visualsearch.js</tt>)</th>
</tr>
<tr>
<td><a href="build-min/visualsearch.js">Production Version (0.2.2)</a></td>
<td><i>8kb, Minified and Gzipped</i></td>
</tr>
<tr>
<td><a href="build/visualsearch.js">Development Version (0.2.2)</a></td>
<td><i>45kb, Uncompressed with Comments</i></td>
</tr>
<tr>
<th colspan="2">2. VisualSearch Stylesheets (<tt>visualsearch.css</tt>)</th>
</tr>
<tr>
<td colspan="2"><i>You should include both the datauri and image urls versions. <a href="#css">See how to include both</a></i></td>
</tr>
<tr>
<td><a href="build-min/visualsearch-datauri.css">Production Version - datauri</a></td>
<td><i>4kb, Minified and Gzipped</i></td>
</tr>
<tr>
<td><a href="build-min/visualsearch.css">Production Version - image urls</a></td>
<td><i>4kb, Minified and Gzipped</i></td>
</tr>
<tr>
<td><a href="build/visualsearch.css">Development Version</a></td>
<td><i>8kb, Uncompressed with Comments</i></td>
</tr>
<tr>
<th colspan="2">3. VisualSearch Images</th>
</tr>
<tr>
<td><img src="lib/images/embed/icons/search_glyph.png"> <a href="lib/images/embed/icons/search_glyph.png">Search Glyph</a></td>
<td><i>4kb, embedded in visualsearch-datauri.css</i></td>
</tr>
<tr>
<td><img src="lib/images/embed/icons/cancel_search.png"> <a href="lib/images/embed/icons/cancel_search.png">Cancel Button</a></td>
<td><i>4kb, embedded in visualsearch-datauri.css</i></td>
</tr>
<tr>
<th colspan="2">4. VisualSearch Dependencies (<tt>jQuery 1.4+, jQuery UI, Underscore.js, Backbone.js</tt>)</th>
</tr>
<tr>
<td colspan="2"><i>You should only include the dependencies you don't already have.</i></td>
</tr>
<tr>
<td><a href="build-min/dependencies.js">Production Version - All</a></td>
<td><i>49kb, Minified and Gzipped</i></td>
</tr>
<tr>
<td><a href="build/dependencies.js">Development Version - All</a></td>
<td><i>340kb, Uncompressed with Comments</i></td>
</tr>
<tr>
<td><a href="vendor/jquery-1.6.1.js">jQuery 1.6.1</a></td>
<td><i>238kb, Uncompressed with Comments</i></td>
</tr>
<tr>
<td>jQuery UI 1.8.13: <br /><a href="vendor/jquery.ui.core.js">Core</a> <a href="vendor/jquery.ui.position.js">Position</a> <a href="vendor/jquery.ui.widget.js">Widget</a> <a href="vendor/jquery.ui.autocomplete.js">Autocomplete</a></td>
<td><i>48kb, Uncompressed with Comments</i></td>
</tr>
<tr>
<td><a href="vendor/underscore-1.1.5.js">Underscore 1.1.5</a></td>
<td><i>29kb, Uncompressed with Comments</i></td>
</tr>
<tr>
<td><a href="vendor/backbone-0.5.0.js">Backbone 0.5.0</a></td>
<td><i>41kb, Uncompressed with Comments</i></td>
</tr>
</table>
<h2 id="usage">Usage</h2>
<p>To use VisualSearch.js on your site, follow these instructions on installation, configuration, and customization.</p>
<ol>
<li class="xml" id="css">Insert the JavaScript and CSS into your page:<br />
<pre><code>&lt;script src="visualsearch.js" type="text/javascript"&gt;&lt;/script&gt;
&lt;!--[if (!IE)|(gte IE 8)]&gt;&lt;!--&gt;
&lt;link href="visualsearch-datauri.css" media="screen" rel="stylesheet" type="text/css" /&gt;
&lt;!--&lt;![endif]--&gt;
&lt;!--[if lte IE 7]&gt;&lt;!--&gt;
&lt;link href="visualsearch.css" media="screen" rel="stylesheet" type="text/css" /&gt;
&lt;!--&lt;![endif]--&gt;</code></pre>
</li>
<li>Initialize the Visual Search box:<br />
<pre class="javascript"><code>&lt;div class="visual_search"&gt;&lt;/div&gt;
&lt;script type="text/javascript" charset="utf-8"&gt;
$(document).ready(function() {
var visualSearch = VS.init({
container : $('.visual_search'),
query : '',
callbacks : {
search : function(query, searchCollection) {},
facetMatches : function(callback) {},
valueMatches : function(facet, searchTerm, callback) {}
}
});
});
&lt;/script&gt;</code></pre>
</li>
<li class="javascript">Customize the autocompleted facets and values:
<pre><code>callbacks : {
...
// These are the facets that will be autocompleted in an empty input.
facetMatches : function(callback) {
callback([
'account', 'filter', 'access', 'title',
{ label: 'city', category: 'location' },
{ label: 'address', category: 'location' },
{ label: 'country', category: 'location' },
{ label: 'state', category: 'location' },
]);
}
...
// These are the values that match specific categories, autocompleted
// in a category's input field. searchTerm can be used to filter the
// list on the server-side, prior to providing a list to the widget.
valueMatches : function(facet, searchTerm, callback) {
switch (facet) {
case 'account':
callback([
{ value: '1-amanda', label: 'Amanda' },
{ value: '2-aron', label: 'Aron' },
{ value: '3-eric', label: 'Eric' },
{ value: '4-jeremy', label: 'Jeremy' },
{ value: '5-samuel', label: 'Samuel' },
{ value: '6-scott', label: 'Scott' }
]);
break;
case 'filter':
callback(['published', 'unpublished', 'draft']);
break;
case 'access':
callback(['public', 'private', 'protected']);
break;
case 'title':
callback([
'Pentagon Papers',
'CoffeeScript Manual',
'Laboratory for Object Oriented Thinking',
'A Repository Grows in Brooklyn'
]);
break;
}
}
...
}</code></pre>
</li>
<li class="javascript">Inspect the Visual Search box
<pre><code>// Returns the unstructured search query
visualSearch.searchBox.value()
// "country: "South Africa" account: 5-samuel title: "Pentagon Papers""
// Returns an array of Facet model instances
visualSearch.searchQuery.facets()
// [FacetModel&lt;country:"South Africa">,
// FacetModel&lt;account:5-samuel>,
// FacetModel&lt;title:"Pentagon Papers">]
// Set the search query with raw text
visualSearch.searchBox.value("Country: US State: \"New York\" Key: Value")
</code></pre>
</li>
</ol>
<h2 id="changelog">Change Log</h2>
<p>
<b class="header">0.2.2</b> <i>March 10th, 2012</i><br />
If you do not want to automatically filter the value matches, you can pass an
options hash with <tt>preserveMatches: true</tt> as the second argument to the callback.
<a href="https://github.com/documentcloud/visualsearch/pull/44">See pull request #44</a> for details.
</p>
<p>
<b class="header">0.2.1</b> <i>November 14th, 2011</i><br />
The autocompleted facets and values that are provided by your callbacks <tt>facetMatches</tt>
and <tt>valueMatches</tt> can now preserve the order of items you give them. Simply pass an
options hash with <tt>preserveOrder: true</tt> as the second argument to the callback. See
<a href="demo.html">the demo page</a> for an example.
</p>
<p>
<b class="header">0.2.0</b> <i>August 10th, 2011</i><br />
Multiple instances of VisualSearch on a single page. <tt>VS.init</tt> now returns
a reference to the instance. The <tt>search</tt> callback now contains both the
serialized search query and a reference to the search query collection (as a
<a href="http://documentcloud.github.com/backbone/#Collection">Backbone.Collection</a>),
which can be used to manipulate each facet directly. See
<a href="docs/search_query.html">the source code for search_query.js</a> for available
methods on the collection.
</p>
<p>
<b class="header">0.1.0</b> <i>June 23rd, 2011</i><br />
Initial release of VisualSearch.js.
</p>
<p>
<a href="http://documentcloud.org/" title="A DocumentCloud Project" style="background:none;">
<img src="http://jashkenas.s3.amazonaws.com/images/a_documentcloud_project.png" alt="A DocumentCloud Project" />
</a>
</p>
</div>
</body>
</html>

View File

@ -30,7 +30,7 @@
border-radius: 3px;
-moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(255, 255, 255, 0.8) inset;
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(255, 255, 255, 0.8) inset;
-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(255, 255, 255, 0.8) inset;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(255, 255, 255, 0.8) inset;
text-shadow: 0 1px 1px rgba(255, 255, 255, 0.5);
-webkit-font-smoothing: antialiased;
outline: none;
@ -56,7 +56,7 @@
background-image: linear-gradient(to bottom, #f6f6f6, #e3e3e3);
-moz-box-shadow: 0 0 3px #80bfff, 0 1px 1px rgba(255, 255, 255, 0.8) inset;
-webkit-box-shadow: 0 0 3px #80bfff, 0 1px 1px rgba(255, 255, 255, 0.8) inset;
-box-shadow: 0 0 3px #80bfff, 0 1px 1px rgba(255, 255, 255, 0.8) inset;
box-shadow: 0 0 3px #80bfff, 0 1px 1px rgba(255, 255, 255, 0.8) inset;
}
.openerp2 a.button:active, .openerp2 a.button.active, .openerp2 button:active, .openerp2 button.active, .openerp2 input[type='submit']:active, .openerp2 input[type='submit'].active {
background: #e3e3e3;
@ -65,14 +65,14 @@
background: linear-gradient(top, #e3e3e3, #f6f6f6) #1b468f;
-moz-box-shadow: none;
-webkit-box-shadow: none;
-box-shadow: none;
box-shadow: none;
}
.openerp2 a.button.disabled, .openerp2 button:disabled, .openerp2 input[type='submit']:disabled {
background: #efefef !important;
border: 1px solid #d1d1d1 !important;
-moz-box-shadow: none !important;
-webkit-box-shadow: none !important;
-box-shadow: none !important;
box-shadow: none !important;
color: #aaaaaa !important;
cursor: default;
text-shadow: 0 1px 1px white !important;
@ -88,7 +88,7 @@
background-image: linear-gradient(to bottom, #dc5f59, #b33630);
-moz-box-shadow: none;
-webkit-box-shadow: none;
-box-shadow: none;
box-shadow: none;
}
.openerp2 button.primary:hover {
background-color: #df6b66;
@ -100,7 +100,7 @@
background-image: linear-gradient(to bottom, #df6b66, #bf3a33);
-moz-box-shadow: 0 0 1px rgba(0, 0, 0, 0.2);
-webkit-box-shadow: 0 0 1px rgba(0, 0, 0, 0.2);
-box-shadow: 0 0 1px rgba(0, 0, 0, 0.2);
box-shadow: 0 0 1px rgba(0, 0, 0, 0.2);
}
.openerp2 button.primary:active {
background-color: #b33630;
@ -112,7 +112,7 @@
background-image: linear-gradient(to bottom, #b33630, #dc5f59);
-moz-box-shadow: none;
-webkit-box-shadow: none;
-box-shadow: none;
box-shadow: none;
}
.openerp2 button.following {
color: white;
@ -254,7 +254,7 @@
color: white;
-moz-box-shadow: 0 1px 2px rgba(255, 255, 255, 0.3) inset;
-webkit-box-shadow: 0 1px 2px rgba(255, 255, 255, 0.3) inset;
-box-shadow: 0 1px 2px rgba(255, 255, 255, 0.3) inset;
box-shadow: 0 1px 2px rgba(255, 255, 255, 0.3) inset;
}
.openerp2 .oe_topbar .oe_topbar_item .oe_active {
background: #303030;
@ -262,7 +262,7 @@
color: white;
-moz-box-shadow: 0 1px 2px rgba(255, 255, 255, 0.3) inset;
-webkit-box-shadow: 0 1px 2px rgba(255, 255, 255, 0.3) inset;
-box-shadow: 0 1px 2px rgba(255, 255, 255, 0.3) inset;
box-shadow: 0 1px 2px rgba(255, 255, 255, 0.3) inset;
}
.openerp2 .oe_topbar .oe_topbar_avatar {
width: 24px;
@ -325,7 +325,7 @@
border-radius: 0 0 6px 6px;
-moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
-webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
-webkit-background-clip: padding-box;
-moz-background-clip: padding-box;
background-clip: padding-box;
@ -353,7 +353,7 @@
background-image: linear-gradient(to bottom, #292929, #191919);
-moz-box-shadow: none;
-webkit-box-shadow: none;
-box-shadow: none;
box-shadow: none;
}
.openerp2 .oe_leftbar {
width: 220px;
@ -413,7 +413,7 @@
color: white;
-moz-box-shadow: 0 1px 2px rgba(255, 255, 255, 0.3) inset;
-webkit-box-shadow: 0 1px 2px rgba(255, 255, 255, 0.3) inset;
-box-shadow: 0 1px 2px rgba(255, 255, 255, 0.3) inset;
box-shadow: 0 1px 2px rgba(255, 255, 255, 0.3) inset;
}
.openerp2 .oe_menu .oe_active {
background: #303030;
@ -421,7 +421,7 @@
color: white;
-moz-box-shadow: 0 1px 2px rgba(255, 255, 255, 0.3) inset;
-webkit-box-shadow: 0 1px 2px rgba(255, 255, 255, 0.3) inset;
-box-shadow: 0 1px 2px rgba(255, 255, 255, 0.3) inset;
box-shadow: 0 1px 2px rgba(255, 255, 255, 0.3) inset;
}
.openerp2 .oe_menu_more_container {
position: relative;
@ -477,7 +477,7 @@
border-radius: 4px;
-moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.2);
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.2);
-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.2);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.2);
}
.openerp2 .oe_secondary_submenu .oe_active {
background: #8a89ba;
@ -486,7 +486,7 @@
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
-moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.2);
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.2);
-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.2);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.2);
}
.openerp2 .oe_secondary_submenu .oe_active a {
color: white;
@ -497,7 +497,7 @@
text-shadow: 0 1px 1px white;
-moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
-webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
}
.openerp2 .oe_secondary_submenu .oe_menu_toggler:before {
width: 0;
@ -626,7 +626,7 @@
border: 1px solid #afafb6;
-moz-box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
-webkit-box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
-box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
}
.openerp2 .oe_form_header {
padding: 4px 16px;
@ -750,7 +750,7 @@
border-radius: 3px;
-moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
-webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
}
.openerp2 .oe_dropdown_menu li {
list-style-type: none;
@ -778,7 +778,7 @@
background-image: linear-gradient(to bottom, #f0f0fa, #eeeef6);
-moz-box-shadow: none;
-webkit-box-shadow: none;
-box-shadow: none;
box-shadow: none;
}
.openerp2 .oe_kanban_group_title {
margin: 1px 1px 4px;
@ -814,7 +814,7 @@
.openerp2 .oe_kanban_record:hover {
-moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.6);
-webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.6);
-box-shadow: 0 0 3px rgba(0, 0, 0, 0.6);
box-shadow: 0 0 3px rgba(0, 0, 0, 0.6);
}
.openerp2 .oe_kanban_record .oe_kanban_title {
font-weight: bold;
@ -828,7 +828,7 @@
border-radius: 3px;
-moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
}
.openerp2 .oe_application a {
color: #8a89ba;
@ -836,6 +836,178 @@
.openerp2 .oe_application a:hover {
text-decoration: underline;
}
.openerp2 .oe_searchview {
position: relative;
}
.openerp2 .oe_searchview .VS-search .VS-search-box {
min-height: 0;
border-width: 1px;
padding: 0;
}
.openerp2 .oe_searchview .VS-search .VS-icon {
top: 5px;
}
.openerp2 .oe_searchview .VS-search .VS-icon-search {
left: 5px;
}
.openerp2 .oe_searchview .VS-search .VS-search-inner {
margin: 0 40px 0 17px;
font-size: 13px;
}
.openerp2 .oe_searchview .VS-search .VS-search-inner input {
font-size: inherit;
line-height: inherit;
height: auto;
padding: 0;
}
.openerp2 .oe_searchview .VS-search .VS-search-inner .VS-input-width-tester {
font-size: inherit;
padding: 0;
}
.openerp2 .oe_searchview .VS-search .VS-search-inner .search_input {
margin-left: 0;
height: 22px;
}
.openerp2 .oe_searchview .VS-search .VS-search-inner .search_input input, .openerp2 .oe_searchview .VS-search .VS-search-inner .search_input .VS-input-width-tester {
padding: 0 2px;
height: inherit;
margin: 0;
}
.openerp2 .oe_searchview .VS-search .VS-search-inner .search_facet {
padding: 0;
margin: 1px 0;
border: 1px solid #afafb6;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border-radius: 3px;
background: #f0f0fa;
height: 18px;
}
.openerp2 .oe_searchview .VS-search .VS-search-inner .search_facet.is_selected {
border-color: #a6a6fe;
-moz-box-shadow: 0 0 3px 1px #a6a6fe;
-webkit-box-shadow: 0 0 3px 1px #a6a6fe;
box-shadow: 0 0 3px 1px #a6a6fe;
}
.openerp2 .oe_searchview .VS-search .VS-search-inner .search_facet.is_selected .category {
margin-left: 0;
}
.openerp2 .oe_searchview .VS-search .VS-search-inner .search_facet.is_selected .VS-icon-cancel {
filter: alpha(opacity=100);
opacity: 1;
background-position: center 0;
}
.openerp2 .oe_searchview .VS-search .VS-search-inner .search_facet .category {
padding: 0 4px 0 14px;
color: white;
background: #8786b7;
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.4);
font-weight: normal;
text-transform: none;
height: 18px;
line-height: 18px;
font-size: inherit;
}
.openerp2 .oe_searchview .VS-search .VS-search-inner .search_facet .search_facet_input_container {
border-left: 1px solid #afafb6;
height: 18px;
line-height: 18px;
padding: 0 4px;
cursor: pointer;
}
.openerp2 .oe_searchview .VS-search .VS-search-inner .search_facet .search_facet_remove {
left: 1px;
top: 3px;
}
.openerp2 .oe_searchview .VS-search .VS-icon-cancel {
right: 24px;
}
.openerp2 .oe_searchview .VS-search .oe_vs_unfold_drawer {
position: absolute;
top: 0;
right: 0;
height: 100%;
line-height: 23px;
padding: 0 7px 0 4px;
color: #cccccc;
cursor: pointer;
}
.openerp2 .oe_searchview .VS-search .oe_vs_unfold_drawer:before {
content: "▾";
}
.openerp2 .oe_searchview.oe_searchview_open_drawer .oe_searchview_drawer {
display: block;
}
.openerp2 .oe_searchview .oe_searchview_drawer {
position: absolute;
top: 100%;
right: 0;
background-color: white;
width: 500px;
display: none;
border: 1px solid #cccccc;
}
.openerp2 .oe_searchview .oe_searchview_drawer .oe_searchview_filters {
display: table;
width: 100%;
}
.openerp2 .oe_searchview .oe_searchview_drawer .oe_searchview_filters > div {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
display: table-cell;
width: 50%;
}
.openerp2 .oe_searchview .oe_searchview_drawer .oe_searchview_filters h3 {
margin: 2px 4px 2px 8px;
color: #8786b7;
}
.openerp2 .oe_searchview .oe_searchview_drawer .oe_searchview_filters ul {
margin: 0 12px 3px;
padding: 0;
list-style: none;
}
.openerp2 .oe_searchview .oe_searchview_drawer .oe_searchview_filters li {
list-style: none;
padding: 3px 6px;
height: 14px;
color: inherit;
cursor: pointer;
}
.openerp2 .oe_searchview .oe_searchview_drawer .oe_searchview_filters li:hover {
background-color: #f0f0fa;
}
.openerp2 .oe_searchview .oe_searchview_drawer .oe_searchview_advanced h4 {
border-top: 1px solid #cccccc;
margin: 5px 0 3px;
cursor: pointer;
}
.openerp2 .oe_searchview .oe_searchview_drawer .oe_searchview_advanced h4:before {
content: "▸ ";
}
.openerp2 .oe_searchview .oe_searchview_drawer .oe_searchview_advanced div {
display: none;
}
.openerp2 .oe_searchview .oe_searchview_drawer .oe_searchview_advanced button.oe_add_condition:before {
content: "⊞ ";
}
.openerp2 .oe_searchview .oe_searchview_drawer .oe_searchview_advanced button.oe_apply:before {
content: "⚡ ";
}
.openerp2 .oe_searchview .oe_searchview_drawer .oe_searchview_advanced ul {
list-style: none;
padding: 0;
}
.openerp2 .oe_searchview .oe_searchview_drawer .oe_searchview_advanced li {
list-style: none;
margin: 0;
}
.openerp2 .oe_searchview .oe_searchview_drawer .oe_searchview_advanced.oe_opened h4:before {
content: "▾ ";
}
.openerp2 .oe_searchview .oe_searchview_drawer .oe_searchview_advanced.oe_opened div {
display: block;
}
.openerp .oe_form_field_many2one td:first-child {
position: relative;

View File

@ -1,5 +1,8 @@
// Variables {{{
$section-title-color: #8786b7
$facets-border: #afafb6
$facets-border-selected: #a6a6fe
$colour4: #8a89ba
//$colour4: #d14836
// }}}
@ -29,7 +32,7 @@ $colour4: #8a89ba
@mixin box-shadow($bsval: 0px 1px 4px #777)
-moz-box-shadow: $bsval
-webkit-box-shadow: $bsval
-box-shadow: $bsval
box-shadow: $bsval
@mixin transition($transval: (border linear 0.2s, box-shadow linear 0.2s))
-webkit-transition: $transval
@ -46,6 +49,12 @@ $colour4: #8a89ba
-webkit-background-clip: $clip
-moz-background-clip: $clip
background-clip: $clip
@mixin unscrew-box
-moz-box-sizing: border-box
-webkit-box-sizing: border-box
box-sizing: border-box
// }}}
.openerp2
@ -697,6 +706,172 @@ $colour4: #8a89ba
text-decoration: underline
// }}}
// Search View {{{
.oe_searchview
position: relative
.VS-search
.VS-search-box
min-height: 0
border-width: 1px
padding: 0
.VS-icon
top: 5px
.VS-icon-search
left: 5px
.VS-search-inner
margin: 0 40px 0 17px
font-size: 13px
input
font-size: inherit
line-height: inherit
height: auto
padding: 0
.VS-input-width-tester
font-size: inherit
padding: 0
.search_input
margin-left: 0
height: 22px
input, .VS-input-width-tester
padding: 0 2px
height: inherit
margin: 0
.search_facet
padding: 0
margin: 1px 0
border: 1px solid $facets-border
@include radius(3px)
background: #f0f0fa
height: 18px
&.is_selected
border-color: $facets-border-selected
@include box-shadow(0 0 3px 1px $facets-border-selected)
.category
margin-left: 0
.VS-icon-cancel
// don't change the icon on selection
@include opacity(1.0)
background-position: center 0
.category
padding: 0 4px 0 14px
color: white
background: #8786b7
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.4)
font-weight: normal
text-transform: none
height: 18px
line-height: 18px
font-size: inherit
.search_facet_input_container
border-left: 1px solid $facets-border
height: 18px
line-height: 18px
padding: 0 4px
cursor: pointer
.search_facet_remove
left: 1px
top: 3px
.VS-icon-cancel
right: 24px
.oe_vs_unfold_drawer
position: absolute
top: 0
right: 0
height: 100%
line-height: 23px
padding: 0 7px 0 4px
color: #ccc
cursor: pointer
&:before
content: ""
&.oe_searchview_open_drawer
.oe_searchview_drawer
display: block
.oe_searchview_drawer
position: absolute
top: 100%
right: 0
background-color: white
width: 500px
display: none
border: 1px solid #ccc
.oe_searchview_filters
display: table
width: 100%
> div
@include unscrew-box
display: table-cell
width: 50%
h3
margin: 2px 4px 2px 8px
color: $section-title-color
ul
margin: 0 12px 3px
padding: 0
list-style: none
li
list-style: none
padding: 3px 6px
height: 14px
color: inherit
cursor: pointer
&:hover
background-color: #f0f0fa
.oe_searchview_advanced
h4
border-top: 1px solid #ccc
margin: 5px 0 3px
cursor: pointer
h4:before
content: ""
div
display: none
button.oe_add_condition:before
content: ""
button.oe_apply:before
content: ""
ul
list-style: none
padding: 0
li
list-style: none
margin: 0
&.oe_opened
h4:before
content: ""
div
display: block
// }}}
// Transitional overrides for old styles {{{
.openerp
.oe_form_field_many2one

View File

@ -13,8 +13,6 @@ openerp.web.core = function(openerp) {
// a function to override the "extend()" method of JR's inheritance, allowing
// the usage of "include()"
// TODO: remove usage of include everywhere, not meant to be included in novajs because we don't
// include rotten cadavers in novajs
var oe_override_class = function(claz){
var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ?
/\b_super\b/ : /.*/;

File diff suppressed because it is too large Load Diff

View File

@ -1298,17 +1298,8 @@
</t>
</t>
<t t-name="SearchView">
<form class="oe_forms">
<t t-call="SearchView.render_lines"/>
<div class="oe_search-view-buttons">
<button class="oe_button">Search</button>
<button class="oe_button" type="reset">Clear</button>
<select class="oe_search-view-filters-management">
</select>
</div>
</form>
</t>
<div t-name="SearchView" class="oe_searchview"/>
<t t-name="SearchView.managed-filters">
<option class="oe-filters-title" value="">Filters</option>
<optgroup label="-- Filters --">
@ -1364,10 +1355,28 @@
<br t-if="attrs.string"/>
<t t-esc="attrs.string"/>
</button>
<span t-name="SearchView.filters" class="filter_label_group"
><t t-foreach="filters" t-as="filter"
><t t-raw="filter.render(defaults)"/></t
></span>
<ul t-name="SearchView.filters">
<li t-foreach="widget.filters" t-as="filter">
<t t-esc="filter.attrs.string or filter.attrs.name or 'Ω'"/>
</li>
</ul>
<t t-name="SearchView.filters.facet">
<div class="category oe_filter_category"><t t-esc="facet.get('category')"/></div>
<t t-set="val" t-value="facet.get('json')"/>
<div t-if="!(val instanceof Array)" class="search_facet_input_container">
<t t-esc="facet.get('value')"/>
</div>
<t t-if="val instanceof Array">
<div class="search_facet_input_container"
t-foreach="facet.get('json')" t-as="filter">
<t t-esc="filter.attrs.string || filter.attrs.name"/>
</div>
</t>
<div class="search_facet_remove VS-icon VS-icon-cancel"/>
</t>
<t t-name="SearchView.field">
<label t-att-class="'oe_label' + (attrs.help ? '_help' : '')"
t-att-title="attrs.help"
@ -1425,8 +1434,7 @@
</div>
</t>
<t t-name="SearchView.util.expand">
<div t-att-class="'searchview_group ' + (expand == '0' ? 'folded' : 'expanded')"
t-att-id="element_id">
<div t-att-class="'searchview_group ' + (expand == '0' ? 'folded' : 'expanded')">
<a t-if="label" class="searchview_group_string" href="#">
<t t-esc="label"/>
</a>
@ -1444,34 +1452,18 @@
</t>
</t>
</t>
<t t-name="SearchView.extended_search">
<t t-call="SearchView.util.expand">
<t t-set="expand" t-value="false"/>
<t t-set="label">Advanced Filters</t>
<t t-set="content">
<div class="searchview_extended_groups_list">
</div>
</t>
</t>
</t>
<t t-name="SearchView.extended_search.group">
<div t-att-id="widget.element_id" class="searchview_extended_group">
<select class="searchview_extended_group_choice">
<option value="any">Any of the following conditions must match</option>
<option value="all">All the following conditions must match</option>
<option value="none">None of the following conditions must match</option>
</select>
<a class="searchview_extended_delete_group"
href="javascript:void(0)"><span></span></a>
<div class="searchview_extended_propositions_list">
</div>
<a class="searchview_extended_add_proposition" href="javascript:void(0)">
<span>Add condition</span></a>
<div class="oe_adv_filters_and"><span>and</span></div>
</div>
</t>
<div t-name="SearchView.advanced" class="oe_searchview_advanced">
<h4>Advanced Search...</h4>
<form>
<ul>
</ul>
<button class="oe_add_condition" type="button">Add a condition</button>
<button class="oe_apply" type="submit">Apply</button>
</form>
</div>
<t t-name="SearchView.extended_search.proposition">
<div t-att-id="widget.element_id">
<li>
<select class="searchview_extended_prop_field">
<t t-foreach="widget.attrs.fields" t-as="field">
<option t-if="typeof field.store === 'undefined' || field.store || field.fnct_search"
@ -1485,7 +1477,7 @@
<span class="searchview_extended_prop_value"/>
<a class="searchview_extended_delete_prop"
href="javascript:void(0)"><span> </span></a>
</div>
</li>
</t>
<t t-name="SearchView.extended_search.proposition.char">
<input t-att-id="widget.element_id" class="field_char"/>

View File

@ -11,6 +11,8 @@ Contents:
.. toctree::
:maxdepth: 2
search-view
getting-started
production
widgets

311
doc/search-view.rst Normal file
View File

@ -0,0 +1,311 @@
Search View
===========
OpenERP Web 6.2 implements a unified facets-based search view instead
of the previous form-like search view (composed of buttons and
multiple fields). The goal for this change is twofold:
* Avoid the common issue of users confusing the search view with a
form view and trying to create their records through it (or entering
all their data, hitting the ``Create`` button expecting their record
to be created and losing everything).
* Improve the looks and behaviors of the view, and the fit within
OpenERP Web's new design.
The faceted search is implemented through a monkey-patched
`VisualSearch <http://documentcloud.github.com/visualsearch/>`_
[#]_. VisualSearch is based on `Backbone
<http://documentcloud.github.com/backbone/>`_ and makes significant
use of Backbone's models and views. As a result, understanding the
implementation of the OpenERP Web 6.2 search view also requires a
basic understanding of Backbone.
.. note::
This document may mention *fetching* data. This is a shortcut for
"returning a deferred to [whatever is being fetched]". Unless
further noted, the function or method may opt to return nothing by
fetching ``null`` (which can easily be done by returning
``$.when(null)``, which simply wraps the ``null`` in a Deferred).
Interaction between the Search View and VisualSearch
----------------------------------------------------
The core data abstraction in VisualSearch is
:js:class:`VS.model.SearchQuery`, a backbone Collection holding
instances of the :js:class:`VS.model.SearchFacet` backbone Model.
Backbone models can hold any number of informal properties interacted
with through the :js:func:`~Backbone.Model.get` and
:js:func:`~Backbone.Model.set` methods. VisualSearch reserves three
such properties for its behavior, these properties *must* be correctly
set on all search facets created programmatically:
``app``
a reference to the VisualSearch instance using this facet. In the
search view, this instance is available as the
:js:attr:`~openerp.web.SearchView.vs` attribute to the searchview
instance.
``category``
the *name* of the facet, displayed in the first section of a facet
view.
``value``
the *displayed value* of the facet, it is directly printed to the
right of the category.
The search view uses additional keys to store state and data it needs
to associate with facet objects:
``field``
the search field instance which created the facet, used when the
search view needs to serialize the facets.
``json``
the "logical" value of the facet, can be absent if the logical and
"printable" values of the facet are the same (e.g. for a basic text
field).
This value may be a complex javascript object such as an array (the
name stands for json-compatible value, it is not a JSON-encoded
string).
.. note::
in order to simplify getting the logical value of a search facet
model, :js:class:`VS.model.SearchFacet` has been extended with a
:js:func:`~VS.model.SearchFacet.value` method
Extensions and patches to VisualSearch
++++++++++++++++++++++++++++++++++++++
.. js:function:: VS.model.SearchFacet.value()
Bundles the logic of selecting between ``json`` and ``value`` in
order to get the logical value of a facet.
.. js:attribute:: VS.options.callbacks.make_facet
Called by :js:class:`VS.ui.SearchBox` when it needs to create a
new search facet *view*. By default this is not supported by
VisualSearch, and requires monkey-patching
:js:func:`VS.ui.SearchBox.renderFacet`.
This patch should not alter any behavior if
:js:attr:`~VS.options.callbacks.make_facet` is not used.
.. js:attribute:: VS.options.callbacks.make_input
Similar to :js:attr:`~VS.options.callbacks.make_facet`, but called
when the :js:class:`~VS.ui.SearchBox` needs to create a search
input view. It requires monkey-patching
:js:func:`VS.ui.SearchBox.renderSearchInput`.
Finally, :js:func:`VS.ui.SearchBox.searchEvent` is monkey-patched to
get rid of its serialize/load round-tripping of facet data: the
additional attributes needed by the search view don't round-trip (at
all) so VisualSearch must not load any data from its (fairly
simplistic) text-serialization format.
.. note::
a second issue is that — as of `commit 3fca87101d`_ — VisualSearch
correctly serializes facet categories containing spaces but is
unable to load them back in. It also does not handle facets with
*empty* categories correctly.
Loading Defaults
----------------
After loading the view data, the SearchView will call
:js:func:`openerp.web.search.Input.facet_for_defaults` on each of its
inputs with the ``defaults`` mapping of key:values (where each key
corresponds to an input). This method should look into the
``defaults`` mapping and fetch the field's default value as a
:js:class:`~VS.models.SearchFacet` if applicable.
The default implementation is to check if there is a default value for
the current input's name (via
:js:attr:`openerp.web.search.Input.attrs.name`) and if there is to
convert this value to a :js:class:`~VS.models.SearchFacet` by calling
:js:func:`openerp.web.search.Input.facet_for`.
There is no built-in (default) implementation of
:js:func:`openerp.web.search.Input.facet_for`. This method should
fetch the :js:class:`~VS.models.SearchFacet` corresponding to the
"raw" value passed as argument.
Providing auto-completion
-------------------------
An important component of the unified search view is the faceted
autocompletion pane. In order to provide good user and developer
experiences, this pane is pluggable (value-wise): each and every
control of the search view can check for (and provide) categorized
auto-completions for a given value being typed by the user.
This is done by implementing
:js:func:`openerp.web.search.Input.complete`: the method is provided
with a value to complete, and should fetch an ``Array`` of completion
values. These completion values will then be provided to the global
autocompletion list, implemented via `jquery-ui autocomplete
<http://jqueryui.com/demos/autocomplete/>`_.
Because the search view uses a custom renderer for its completion, it
was possible to fix some incompatibilities between the attributes of
completion items and VisualSearch's facet model:
Actual completion items
+++++++++++++++++++++++
These are selectable items, and upon selection are turned into actual
search facet objects. They should have all the properties of a search
facet (as described above) and can have one more optional property:
``label``.
When rendering an item in the list, the renderer will first try to use
the ``label`` property if it exists (``label`` can contain HTML and
will be inserted as-is, so it can bold or emphasize some of its
elements), if it does not the ``value`` property will be used.
.. note:: the ``app`` key should not be specified on completion item,
it will be set automatically when the search view creates
the facet from the item.
Section titles
++++++++++++++
A second kind of completion values is the section titles. Section
titles are similar to completion items but only have a ``category``
property. They will be rendered in a different style and can not be
selected in the auto-completion (they will be skipped).
.. note::
Technically, section title items can have any property they want
*as long as they do not have a value property*. A ``value``
property set to ``false``, ``null`` or ``undefined`` is **not**
equivalent to not having a ``value`` property.
If an input *may* fetch more than one completion item, it *should*
prepend a section title (using its own name) to the completion items.
Converting from facet objects
-----------------------------
Ultimately, the point of the search view is to allow searching. In
OpenERP this is done via :ref:`domains <openerpserver:domains>`. On
the other hand, the OpenERP Web 6.2 search view's state is modelled
after a collection of :js:class:`~VS.model.SearchFacet`, and each
field of a search view may have special requirements when it comes to
the domains it produces [#]_.
So there needs to be some way of mapping
:js:class:`~VS.model.SearchFacet` objects to OpenERP search data.
This is done via an input's
:js:func:`~openerp.web.search.Input.get_domain` and
:js:func:`~openerp.web.search.Input.get_context`. Each takes a
:js:class:`~VS.model.SearchFacet` and returns whatever it's supposed
to generate (a domain or a context, respectively). Either can return
``null`` if the current value does not map to a domain or context, and
can throw an :js:class:`~openerp.web.search.Invalid` exception if the
value is not valid at all for the field.
Converting to facet objects
---------------------------
Changes
-------
.. todo:: merge in changelog instead
The displaying of the search view was significantly altered from
OpenERP Web 6.1 to OpenERP Web 6.2.
As a result, while the external API used to interact with the search
view does not change many internal details — including the interaction
between the search view and its widgets — were significantly altered:
Internal operations
+++++++++++++++++++
* :js:func:`openerp.web.SearchView.do_clear` has been removed
* :js:func:`openerp.web.SearchView.do_toggle_filter` has been removed
Widgets API
+++++++++++
* :js:func:`openerp.web.search.Widget.render` has been removed
* :js:func:`openerp.web.search.Widget.make_id` has been removed
* Search field objects are not openerp widgets anymore, their
``start`` is not generally called
* :js:func:`~openerp.web.search.Input.clear` has been removed since
clearing the search view now simply consists of removing all search
facets from VisualSearch
* :js:func:`~openerp.web.search.Input.get_domain` and
:js:func:`~openerp.web.search.Input.get_context` now take a
:js:class:`~VS.model.SearchFacet` as parameter, from which it's
their job to get whatever value they want
* :js:func:`~openerp.web.search.Input.get_groupby` has been added. It returns
an :js:class:`Array` of context-like constructs. By default, it does not do
anything in :js:class:`~openerp.web.search.Field` and it returns the various
contexts of its enabled filters in
:js:class:`~openerp.web.search.FilterGroup`.
Filters
+++++++
* :js:func:`openerp.web.search.Filter.is_enabled` has been removed
* :js:class:`~openerp.web.search.FilterGroup` instances are still
rendered (and started) in the "advanced search" drawer.
Fields
++++++
* ``get_value`` now takes a :js:class:`~VS.model.SearchFacet` (instead
of taking no argument).
A default implementation is provided as
:js:func:`openerp.web.search.Field.get_value` and simply calls
:js:func:`VS.model.SearchFacet.value`.
* The third argument to
:js:func:`~openerp.web.search.Field.make_domain` is now the
:js:class:`~VS.model.SearchFacet` received by
:js:func:`~openerp.web.search.Field.get_domain`, so child classes
have all the information they need to derive the "right" resulting
domain.
Custom filters
++++++++++++++
Instead of being an intrinsic part of the search view, custom filters
are now a special case of filter groups. They are treated specially
still, but much less so than they used to be.
Many To One
+++++++++++
* Because the autocompletion service is now provided by the search
view itself,
:js:func:`openerp.web.search.ManyToOneField.setup_autocomplete` has
been removed.
.. [#] the library code is untouched, all patching is performed in the
Search view's implementation module. Changes to the
VisualSearch code should only update the library to new
revisions or releases.
.. [#] search view fields may also bundle context data to add to the
search context
.. _commit 3fca87101d:
https://github.com/documentcloud/visualsearch/commit/3fca87101d