merge trunk

bzr revid: nicolas.vanhoren@openerp.com-20120524115141-d8tgll1dl7fsbz0o
This commit is contained in:
niv-openerp 2012-05-24 13:51:41 +02:00
commit c6b01a2c03
34 changed files with 4094 additions and 5281 deletions

View File

@ -36,19 +36,6 @@
"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/src/js/boot.js",
@ -74,9 +61,6 @@
"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

@ -1287,25 +1287,6 @@ class SearchView(View):
del filter['domain']
return filters
@openerpweb.jsonrequest
def save_filter(self, req, model, name, context_to_save, domain):
Model = req.session.model("ir.filters")
ctx = common.nonliterals.CompoundContext(context_to_save)
ctx.session = req.session
ctx = ctx.evaluate()
domain = common.nonliterals.CompoundDomain(domain)
domain.session = req.session
domain = domain.evaluate()
uid = req.session._uid
context = req.session.eval_context(req.context)
to_return = Model.create_or_replace({"context": ctx,
"domain": domain,
"model_id": model,
"name": name,
"user_id": uid
}, context)
return to_return
@openerpweb.jsonrequest
def add_to_dashboard(self, req, menu_id, action_id, context_to_save, domain, view_mode, name=''):
ctx = common.nonliterals.CompoundContext(context_to_save)

View File

@ -4,7 +4,7 @@
// TODO: t-set + t-value + children node == scoped variable ?
var QWeb2 = {
expressions_cache: {},
RESERVED_WORDS: 'true,false,NaN,null,undefined,debugger,console,in,instanceof,new,function,return,this,typeof,eval,Math,RegExp,Array,Object,Date'.split(','),
RESERVED_WORDS: 'true,false,NaN,null,undefined,debugger,console,in,instanceof,new,function,return,this,typeof,eval,void,Math,RegExp,Array,Object,Date'.split(','),
ACTIONS_PRECEDENCE: 'foreach,if,call,set,esc,escf,raw,rawf,js,debug,log'.split(','),
WORD_REPLACEMENT: {
'and': '&&',

View File

@ -1,22 +0,0 @@
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

@ -1,16 +0,0 @@
__ ___ _ _____ _ _
\ \ / (_) | |/ ____| | | (_)
\ \ / / _ ___ _ _ __ _| | (___ ___ __ _ _ __ ___| |__ _ ___
\ \/ / | / __| | | |/ _` | |\___ \ / _ \/ _` | '__/ __| '_ \ | / __|
\ / | \__ \ |_| | (_| | |____) | __/ (_| | | | (__| | | |_| \__ \
\/ |_|___/\__,_|\__,_|_|_____/ \___|\__,_|_| \___|_| |_(_) |___/
_/ |
|__/
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

@ -1,37 +0,0 @@
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

@ -1,28 +0,0 @@
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

@ -1,310 +0,0 @@
.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

@ -1,310 +0,0 @@
.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

@ -1,453 +0,0 @@
<!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

@ -1,537 +0,0 @@
<!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

@ -517,6 +517,7 @@
border-right: 1px solid #afafb6;
text-shadow: 0 1px 1px white;
padding-bottom: 16px;
line-height: 18px;
}
.openerp a.oe_logo {
width: 220px;
@ -729,10 +730,6 @@
.openerp .oe_menu_more_container .oe_menu_more li a {
white-space: nowrap;
}
.oe_leftbar {
line-height: 18px;
}
.openerp .oe_secondary_menu_section {
font-weight: bold;
margin-left: 8px;
@ -1163,140 +1160,164 @@
white-space: nowrap;
}
.openerp .oe_searchview {
cursor: text;
position: relative;
float: right;
}
.openerp .oe_searchview .VS-search .VS-search-box {
min-height: 0;
padding: 0;
width: 480px;
padding-right: 20px;
width: 410px;
border: 1px solid #ababab;
-moz-border-radius: 13px;
-webkit-border-radius: 13px;
border-radius: 13px;
background: white;
-moz-border-radius: 1em;
-webkit-border-radius: 1em;
border-radius: 1em;
-moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2) inset;
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2) inset;
-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2) inset;
}
.openerp .oe_searchview .VS-search .VS-icon {
top: 6px;
.openerp .oe_searchview.oe_focused {
border-color: #a6a6fe;
-moz-box-shadow: 0 1px 2px #a6a6fe inset;
-webkit-box-shadow: 0 1px 2px #a6a6fe inset;
-box-shadow: 0 1px 2px #a6a6fe inset;
}
.openerp .oe_searchview .VS-search .VS-icon-search {
left: 2px;
top: 3px;
height: 18px;
width: 18px;
.openerp .oe_searchview .oe_searchview_clear {
cursor: pointer;
position: absolute;
top: 0;
right: 22px;
width: 15px;
height: 100%;
background: url(../img/attachments-close.png) center center no-repeat;
}
.openerp .oe_searchview .VS-search .VS-search-inner {
margin: 0 40px 0 17px;
padding: 1px 0;
font-size: 13px;
.openerp .oe_searchview .oe_searchview_unfold_drawer {
position: absolute;
top: 0;
right: 0;
height: 100%;
line-height: 2.5em;
padding: 0 7px 0 4px;
color: #cccccc;
cursor: pointer;
}
.openerp .oe_searchview .VS-search .VS-search-inner input {
font-size: inherit;
line-height: inherit;
height: auto;
padding: 0;
.openerp .oe_searchview .oe_searchview_unfold_drawer:hover {
color: #999999;
}
.openerp .oe_searchview .VS-search .VS-search-inner .VS-input-width-tester {
font-size: inherit;
padding: 0;
.openerp .oe_searchview .oe_searchview_unfold_drawer:before {
content: "◀";
}
.openerp .oe_searchview .VS-search .VS-search-inner .search_input {
margin-left: 0;
height: 22px;
.openerp .oe_searchview .oe_searchview_facets:before {
color: #cccccc;
font-family: "mnmliconsRegular";
content: "r";
font-size: 150%;
padding: 0 1px 0 3px;
display: inline;
}
.openerp .oe_searchview .VS-search .VS-search-inner .search_input input, .openerp .oe_searchview .VS-search .VS-search-inner .search_input .VS-input-width-tester {
height: inherit;
margin: 0;
.openerp .oe_searchview .oe_searchview_facets * {
vertical-align: top;
display: inline-block;
line-height: 26px;
}
.openerp .oe_searchview .VS-search .VS-search-inner .search_facet {
padding: 0;
margin: 1px 0;
.openerp .oe_searchview .oe_searchview_facets .oe_searchview_input, .openerp .oe_searchview .oe_searchview_facets .oe_searchview_facet {
height: 26px;
}
.openerp .oe_searchview .oe_searchview_facets .oe_searchview_input:focus, .openerp .oe_searchview .oe_searchview_facets .oe_searchview_facet:focus {
outline: none;
}
.openerp .oe_searchview .oe_searchview_facets .oe_searchview_input {
padding: 0 3px;
}
.openerp .oe_searchview .oe_searchview_facets .oe_searchview_facet {
position: relative;
cursor: pointer;
border: 1px solid #afafb6;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border-radius: 3px;
background: #f0f0fa;
height: 18px;
background: #8786b7;
-webkit-font-smoothing: auto;
padding-left: 1.1em;
margin: 1px 0;
}
.openerp .oe_searchview .VS-search .VS-search-inner .search_facet.is_selected {
.openerp .oe_searchview .oe_searchview_facets .oe_searchview_facet:focus {
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;
}
.openerp .oe_searchview .VS-search .VS-search-inner .search_facet.is_selected .category {
margin-left: 0;
.openerp .oe_searchview .oe_searchview_facets .oe_searchview_facet .oe_facet_values {
background: #f0f0fa;
-moz-border-radius: 0 3px 3px 0;
-webkit-border-radius: 0 3px 3px 0;
border-radius: 0 3px 3px 0;
}
.openerp .oe_searchview .VS-search .VS-search-inner .search_facet.is_selected .VS-icon-cancel {
filter: alpha(opacity=100);
opacity: 1;
background-position: center 0;
.openerp .oe_searchview .oe_searchview_facets .oe_searchview_facet .oe_facet_category, .openerp .oe_searchview .oe_searchview_facets .oe_searchview_facet .oe_facet_value {
height: 24px;
padding: 1px 0.1em;
}
.openerp .oe_searchview .VS-search .VS-search-inner .search_facet .category {
padding: 0 4px 0 14px;
.openerp .oe_searchview .oe_searchview_facets .oe_searchview_facet .oe_facet_category {
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;
}
.openerp .oe_searchview .VS-search .VS-search-inner .search_facet .search_facet_input_container {
.openerp .oe_searchview .oe_searchview_facets .oe_searchview_facet .oe_facet_value {
border-left: 1px solid #afafb6;
height: 18px;
line-height: 18px;
padding: 0 4px;
cursor: pointer;
}
.openerp .oe_searchview .VS-search .VS-search-inner .search_facet .search_facet_remove {
left: 1px;
top: 3px;
}
.openerp .oe_searchview .VS-search .VS-icon-cancel {
right: 24px;
}
.openerp .oe_searchview .VS-search .oe_vs_unfold_drawer {
.openerp .oe_searchview .oe_searchview_facets .oe_searchview_facet .oe_facet_remove {
position: absolute;
top: 0;
right: 0;
height: 100%;
line-height: 23px;
padding: 0 7px 0 4px;
color: #4c4c4c;
cursor: pointer;
left: 2px;
color: white;
}
.openerp .oe_searchview .VS-search .oe_vs_unfold_drawer:before {
position: absolute;
top: 9px;
right: 8px;
width: 0;
height: 0;
display: inline-block;
content: "";
vertical-align: top;
border-top: 5px solid #4c4c4c;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
filter: alpha(opacity=50);
opacity: 0.5;
.openerp .oe_searchview .oe_searchview_facets .oe_searchview_facet .oe_facet_remove:hover {
color: #cccccc;
}
.openerp .oe_searchview.oe_searchview_open_drawer .oe_searchview_drawer {
display: block;
}
.openerp .oe_searchview.oe_searchview_open_drawer .oe_searchview_unfold_drawer:before {
content: "▼";
}
.openerp .oe_searchview .oe_searchview_drawer {
position: absolute;
z-index: 1;
margin-top: 3px;
top: 100%;
right: 0;
background-color: white;
width: 480px;
min-width: 100%;
display: none;
border: 1px solid #cccccc;
text-align: left;
padding-bottom: 0.5em;
-moz-border-radius: 1em;
-webkit-border-radius: 1em;
border-radius: 1em;
}
.openerp .oe_searchview .oe_searchview_drawer > div {
border-top: 1px solid #cccccc;
margin: 3px 0;
}
.openerp .oe_searchview .oe_searchview_drawer > div:first-child {
border-top: none;
margin: 0;
}
.openerp .oe_searchview .oe_searchview_drawer h4, .openerp .oe_searchview .oe_searchview_drawer h4 * {
margin: 0;
cursor: pointer;
}
.openerp .oe_searchview .oe_searchview_drawer h4:before {
content: "▸ ";
}
.openerp .oe_searchview .oe_searchview_drawer button, .openerp .oe_searchview .oe_searchview_drawer .button {
border: none;
background: transparent;
padding: 0 2px;
-moz-box-shadow: none;
-webkit-box-shadow: none;
-box-shadow: none;
-moz-border-radius: 0;
-webkit-border-radius: 0;
border-radius: 0;
}
.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_filters {
display: table;
@ -1320,23 +1341,49 @@
}
.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_filters li {
list-style: none;
padding: 3px 6px;
height: 14px;
padding: 3px 6px 3px 18px;
line-height: 14px;
color: inherit;
cursor: pointer;
}
.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_filters li.oe_selected {
background: url(/web/static/src/img/icons/gtk-apply.png) left 2px no-repeat;
}
.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_filters li:hover {
background-color: #f0f0fa;
}
.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_advanced h4 {
border-top: 1px solid #cccccc;
margin: 5px 0 3px;
.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_custom form {
display: none;
}
.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_custom form button {
font-size: 1px;
letter-spacing: -1px;
color: transparent;
}
.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_custom form button:before {
font-family: "mnmliconsRegular";
content: "S";
font-size: 20px;
color: #404040;
}
.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_custom li {
cursor: pointer;
position: relative;
line-height: 1.2em;
padding: 2px 20px 2px 25px;
}
.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_advanced h4:before {
content: "▸ ";
.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_custom li.oe_searchview_custom_private {
background: url(/web/static/src/img/icons/terp-locked.png) 5px center no-repeat;
}
.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_advanced div {
.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_custom li:hover {
background-color: #f0f0fa;
}
.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_custom li button {
position: absolute;
top: 0;
right: 5px;
}
.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_advanced form {
display: none;
}
.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_advanced button.oe_add_condition:before {
@ -1352,13 +1399,25 @@
.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_advanced li {
list-style: none;
margin: 0;
white-space: nowrap;
}
.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_advanced.oe_opened h4:before {
.openerp .oe_searchview .oe_searchview_drawer .oe_opened h4:before {
content: "▾ ";
}
.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_advanced.oe_opened div {
.openerp .oe_searchview .oe_searchview_drawer .oe_opened form {
display: block;
}
.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_custom_delete, .openerp .oe_searchview .oe_searchview_drawer .searchview_extended_delete_prop {
font-size: 1px;
letter-spacing: -1px;
color: transparent;
}
.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_custom_delete:before, .openerp .oe_searchview .oe_searchview_drawer .searchview_extended_delete_prop:before {
font-family: "mnmliconsRegular";
content: "d";
font-size: 20px;
color: #404040;
}
.openerp .oe_view_nocontent > img {
float: left;
margin: 1.5em;
@ -1498,7 +1557,7 @@
padding: 8px 0;
border-bottom: 1px solid #dddddd;
}
.openerp .oe_application .oe_form_sheet_width {
.openerp .oe_application .oe_form_sheet_width, .openerp .oe_application .oe_form_bottom {
min-width: 650px;
max-width: 980px;
margin: 0 auto;
@ -1972,59 +2031,6 @@
.openerp .oe-listview-content .numeric input {
text-align: right;
}
.openerp .oe_kanban_group_title {
margin: 1px 1px 4px;
font-size: 15px;
font-weight: bold;
text-shadow: 0 1px 0 white;
}
.openerp .oe_kanban_column, .openerp .oe_kanban_group_header {
width: 240px;
vertical-align: top;
padding: 6px 7px 6px 6px;
background: #f0eeee;
border-left: 1px solid #f0f8f8;
border-right: 1px solid #b9b9b9;
}
.openerp .oe_kanban_record {
position: relative;
display: block;
min-height: 50px;
margin: 6px 0;
display: block;
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
border-radius: 4px;
}
.openerp .oe_kanban_record:last-child {
margin-bottom: 0;
}
.openerp .oe_kanban_record .oe_kanban_title {
font-weight: bold;
margin: 2px 4px;
}
.openerp .oe_kanban_gravatar {
width: 20px;
height: 20px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
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);
}
.openerp .oe_kanban_avatar_toto {
height: 40px;
width: 40px;
border: 1px solid;
border-color: #e5e5e5 #dbdbdb #d2d2d2;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
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);
}
.openerp .oe_trad_field.touched {
border: 1px solid green !important;
}
@ -2090,6 +2096,15 @@
color: #333333;
}
.kitten-mode-activated {
background-image: url(http://placekitten.com/g/1365/769);
background-size: cover;
background-attachment: fixed;
}
.kitten-mode-activated > * {
opacity: 0.7;
}
.openerp .oe_form_field_many2one td:first-child {
position: relative;
}

View File

@ -4,6 +4,7 @@
$section-title-color: #8786b7
$facets-border: #afafb6
$facets-border-selected: #a6a6fe
$hover-background: #f0f0fa
$colour4: #8a89ba
// }}}
// Mixins {{{
@ -74,6 +75,18 @@ $colour4: #8a89ba
-webkit-box-sizing: border-box
box-sizing: border-box
// Transforms the (readable) text of an inline element into an mmlicons icon,
// allows for actual readable text in-code (and in readers?) with iconic looks
@mixin text-to-icon($icon-name, $color: #404040)
font-size: 1px
letter-spacing: -1px
color: transparent
&:before
font-family: "mnmliconsRegular"
content: $icon-name
font-size: 20px
color: $color
// }}}
.openerp.openerp-web-client-container
@ -105,7 +118,6 @@ $colour4: #8a89ba
border-right: none
th, td
padding: 0
line-height: 18px
text-align: left
th
font-weight: bold
@ -423,6 +435,7 @@ $colour4: #8a89ba
border-right: 1px solid #afafb6
text-shadow: 0 1px 1px white
padding-bottom: 16px
line-height: 18px
a.oe_logo
width: 220px
display: block
@ -784,11 +797,6 @@ $colour4: #8a89ba
.oe_view_manager_buttons
white-space: nowrap
// }}}
// ViewManager.body {{{
.oe_view_manager_body
h4
margin: 8px 0
// }}}
// ViewManager.pager {{{
.oe_view_manager_pager
line-height: 26px
@ -855,18 +863,6 @@ $colour4: #8a89ba
content: "k"
.oe_vm_switch_diagram:after
content: "f"
//.oe_vm_switch_list:after, .oe_vm_switch_tree:after
//content: "ö"
//.oe_vm_switch_graph:after
//content: "ó"
//.oe_vm_switch_gantt:after
//content: "y"
//.oe_vm_switch_calendar:after
//content: "b"
//.oe_vm_switch_kanban:after
//content: "ó"
//.oe_vm_switch_diagram:after
//content: "}"
// }}}
// ViewManager.sidebar {{{
.oe_form_dropdown_section
@ -923,132 +919,145 @@ $colour4: #8a89ba
// }}}
// SearchView xmo {{{
.oe_searchview
cursor: text
position: relative
float: right
.VS-search
.VS-search-box
min-height: 0
padding: 0
width: 480px
border: 1px solid #ababab
@include radius(13px)
@include box-shadow(0 1px 2px rgba(0,0,0,0.2) inset)
//padding: 4px 19px
//font-size: 13px
//background: url('../img/search.png') no-repeat 5px
//background-color: white
.VS-icon
top: 6px
padding-right: 20px
width: 410px
border: 1px solid #ababab
background: white
@include radius(1em)
@include box-shadow(0 1px 2px rgba(0,0,0,0.2) inset)
.VS-icon-search
left: 2px
top: 3px
height: 18px
width: 18px
&.oe_focused
border-color: $facets-border-selected
@include box-shadow(0 1px 2px $facets-border-selected inset)
.VS-search-inner
margin: 0 40px 0 17px
padding: 1px 0
font-size: 13px
.oe_searchview_clear
cursor: pointer
position: absolute
top: 0
right: 22px
width: 15px
height: 100%
background: url(../img/attachments-close.png) center center no-repeat
input
font-size: inherit
line-height: inherit
height: auto
padding: 0
.oe_searchview_unfold_drawer
position: absolute
top: 0
right: 0
height: 100%
line-height: 2.5em
padding: 0 7px 0 4px
color: #ccc
cursor: pointer
&:hover
color: #999
&:before
content: ""
.VS-input-width-tester
font-size: inherit
padding: 0
.oe_searchview_facets
&:before
color: #ccc
font-family: "mnmliconsRegular"
content: "r"
font-size: 150%
padding: 0 1px 0 3px
display: inline
.search_input
margin-left: 0
height: 22px
input, .VS-input-width-tester
height: inherit
margin: 0
*
vertical-align: top
display: inline-block
line-height: 26px
.search_facet
padding: 0
margin: 1px 0
border: 1px solid $facets-border
@include radius(3px)
background: #f0f0fa
height: 18px
.oe_searchview_input, .oe_searchview_facet
height: 26px
&:focus
outline: none
&.is_selected
border-color: $facets-border-selected
@include box-shadow(0 0 3px 1px $facets-border-selected)
.oe_searchview_input
padding: 0 3px
.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: #4c4c4c
.oe_searchview_facet
position: relative
cursor: pointer
&:before
border: 1px solid $facets-border
@include radius(3px)
background: #8786b7
-webkit-font-smoothing: auto
padding-left: 1.1em
// spacing for opera, FF
margin: 1px 0
&:focus
border-color: $facets-border-selected
@include box-shadow(0 0 3px 1px $facets-border-selected)
.oe_facet_values
background: #f0f0fa
@include radius(0 3px 3px 0)
.oe_facet_category, .oe_facet_value
height: 24px
padding: 1px 0.1em
.oe_facet_category
color: white
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.4)
.oe_facet_value
border-left: 1px solid $facets-border
.oe_facet_remove
position: absolute
top: 9px
right: 8px
width: 0
height: 0
display: inline-block
content: ""
vertical-align: top
border-top: 5px solid #4c4c4c
border-left: 5px solid transparent
border-right: 5px solid transparent
@include opacity(0.5)
top: 0
left: 2px
color: white
&:hover
color: #ccc
&.oe_searchview_open_drawer
.oe_searchview_drawer
display: block
.oe_searchview_unfold_drawer:before
content: ""
.oe_searchview_drawer
position: absolute
z-index: 1
// detach drawer from field slightly
margin-top: 3px
top: 100%
right: 0
background-color: white
width: 480px
min-width: 100%
display: none
border: 1px solid #ccc
text-align: left
padding-bottom: 0.5em
@include radius(1em)
> div
border-top: 1px solid #ccc
margin: 3px 0
> div:first-child
border-top: none
margin: 0
h4, h4 *
margin: 0
cursor: pointer
h4:before
content: ""
button, .button
border: none
background: transparent
padding: 0 2px
@include box-shadow(none)
@include radius(0)
.oe_searchview_filters
display: table
@ -1070,24 +1079,44 @@ $colour4: #8a89ba
li
list-style: none
padding: 3px 6px
height: 14px
padding: 3px 6px 3px 18px
line-height: 14px
color: inherit
cursor: pointer
&.oe_selected
background: url(/web/static/src/img/icons/gtk-apply.png) left 2px no-repeat
// after oe_selected so background color is not overridden
&:hover
background-color: #f0f0fa
background-color: $hover-background
.oe_searchview_custom
form
display: none
button
@include text-to-icon("S")
li
cursor: pointer
position: relative
line-height: 1.2em
padding: 2px 20px 2px 25px
&.oe_searchview_custom_private
background: url(/web/static/src/img/icons/terp-locked.png) 5px center no-repeat
&:hover
background-color: $hover-background
button
position: absolute
top: 0
right: 5px
.oe_searchview_advanced
h4
border-top: 1px solid #ccc
margin: 5px 0 3px
cursor: pointer
h4:before
content: ""
div
form
display: none
button.oe_add_condition:before
@ -1101,22 +1130,28 @@ $colour4: #8a89ba
li
list-style: none
margin: 0
white-space: nowrap
&.oe_opened
h4:before
content: ""
div
display: block
.oe_opened
h4:before
content: ""
form
display: block
// delete buttons
.oe_searchview_custom_delete, .searchview_extended_delete_prop
@include text-to-icon("d")
// }}}
// Views Common {{{
.oe_view_nocontent
> img
float: left
margin-right: 1.5em
margin: 1.5em
> div
// don't encroach on my arrow
overflow: hidden
padding: 6px
padding: 35px 0px 0px 0px
max-width: 700px
font-size: 125%
.oe_view_topbar
border-bottom: 1px solid #cacaca
@ -1220,7 +1255,7 @@ $colour4: #8a89ba
background: url(/web/static/src/img/form_sheetbg.png)
padding: 8px 0
border-bottom: 1px solid #ddd
.oe_form_sheet_width
.oe_form_sheet_width, .oe_form_bottom
min-width: 650px
max-width: 980px
margin: 0 auto
@ -1308,7 +1343,6 @@ $colour4: #8a89ba
padding-left: 8px
@include box-shadow(none)
@include radius(0px)
color: #666
.oe_form_field_many2one input,
.oe_form_field_binary input,
.oe_form_field_binary input,
@ -1636,44 +1670,6 @@ $colour4: #8a89ba
input
text-align: right
// }}}
// KanbanView {{{
.oe_kanban_group_title
margin: 1px 1px 4px
font-size: 15px
font-weight: bold
text-shadow: 0 1px 0 white
.oe_kanban_column, .oe_kanban_group_header
width: 240px
vertical-align: top
padding: 6px 7px 6px 6px
background: #f0eeee
border-left: 1px solid #f0f8f8
border-right: 1px solid #b9b9b9
.oe_kanban_record
position: relative
display: block
min-height: 50px
margin: 6px 0
display: block
@include radius(4px)
&:last-child
margin-bottom: 0
.oe_kanban_title
font-weight: bold
margin: 2px 4px
.oe_kanban_gravatar
width: 20px
height: 20px
@include radius(3px)
@include box-shadow(0 1px 2px rgba(0,0,0,0.2))
.oe_kanban_avatar_toto
height: 40px
width: 40px
border: 1px solid
border-color: #e5e5e5 #dbdbdb #d2d2d2
@include radius(3px)
@include box-shadow(0 1px 2px rgba(0,0,0,0.2))
// }}}
// Translation {{{
.oe_trad_field.touched
border: 1px solid green !important
@ -1731,6 +1727,13 @@ $colour4: #8a89ba
color: #333
// }}}
.kitten-mode-activated
background-image: url(http://placekitten.com/g/1365/769)
background-size: cover
background-attachment: fixed
>*
opacity: 0.70
// Transitional overrides for old styles {{{
.openerp
.oe_form_field_many2one

View File

@ -450,6 +450,8 @@ instance.web.DatabaseManager = instance.web.Widget.extend({
instance.web.Login = instance.web.Widget.extend({
template: "Login",
remember_credentials: true,
_db_list: null,
init: function(parent) {
this._super(parent);
this.has_local_storage = typeof(localStorage) != 'undefined';
@ -478,23 +480,33 @@ instance.web.Login = instance.web.Widget.extend({
self.databasemanager.destroy();
self.$element.find('.oe_login_bottom').show();
self.$element.find('.oe_login_pane').show();
self.load_db_list();
self.load_db_list(true).then(self.proxy('_db_list_loaded'));
});
});
self.load_db_list();
return self.load_db_list().then(self.proxy('_db_list_loaded'));
},
load_db_list: function () {
var self = this;
self.rpc("/web/database/get_list", {}, function(result) {
self.set_db_list(result.db_list);
}, function(error, event) {
if (error.data.fault_code === 'AccessDenied') {
event.preventDefault();
}
});
load_db_list: function (force) {
var d = $.when(), self = this;
if (_.isNull(this._db_list) || force) {
d = self.rpc("/web/database/get_list", {}, function(result) {
self._db_list = _.clone(result.db_list);
}, function(error, event) {
if (error.data.fault_code === 'AccessDenied') {
event.preventDefault();
}
});
}
return d;
},
set_db_list: function (list) {
_db_list_loaded: function () {
var list = this._db_list,
dbdiv = this.$element.find('div.oe_login_dbpane');
this.$element.find("[name=db]").replaceWith(instance.web.qweb.render('Login.dblist', { db_list: list, selected_db: this.selected_db}));
if(list && list.length === 1) {
dbdiv.hide();
} else {
dbdiv.show();
}
},
on_submit: function(ev) {
if(ev) {
@ -521,14 +533,7 @@ instance.web.Login = instance.web.Widget.extend({
do_login: function (db, login, password) {
var self = this;
this.$element.removeClass('oe_login_invalid');
this.session.on_session_invalid.add({
callback: function () {
self.$element.addClass("oe_login_invalid");
},
unique: true
});
this.session.session_authenticate(db, login, password).then(function() {
self.$element.removeClass("oe_login_invalid");
return this.session.session_authenticate(db, login, password).pipe(function() {
if (self.has_local_storage) {
if(self.remember_credentials) {
localStorage.setItem('last_db_login_success', db);
@ -542,6 +547,10 @@ instance.web.Login = instance.web.Widget.extend({
localStorage.setItem('last_password_login_success', '');
}
}
self.$(".oe_login_pane").fadeOut("slow");
self.trigger("login");
},function () {
self.$element.addClass("oe_login_invalid");
});
}
});
@ -849,47 +858,53 @@ instance.web.WebClient = instance.web.Widget.extend({
var self = this;
this.$element.addClass("openerp openerp-web-client-container");
if (jQuery.param !== undefined && jQuery.deparam(jQuery.param.querystring()).kitten !== undefined) {
this.$element.addClass("kitten-mode-activated");
this.$element.delegate('img.oe-record-edit-link-img', 'hover', function(e) {
$("body").addClass("kitten-mode-activated");
self.$element.delegate('img.oe-record-edit-link-img', 'hover', function(e) {
self.$element.toggleClass('clark-gable');
});
}
this.session.session_bind().then(function() {
self.destroy_content();
self.show_common();
if (!self.session.session_is_valid()) {
self.show_login();
}
});
this.session.on_session_valid.add(function() {
self.show_application();
if(self.action_manager)
self.action_manager.destroy();
self.action_manager = new instance.web.ActionManager(self);
self.action_manager.appendTo(self.$element.find('.oe_application'));
self.bind_hashchange();
var version_label = _t("OpenERP - Unsupported/Community Version");
if (!self.session.openerp_entreprise) {
self.$element.find('.oe_footer_powered').append(_.str.sprintf('<span> - <a href="http://www.openerp.com/support-or-publisher-warranty-contract" target="_blank">%s</a></span>', version_label));
document.title = version_label;
} else {
self.show_application();
}
});
this.$element.on('mouseenter', '.oe_systray > div:not([data-tipsy=true])', function() {
$(this).attr('data-tipsy', 'true').tipsy().trigger('mouseenter');
});
},
show_common: function() {
var self = this;
this.crashmanager = new instance.web.CrashManager();
instance.connection.on_rpc_error.add(this.crashmanager.on_rpc_error);
window.onerror = function (message, file, line) {
self.crashmanager.on_traceback({
type: _t("Client Error"),
message: message,
data: {debug: file + ':' + line}
});
};
self.notification = new instance.web.Notification(this);
self.notification.appendTo(self.$element);
self.loading = new instance.web.Loading(self);
self.loading.appendTo(self.$element);
self.login = new instance.web.Login(self);
self.login.on("login",self,self.show_application);
self.$table = $(QWeb.render("WebClient", {}));
self.action_manager = new instance.web.ActionManager(self);
self.action_manager.appendTo(self.$table.find('.oe_application'));
},
show_login: function() {
var self = this;
this.destroy_content();
this.show_common();
self.login = new instance.web.Login(self);
self.login.appendTo(self.$element);
},
show_application: function() {
var self = this;
this.destroy_content();
this.show_common();
self.$table = $(QWeb.render("WebClient", {}));
self.$element.append(self.$table);
self.login.$element.hide();
self.menu = new instance.web.Menu(self);
self.menu.replace(this.$element.find('.oe_menu_placeholder'));
self.menu.on('menu_click', this, this.on_menu_action);
@ -898,24 +913,12 @@ instance.web.WebClient = instance.web.Widget.extend({
self.user_menu.on_menu_logout.add(this.proxy('on_logout'));
self.user_menu.on_action.add(this.proxy('on_menu_action'));
self.user_menu.do_update();
},
show_common: function() {
var self = this;
if (!this.crashmanager) {
this.crashmanager = new instance.web.CrashManager();
instance.connection.on_rpc_error.add(this.crashmanager.on_rpc_error);
window.onerror = function (message, file, line) {
self.crashmanager.on_traceback({
type: _t("Client Error"),
message: message,
data: {debug: file + ':' + line}
});
};
self.bind_hashchange();
var version_label = _t("OpenERP - Unsupported/Community Version");
if (!self.session.openerp_entreprise) {
self.$element.find('.oe_footer_powered').append(_.str.sprintf('<span> - <a href="http://www.openerp.com/support-or-publisher-warranty-contract" target="_blank">%s</a></span>', version_label));
document.title = version_label;
}
this.notification = new instance.web.Notification(this);
this.notification.appendTo(this.$element);
this.loading = new instance.web.Loading(this);
this.loading.appendTo(this.$element);
},
destroy_content: function() {
_.each(_.clone(this.getChildren()), function(el) {

View File

@ -709,6 +709,12 @@ instance.web.Widget = instance.web.Class.extend(instance.web.WidgetMixin, {
this.$element = elem;
}
},
/**
* Shortcut for $element.find() like backbone
*/
"$": function() {
return this.$element.find.apply(this.$element,arguments);
},
/**
* Informs the action manager to do an action. This supposes that
* the action manager can be found amongst the ancestors of the current widget.
@ -1341,6 +1347,9 @@ instance.web.JsonRPC = instance.web.CallbackEnabled.extend({
},
on_rpc_error: function(error) {
},
get_url: function (file) {
return this.prefix + file;
},
});
}

View File

@ -121,6 +121,10 @@ instance.web.Session = instance.web.JsonRPC.extend( /** @lends instance.web.Sess
var base_location = document.location.protocol + '//' + document.location.host;
var params = { db: db, login: login, password: password, base_location: base_location };
return this.rpc("/web/session/authenticate", params).pipe(function(result) {
if (!result.uid) {
return $.Deferred().reject();
}
_.extend(self, {
session_id: result.session_id,
db: result.db,
@ -284,9 +288,6 @@ instance.web.Session = instance.web.JsonRPC.extend( /** @lends instance.web.Sess
}
}
},
get_url: function (file) {
return this.prefix + file;
},
/**
* Cooperative file download implementation, for ajaxy APIs.
*

View File

@ -111,7 +111,7 @@ instance.web.format_value = function (value, descriptor, value_if_empty) {
return value_if_empty === undefined ? '' : value_if_empty;
}
var l10n = _t.database.parameters;
switch (descriptor.type || (descriptor.field && descriptor.field.type)) {
switch (descriptor.widget || descriptor.type || (descriptor.field && descriptor.field.type)) {
case 'id':
return value.toString();
case 'integer':
@ -171,7 +171,7 @@ instance.web.parse_value = function (value, descriptor, value_if_empty) {
case "":
return value_if_empty === undefined ? false : value_if_empty;
}
switch (descriptor.type || (descriptor.field && descriptor.field.type)) {
switch (descriptor.widget || descriptor.type || (descriptor.field && descriptor.field.type)) {
case 'integer':
var tmp;
do {

File diff suppressed because it is too large Load Diff

View File

@ -794,41 +794,36 @@ instance.web.FormView = instance.web.View.extend(_.extend({}, instance.web.form.
var self = this;
var fields = _.chain(this.fields)
.map(function (field, name) {
var value_ = field.get_value();
var value = field.get_value();
// ignore fields which are empty, invisible, readonly, o2m
// or m2m
if (!value_
if (!value
|| field.get('invisible')
|| field.get("readonly")
|| field.field.type === 'one2many'
|| field.field.type === 'many2many') {
return false;
}
var displayed;
switch(field.field.type) {
var displayed = value;
switch (field.field.type) {
case 'selection':
displayed = _(field.values).find(function (option) {
return option[0] === value_;
return option[0] === value;
})[1];
break;
case 'many2one':
displayed = value_;
break;
default:
displayed = value_;
}
return {
name: name,
string: field.node_atts.string,
value: value_,
string: field.node.attrs.string || field.field.string,
value: value,
displayed: displayed,
// convert undefined to false
change_default: !!field.field.change_default
}
})
.compact()
.sortBy(function (field) { return field.node_atts.string; })
.sortBy(function (field) { return field.string; })
.value();
var conditions = _.chain(fields)
.filter(function (field) { return field.change_default; })

View File

@ -69,8 +69,7 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi
this.groups.datagroup = new instance.web.DataGroup(
this, this.model,
dataset.get_domain(),
dataset.get_context(),
{});
dataset.get_context());
this.groups.datagroup.sort = this.dataset._sort;
}

View File

@ -615,6 +615,17 @@ instance.web.ViewManagerAction = instance.web.ViewManager.extend({
case 'edit':
this.do_edit_resource($option.data('model'), $option.data('id'), { name : $option.text() });
break;
case 'manage_filters':
this.do_action({
res_model: 'ir.filters',
views: [[false, 'list'], [false, 'form']],
type: 'ir.actions.act_window',
context: {
search_default_my_filters: true,
search_default_model_id: this.dataset.model
}
});
break;
default:
if (val) {
console.log("No debug handler for ", val);
@ -689,7 +700,7 @@ instance.web.Sidebar = instance.web.Widget.extend({
var view = this.getParent();
this.sections = [
{ 'name' : 'print', 'label' : _t('Print'), },
{ 'name' : 'files', 'label' : _t('Attachement'), },
{ 'name' : 'files', 'label' : _t('Attachment'), },
{ 'name' : 'other', 'label' : _t('More'), }
];
this.items = {

View File

@ -264,32 +264,6 @@
</div>
</t>
<t t-name="WebClient">
<table class="oe_webclient">
<tr>
<td colspan="2" class="oe_topbar">
<div class="oe_menu_placeholder"/>
<div class="oe_user_menu_placeholder"/>
<div class="oe_systray"/>
</td>
</tr>
<tr>
<td class="oe_leftbar" valign="top">
<t t-js="d">
d.url = '/' + (window.location.search || '');
</t>
<a t-att-href="url" class="oe_logo"><img t-att-src='_s + "/web/static/src/img/logo.png"'/></a>
<div class="oe_secondary_menus_container"/>
<div class="oe_footer">
Powered by <a href="http://www.openerp.com"><span>Open</span>ERP</a>
</div>
</td>
<td class="oe_application">
</td>
</tr>
</table>
</t>
<t t-name="Menu">
<ul class="oe_menu" t-if="widget.data">
<li t-foreach="widget.data.data.children" t-as="menu">
@ -358,7 +332,7 @@
</t>
<t t-name="UserMenu.about">
<div>
<a class="oe_activate_debug_mode" href="?debug" style="float:right; font-size: 80%;">Activate the developper mode</a>
<a class="oe_activate_debug_mode" href="?debug" style="float:right; font-size: 80%;">Activate the developer mode</a>
<h1 style="margin:0;">OpenERP</h1>
<h3 style="margin:15px 0;padding:0;">Version <t t-esc="version_info.version"/></h3>
<p>
@ -409,7 +383,10 @@
</tr>
<tr>
<td class="oe_leftbar" valign="top">
<a href="#" class="oe_logo"><img t-att-src='_s + "/web/static/src/img/logo.png"'/></a>
<t t-js="d">
d.url = '/' + (window.location.search || '');
</t>
<a t-att-href="url" class="oe_logo"><img t-att-src='_s + "/web/static/src/img/logo.png"'/></a>
<div class="oe_secondary_menus_container"/>
<div class="oe_footer">
Powered by <a href="http://www.openerp.com"><span>Open</span>ERP</a>
@ -476,6 +453,7 @@
<option t-if="view_manager.active_view === 'form'" value="toggle_layout_outline">Toggle Form Layout Outline</option>
<option value="fields">View Fields</option>
<option value="fvg">Fields View Get</option>
<option value="manage_filters">Manage Filters</option>
<t t-if="view_manager.session.uid === 1">
<option value="manage_views">Manage Views</option>
<option value="edit" data-model="ir.ui.view" t-att-data-id="view.fields_view.view_id">Edit <t t-esc="_.str.capitalize(view.fields_view.type)"/>View</option>
@ -998,11 +976,12 @@
</div>
</t>
<t t-name="web.datetimepicker">
<t t-set="placeholder" t-value="widget.getParent().node and widget.getParent().node.attrs.placeholder"/>
<div class="oe_datepicker_root oe_form_field_datetime">
<input type="text" class="oe_datepicker_container" disabled="disabled" style="display: none;"/>
<input type="text"
t-att-name="widget.name"
t-att-placeholder="widget.getParent().node.attrs.placeholder"
t-att-placeholder="placeholder"
t-attf-class="oe_datepicker_master field_#{widget.type_of_date} oe_form_field_#{widget.type_of_date}"
/><img class="oe_input_icon oe_datepicker_trigger" t-att-src='_s + "/web/static/src/img/ui/field_calendar.png"'
title="Select date" width="16" height="16" border="0"/>
@ -1318,7 +1297,31 @@
</t>
<div t-name="SearchView" class="oe_searchview">
<div class="oe_searchview_facets"/>
<div class="oe_searchview_clear"/>
<div class="oe_searchview_unfold_drawer"/>
<div class="oe_searchview_drawer"/>
</div>
<div t-name="SearchView.InputView"
class="oe_searchview_input"
contenteditable="true"/>
<!-- tabindex: makes div focusable -->
<div t-name="SearchView.FacetView"
class="oe_searchview_facet"
tabindex="0"
><span class="oe_facet_remove"></span
><span class="oe_facet_category oe_i" t-if="widget.model.has('icon')">
<t t-esc="widget.model.get('icon')"/>
</span
><span class="oe_facet_category" t-if="!widget.model.has('icon')">
<t t-esc="widget.model.get('category')"/>
</span ><span class="oe_facet_values"
/></div>
<span t-name="SearchView.FacetView.Value" class="oe_facet_value">
<t t-esc="widget.model.get('label')"/>
</span>
<t t-name="SearchView.managed-filters">
<option class="oe-filters-title" value="">Filters</option>
<optgroup label="-- Filters --">
@ -1375,8 +1378,9 @@
<t t-esc="attrs.string"/>
</button>
<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 t-foreach="widget.filters" t-as="filter"
t-att-title="filter.attrs.string ? filter.attrs.help : undefined">
<t t-esc="filter.attrs.string or filter.attrs.help or filter.attrs.name or 'Ω'"/>
</li>
</ul>
<t t-name="SearchView.filters.facet">
@ -1471,8 +1475,22 @@
</t>
</t>
</t>
<div t-name="SearchView.Filters" class="oe_searchview_filters">
</div>
<div t-name="SearchView.CustomFilters" class="oe_searchview_custom">
<ul class="oe_searchview_custom_list"/>
<h4 class="oe_searchview_custom_title">
<label for="oe_searchview_custom_input">Save search</label></h4>
<form>
<input id="oe_searchview_custom_input"/>
<button>Save</button><br/>
<label for="oe_searchview_custom_public">Share with all users:</label>
<input id="oe_searchview_custom_public" type="checkbox"/>
</form>
</div>
<div t-name="SearchView.advanced" class="oe_searchview_advanced">
<h4>Advanced Search...</h4>
<h4>Advanced Search</h4>
<form>
<ul>
@ -1494,26 +1512,23 @@
</select>
<select class="searchview_extended_prop_op"/>
<span class="searchview_extended_prop_value"/>
<a class="searchview_extended_delete_prop"
href="javascript:void(0)"><span> </span></a>
<button type="button" class="searchview_extended_delete_prop">Delete</button>
</li>
</t>
<t t-name="SearchView.extended_search.proposition.char">
<input t-att-id="widget.element_id" class="field_char"/>
<input class="field_char"/>
</t>
<t t-name="SearchView.extended_search.proposition.empty">
<span t-att-id="widget.element_id"></span>
<span/>
</t>
<t t-name="SearchView.extended_search.proposition.integer">
<input type="number" t-att-id="widget.element_id" class="field_integer" step="1"/>
<input type="number" class="field_integer" step="1"/>
</t>
<t t-name="SearchView.extended_search.proposition.float">
<input type="number" t-att-id="widget.element_id" class="field_float" step="0.01"/>
</t>
<t t-name="SearchView.extended_search.proposition.boolean">
<input type="number" class="field_float" step="0.01"/>
</t>
<t t-name="SearchView.extended_search.proposition.selection">
<select t-att-id="widget.element_id">
<select>
<t t-foreach="widget.field.selection" t-as="element">
<option t-att-value="element[0]"><t t-esc="element[1]"/></option>
</t>

View File

@ -66,7 +66,7 @@ $(document).ready(function () {
ok(!fail2);
});
asyncTest('Resolve all correctly ordered, sync', 1, function () {
asyncTest('Resolve all correctly ordered, async', 1, function () {
var dm = new openerp.web.DropMisordered();
var d1 = $.Deferred(), d2 = $.Deferred(),
@ -80,7 +80,7 @@ $(document).ready(function () {
ok(true);
});
});
asyncTest("Don't resolve mis-ordered, sync", 4, function () {
asyncTest("Don't resolve mis-ordered, async", 4, function () {
var dm = new openerp.web.DropMisordered(),
done1 = false, done2 = false,
fail1 = false, fail2 = false;
@ -104,7 +104,7 @@ $(document).ready(function () {
ok(!fail2);
}, 400);
});
asyncTest('Fail mis-ordered flag, sync', 4, function () {
asyncTest('Fail mis-ordered flag, async', 4, function () {
var dm = new openerp.web.DropMisordered(true),
done1 = false, done2 = false,
fail1 = false, fail2 = false;

File diff suppressed because it is too large Load Diff

View File

@ -10,9 +10,10 @@
<script src="/web/static/lib/underscore/underscore.js" type="text/javascript"></script>
<script src="/web/static/lib/underscore/underscore.string.js" type="text/javascript"></script>
<script src="/web/static/lib/backbone/backbone.js" type="text/javascript"></script>
<!-- jquery -->
<script src="/web/static/lib/jquery/jquery-1.6.4.js"></script>
<script src="/web/static/lib/jquery/jquery-1.7.2b1.js"></script>
<script src="/web/static/lib/jquery.ui/js/jquery-ui-1.8.17.custom.min.js"></script>
<script src="/web/static/lib/jquery.ba-bbq/jquery.ba-bbq.js"></script>
@ -53,4 +54,5 @@
<script type="text/javascript" src="/web/static/test/formats.js"></script>
<script type="text/javascript" src="/web/static/test/rpc.js"></script>
<script type="text/javascript" src="/web/static/test/evals.js"></script>
<script type="text/javascript" src="/web/static/test/search.js"></script>
</html>

View File

@ -1,500 +1,477 @@
@charset "utf-8";
.openerp .oe_kanban_view {
position: absolute;
top: 111px;
bottom: 0;
}
.openerp .oe_kanban_view .ui-sortable-placeholder {
border: 1px dotted black;
visibility: visible !important;
height: 60px !important;
}
.openerp .oe_kanban_groups {
width: 100%;
}
.openerp .oe_kanban_group_header {
position: relative;
}
.openerp .oe_kanban_group_folded {
padding: 0 5px 0 5px;
}
.openerp .oe_kanban_group_folded .oe_kanban_group_title,
.openerp .oe_kanban_group_folded.oe_kanban_column > *,
.openerp .oe_kanban_group_folded .oe_kanban_aggregates {
display: none;
}
.openerp .oe_kanban_group_folded .oe_kanban_group_title_vertical {
display: block;
}
.openerp .oe_kanban_group_title {
font-size: 100%;
font-weight: bold;
padding-left: 2px;
color: #333333;
}
.openerp .oe_kanban_group_title_undefined {
color: #666666;
}
.openerp .oe_kanban_group_title_vertical {
writing-mode: tb-rl;
-webkit-transform: rotate(90deg);
-moz-transform: rotate(90deg);
-o-transform: rotate(90deg);
-ms-transform: rotate(90deg);
transform: rotate(90deg);
width: 30px;
height: 20px;
font-size: 24px;
white-space: nowrap;
display: none;
position: absolute;
top: 10px;
}
.openerp .oe_kanban_show_more {
clear: both;
text-align: center;
}
.openerp .oe_kanban_grouped .oe_kanban_show_more .oe_button {
width: 100%;
}
.openerp .oe_kanban_ungrouped .oe_kanban_record {
float: left;
padding: 2px;
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
}
.openerp .oe_kanban_fold_icon {
cursor: pointer;
float: left;
padding: 2px;
width: 16px;
height: 16px;
background: url(/web_kanban/static/src/img/minus-icon.png) no-repeat;
}
.openerp .oe_kanban_group_folded .oe_kanban_fold_icon {
background: url(/web_kanban/static/src/img/plus-icon.png) no-repeat;
}
.openerp ul.oe_kanban_aggregates {
padding: 0;
margin: 0 0 0 22px;
}
.openerp ul.oe_kanban_aggregates li {
list-style: circle;
font-style: italic;
}
.openerp ul.oe_kanban_aggregates span {
text-decoration: underline;
font-size: 90%;
}
.openerp .oe_kanban_action_button {
height: 22px;
margin: 0;
}
.openerp .oe_kanban_action_a {
text-decoration: none;
}
.openerp .oe_kanban_box {
background: #FFF;
border: 2px solid #CCC;
border-radius: 4px;
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
margin-bottom: 5px;
}
.openerp .oe_kanban_box_header {
background: #EEE;
border-bottom: 1px solid #CCC;
}
.openerp .oe_kanban_title {
font-size: 95%;
font-weight: bold;
padding: 0 4px 0 4px;
}
.openerp .oe_kanban_small {
font-size: 80%;
font-weight: normal;
}
.openerp .oe_kanban_table {
width: 100%;
border: none;
border-collapse: collapse;
margin: 0;
padding: 0;
}
.openerp .oe_kanban_table tr td {
padding: 0;
}
.openerp .oe_kanban_table tr td.oe_kanban_title {
padding: 2px;
}
.openerp .oe_kanban_gravatar {
display: block;
}
.openerp .oe_kanban_box_content {
padding: 4px;
font-size: 90%;
}
.openerp .oe_kanban_button {
border: 1px solid #8ec1da;
background-color: #ddeef6;
border-radius: 3px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
color: #000000;
text-shadow: 0 1px #fff;
padding: 0 4px;
font-size: 85%;
margin: 1px;
}
.openerp a.oe_kanban_button:hover,
.openerp button.oe_kanban_button:hover {
background-color: #eeddf6;
}
.openerp .oe_kanban_buttons_set {
border-top: 1px dotted;
white-space: nowrap;
padding-top: 2px;
position: relative;
clear: both;
}
.openerp .oe_kanban_buttons_set a {
padding: 2px;
}
.oe_kanban_color_picker {
position: absolute;
top: -10px;
border: 1px solid black;
-moz-box-shadow: 2px 2px 5px #666;
-webkit-box-shadow: 2px 2px 5px #666;
box-shadow: 2px 2px 5px #666;
z-index: 2;
}
.oe_kanban_color_picker a {
display: block;
width: 30px;
height: 30px;
border: 1px solid black;
text-align: center;
text-decoration: none;
}
.oe_kanban_color_picker a:hover {
border-color: white;
}
.oe_kanban_color_picker span {
border: none;
font-size: 120%;
font-weight: bold;
color: black;
line-height: 30px;
}
.openerp .oe_kanban_left {
float: left;
}
.openerp .oe_kanban_right {
float: right;
}
.openerp .oe_kanban_clear {
clear: both;
}
.openerp .oe_kanban_box_show_onclick {
display: none;
}
.openerp .oe_kanban_draghandle {
cursor: move;
}
.openerp .oe_kanban_color_border {
border-color: #CCCCCC;
}
.openerp .oe_kanban_color_border {
border-color: #CCCCCC;
}
.openerp .oe_kanban_tooltip ul,
.openerp ul.oe_kanban_tooltip {
padding: 0 0 4px 0;
margin: 5px 0 0 15px;
list-style: circle;
}
.openerp .oe_kanban_highlight {
border-radius: 2px;
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
padding: 1px 5px;
margin: 1px 4px;
white-space: nowrap;
display: inline-block;
line-height: 1em;
}
.openerp .oe_kanban_add {
cursor: pointer;
position: absolute;
top: 6px;
right: 6px;
width: 16px;
height: 16px;
background: url(/web_kanban/static/src/img/plus-icon.png) no-repeat;
}
.openerp .oe_kanban_quick_create {
/* apply block formatting context */
overflow: hidden;
}
.openerp .oe_kanban_no_group .oe_kanban_quick_create {
width: 200px;
padding: 10px;
}
.openerp .oe_kanban_quick_create input {
display: block;
/* margins within width */
box-sizing: border-box;
width: 100%;
}
.openerp .oe_kanban_quick_create button {
float: right;
}
/* Custom colors are also present in kanban.js */
/* Custom color#0 */
.openerp .oe_kanban_color_0 .oe_kanban_color_bglight {
background: #FFFFFF;
}
.openerp .oe_kanban_color_0 .oe_kanban_color_bgdark {
background: #EEEEEE;
}
.openerp .oe_kanban_color_0 .oe_kanban_color_border {
border-color: #CCCCCC;
}
.openerp .oe_kanban_color_0 .oe_kanban_button {
background-color: #EEEEEE;
border-color: #CCCCCC;
text-shadow: 0 1px #FFFFFF;
}
.openerp .oe_kanban_color_0 .oe_kanban_button_active,
.openerp .oe_kanban_color_0 a.oe_kanban_button:hover,
.openerp .oe_kanban_color_0 button.oe_kanban_button:hover {
background-color: #999999;
color: #fff;
text-shadow: 0 1px #000;
}
/* Custom color#1 */
.openerp .oe_kanban_color_1 .oe_kanban_color_bglight {
background: #CCCCCC;
}
.openerp .oe_kanban_color_1 .oe_kanban_color_bgdark {
background: #999999;
}
.openerp .oe_kanban_color_1 .oe_kanban_color_border {
border-color: #666666;
}
.openerp .oe_kanban_color_1 .oe_kanban_button {
background-color: #999999;
border-color: #666666;
text-shadow: 0 1px #CCCCCC;
}
.openerp .oe_kanban_color_1 .oe_kanban_button_active,
.openerp .oe_kanban_color_1 a.oe_kanban_button:hover,
.openerp .oe_kanban_color_1 button.oe_kanban_button:hover {
background-color: #666666;
color: #fff;
text-shadow: 0 1px #000;
}
/* Custom color#2 */
.openerp .oe_kanban_color_2 .oe_kanban_color_bglight {
background: #FFC7C7;
}
.openerp .oe_kanban_color_2 .oe_kanban_color_bgdark {
background: #FF8F8F;
}
.openerp .oe_kanban_color_2 .oe_kanban_color_border {
border-color: #D97979;
}
.openerp .oe_kanban_color_2 .oe_kanban_button {
background-color: #FF8F8F;
border-color: #D97979;
text-shadow: 0 1px #FFC7C7;
}
.openerp .oe_kanban_color_2 .oe_kanban_button_active,
.openerp .oe_kanban_color_2 a.oe_kanban_button:hover,
.openerp .oe_kanban_color_2 button.oe_kanban_button:hover {
background-color: #CC5C5C;
color: #fff;
text-shadow: 0 1px #000;
}
/* Custom color#3 */
.openerp .oe_kanban_color_3 .oe_kanban_color_bglight {
background: #FFF1C7;
}
.openerp .oe_kanban_color_3 .oe_kanban_color_bgdark {
background: #FFE38F;
}
.openerp .oe_kanban_color_3 .oe_kanban_color_border {
border-color: #D9C179;
}
.openerp .oe_kanban_color_3 .oe_kanban_button {
background-color: #FFE38F;
border-color: #D9C179;
text-shadow: 0 1px #FFF1C7;
}
.openerp .oe_kanban_color_3 .oe_kanban_button_active,
.openerp .oe_kanban_color_3 a.oe_kanban_button:hover,
.openerp .oe_kanban_color_3 button.oe_kanban_button:hover {
background-color: #CCB05C;
color: #fff;
text-shadow: 0 1px #000;
}
/* Custom color#4 */
.openerp .oe_kanban_color_4 .oe_kanban_color_bglight {
background: #E3FFC7;
}
.openerp .oe_kanban_color_4 .oe_kanban_color_bgdark {
background: #C7FF8F;
}
.openerp .oe_kanban_color_4 .oe_kanban_color_border {
border-color: #A9D979;
}
.openerp .oe_kanban_color_4 .oe_kanban_button {
background-color: #C7FF8F;
border-color: #A9D979;
text-shadow: 0 1px #E3FFC7;
}
.openerp .oe_kanban_color_4 .oe_kanban_button_active,
.openerp .oe_kanban_color_4 a.oe_kanban_button:hover,
.openerp .oe_kanban_color_4 button.oe_kanban_button:hover {
background-color: #94CC5C;
color: #fff;
text-shadow: 0 1px #000;
}
/* Custom color#5 */
.openerp .oe_kanban_color_5 .oe_kanban_color_bglight {
background: #C7FFD5;
}
.openerp .oe_kanban_color_5 .oe_kanban_color_bgdark {
background: #8FFFAB;
}
.openerp .oe_kanban_color_5 .oe_kanban_color_border {
border-color: #79D991;
}
.openerp .oe_kanban_color_5 .oe_kanban_button {
background-color: #8FFFAB;
border-color: #79D991;
text-shadow: 0 1px #C7FFD5;
}
.openerp .oe_kanban_color_5 .oe_kanban_button_active,
.openerp .oe_kanban_color_5 a.oe_kanban_button:hover,
.openerp .oe_kanban_color_5 button.oe_kanban_button:hover {
background-color: #5CCC78;
color: #fff;
text-shadow: 0 1px #000;
}
/* Custom color#6 */
.openerp .oe_kanban_color_6 .oe_kanban_color_bglight {
background: #C7FFFF;
}
.openerp .oe_kanban_color_6 .oe_kanban_color_bgdark {
background: #8FFFFF;
}
.openerp .oe_kanban_color_6 .oe_kanban_color_border {
border-color: #79D9D9;
}
.openerp .oe_kanban_color_6 .oe_kanban_button {
background-color: #8FFFFF;
border-color: #79D9D9;
text-shadow: 0 1px #C7FFFF;
}
.openerp .oe_kanban_color_6 .oe_kanban_button_active,
.openerp .oe_kanban_color_6 a.oe_kanban_button:hover,
.openerp .oe_kanban_color_6 button.oe_kanban_button:hover {
background-color: #5CCCCC;
color: #fff;
text-shadow: 0 1px #000;
}
/* Custom color#7 */
.openerp .oe_kanban_color_7 .oe_kanban_color_bglight {
background: #C7D5FF;
}
.openerp .oe_kanban_color_7 .oe_kanban_color_bgdark {
background: #8FABFF;
}
.openerp .oe_kanban_color_7 .oe_kanban_color_border {
border-color: #8FABFF;
}
.openerp .oe_kanban_color_7 .oe_kanban_button {
background-color: #8FABFF;
border-color: #7995E9;
text-shadow: 0 1px #C7D5FF;
}
.openerp .oe_kanban_color_7 .oe_kanban_button_active,
.openerp .oe_kanban_color_7 a.oe_kanban_button:hover,
.openerp .oe_kanban_color_7 button.oe_kanban_button:hover {
background-color: #5C78CC;
color: #fff;
text-shadow: 0 1px #000;
}
/* Custom color#8 */
.openerp .oe_kanban_color_8 .oe_kanban_color_bglight {
background: #E3C7FF;
}
.openerp .oe_kanban_color_8 .oe_kanban_color_bgdark {
background: #C78FFF;
}
.openerp .oe_kanban_color_8 .oe_kanban_color_border {
border-color: #A979D9;
}
.openerp .oe_kanban_color_8 .oe_kanban_button {
background-color: #C78FFF;
border-color: #A979D9;
text-shadow: 0 1px #E3C7FF;
}
.openerp .oe_kanban_color_8 .oe_kanban_button_active,
.openerp .oe_kanban_color_8 a.oe_kanban_button:hover,
.openerp .oe_kanban_color_8 button.oe_kanban_button:hover {
background-color: #945CCC;
color: #fff;
text-shadow: 0 1px #000;
}
/* Custom color#9 */
.openerp .oe_kanban_color_9 .oe_kanban_color_bglight {
background: #FFC7F1;
}
.openerp .oe_kanban_color_9 .oe_kanban_color_bgdark {
background: #FF8FE3;
}
.openerp .oe_kanban_color_9 .oe_kanban_color_border {
border-color: #D979C1;
}
.openerp .oe_kanban_color_9 .oe_kanban_button {
background-color: #FF8FE3;
border-color: #D979C1;
text-shadow: 0 1px #FFC7F1;
}
.openerp .oe_kanban_color_9 .oe_kanban_button_active,
.openerp .oe_kanban_color_9 a.oe_kanban_button:hover,
.openerp .oe_kanban_color_9 button.oe_kanban_button:hover {
background-color: #CC5CB0;
color: #fff;
text-shadow: 0 1px #000;
}
/* Red border */
.openerp .oe_kanban_color_alert .oe_kanban_color_border,
.openerp .oe_kanban_color_red .oe_kanban_color_border {
border-color: #c00 !important;
}
/* Green border */
.openerp .oe_kanban_color_green .oe_kanban_color_border {
border-color: #0c0 !important;
}
/* Blue border */
.openerp .oe_kanban_color_blue .oe_kanban_color_border {
border-color: #00c !important;
border: 1px dotted black;
visibility: visible !important;
height: 60px !important;
}
.openerp .oe_kanban_view .oe_kanban_left {
float: left;
}
.openerp .oe_kanban_view .oe_kanban_right {
float: right;
}
.openerp .oe_kanban_view .oe_kanban_clear {
clear: both;
}
.openerp .oe_kanban_view .oe_kanban_groups {
height: 100%;
}
.openerp .oe_kanban_view .oe_kanban_group_title {
margin: 1px 1px 4px;
padding-left: 2px;
font-size: 100%;
font-weight: bold;
color: #333333;
text-shadow: 0 1px 0 white;
}
.openerp .oe_kanban_view .oe_kanban_column, .openerp .oe_kanban_view .oe_kanban_group_header {
vertical-align: top;
padding: 6px 7px 6px 6px;
background: #f0eeee;
border-left: 1px solid #f0f8f8;
border-right: 1px solid #b9b9b9;
}
.openerp .oe_kanban_view .oe_kanban_column {
height: 100%;
}
.openerp .oe_kanban_view .oe_kanban_aggregates {
padding: 0;
}
.openerp .oe_kanban_view .oe_kanban_group_header {
position: relative;
}
.openerp .oe_kanban_view .oe_kanban_group_folded {
padding: 0 5px 0 5px;
}
.openerp .oe_kanban_view .oe_kanban_group_folded .oe_kanban_group_title, .openerp .oe_kanban_view .oe_kanban_group_folded.oe_kanban_column > *, .openerp .oe_kanban_view .oe_kanban_group_folded .oe_kanban_aggregates {
display: none;
}
.openerp .oe_kanban_view .oe_kanban_group_folded .oe_kanban_group_title_vertical {
display: block;
}
.openerp .oe_kanban_view .oe_kanban_group_title_undefined {
color: #666666;
}
.openerp .oe_kanban_view .oe_kanban_group_title_vertical {
writing-mode: tb-rl;
-webkit-transform: rotate(90deg);
-moz-transform: rotate(90deg);
-o-transform: rotate(90deg);
-ms-transform: rotate(90deg);
transform: rotate(90deg);
width: 30px;
height: 20px;
font-size: 24px;
white-space: nowrap;
display: none;
position: absolute;
top: 10px;
}
.openerp .oe_kanban_view .oe_kanban_fold_icon {
cursor: pointer;
float: left;
padding: 2px;
width: 16px;
height: 16px;
background: url(/web_kanban/static/src/img/minus-icon.png) no-repeat;
}
.openerp .oe_kanban_view .oe_kanban_group_folded .oe_kanban_fold_icon {
background: url(/web_kanban/static/src/img/plus-icon.png) no-repeat;
}
.openerp .oe_kanban_view .oe_kanban_add {
cursor: pointer;
position: absolute;
top: 6px;
right: 6px;
width: 16px;
height: 16px;
background: url(/web_kanban/static/src/img/plus-icon.png) no-repeat;
}
.openerp .oe_kanban_view .oe_kanban_quick_create {
overflow: hidden;
}
.openerp .oe_kanban_view .oe_kanban_no_group .oe_kanban_quick_create {
width: 200px;
padding: 10px;
}
.openerp .oe_kanban_view .oe_kanban_quick_create input {
display: block;
box-sizing: border-box;
width: 100%;
}
.openerp .oe_kanban_view .oe_kanban_quick_create button {
float: right;
}
.openerp .oe_kanban_view .oe_kanban_vignette {
padding: 8px;
min-height: 100px;
}
.openerp .oe_kanban_view .oe_kanban_image {
display: inline-block;
vertical-align: top;
width: 64px;
height: 64px;
text-align: center;
overflow: hidden;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border-radius: 3px;
-moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
-webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
}
.openerp .oe_kanban_view .oe_kanban_details {
display: inline-block;
vertical-align: top;
width: 240px;
font-size: 13px;
padding: 0 5px;
color: #4c4c4c;
min-height: 120px;
}
.openerp .oe_kanban_view .oe_kanban_details h4 {
margin: 0 0 4px 0;
}
.openerp .oe_kanban_view .oe_kanban_record {
position: relative;
display: block;
min-height: 50px;
margin: 0;
display: block;
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
border-radius: 4px;
}
.openerp .oe_kanban_view .oe_kanban_record:last-child {
margin-bottom: 0;
}
.openerp .oe_kanban_view .oe_kanban_record .oe_kanban_title {
font-weight: bold;
margin: 2px 4px;
}
.openerp .oe_kanban_view .oe_kanban_grouped .oe_kanban_record {
margin-bottom: 6px;
}
.openerp .oe_kanban_view .oe_kanban_gravatar {
display: block;
width: 20px;
height: 20px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
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);
}
.openerp .oe_kanban_view .oe_kanban_avatar_toto {
height: 40px;
width: 40px;
border: 1px solid;
border-color: #e5e5e5 #dbdbdb #d2d2d2;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
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);
}
.openerp .oe_kanban_view .oe_kanban_box {
background: white;
border: 2px solid #cccccc;
border-radius: 4px;
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
margin-bottom: 5px;
}
.openerp .oe_kanban_view .oe_kanban_box_header {
background: #eeeeee;
border-bottom: 1px solid #cccccc;
}
.openerp .oe_kanban_view .oe_kanban_title {
font-size: 95%;
font-weight: bold;
padding: 0 4px 0 4px;
}
.openerp .oe_kanban_view .oe_kanban_small {
font-size: 80%;
font-weight: normal;
}
.openerp .oe_kanban_view .oe_kanban_show_more {
clear: both;
text-align: center;
}
.openerp .oe_kanban_view .oe_kanban_grouped .oe_kanban_show_more .oe_button {
width: 100%;
}
.openerp .oe_kanban_view .oe_kanban_ungrouped .oe_kanban_record {
float: left;
padding: 2px;
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
}
.openerp .oe_kanban_view .oe_kanban_action_button {
height: 22px;
margin: 0;
}
.openerp .oe_kanban_view .oe_kanban_action_a {
text-decoration: none;
}
.openerp .oe_kanban_view .oe_kanban_table {
width: 100%;
border: none;
border-collapse: collapse;
margin: 0;
padding: 0;
}
.openerp .oe_kanban_view .oe_kanban_table tr td {
padding: 0;
}
.openerp .oe_kanban_view .oe_kanban_table tr td.oe_kanban_title {
padding: 2px;
}
.openerp .oe_kanban_view .oe_kanban_box_content {
padding: 4px;
font-size: 90%;
}
.openerp .oe_kanban_view .oe_kanban_button {
border: 1px solid #8ec1da;
background-color: #ddeef6;
border-radius: 3px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
color: black;
text-shadow: 0 1px white;
padding: 0 4px;
font-size: 85%;
margin: 1px;
}
.openerp .oe_kanban_view a.oe_kanban_button:hover, .openerp .oe_kanban_view .openerp button.oe_kanban_button:hover {
background-color: #eeddf6;
}
.openerp .oe_kanban_view .oe_kanban_buttons_set {
border-top: 1px dotted;
white-space: nowrap;
padding-top: 2px;
position: relative;
clear: both;
}
.openerp .oe_kanban_view .oe_kanban_buttons_set a {
padding: 2px;
}
.openerp .oe_kanban_view .oe_kanban_box_show_onclick {
display: none;
}
.openerp .oe_kanban_view .oe_kanban_draghandle {
cursor: move;
}
.openerp .oe_kanban_view .oe_kanban_color_border {
border-color: #cccccc;
}
.openerp .oe_kanban_view .oe_kanban_color_border {
border-color: #cccccc;
}
.openerp .oe_kanban_view .oe_kanban_tooltip ul, .openerp .oe_kanban_view ul.oe_kanban_tooltip {
padding: 0 0 4px 0;
margin: 5px 0 0 15px;
list-style: circle;
}
.openerp .oe_kanban_view .oe_kanban_highlight {
border-radius: 2px;
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
padding: 1px 5px;
margin: 1px 4px;
white-space: nowrap;
display: inline-block;
line-height: 1em;
}
.openerp .oe_kanban_view .oe_kanban_card {
position: relative;
display: block;
min-height: 50px;
background: white;
border: 1px solid #d8d8d8;
border-bottom-color: #b9b9b9;
padding: 6px;
display: block;
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
border-radius: 4px;
}
.openerp .oe_kanban_view .oe_kanban_card:last-child {
margin-bottom: 0;
}
.openerp .oe_kanban_view .oe_kanban_card: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);
}
.openerp .oe_kanban_view .oe_kanban_card:hover .oe_kanban_menuaction {
display: block;
}
.openerp .oe_kanban_view .oe_kanban_card h3 {
margin: 0 16px 0 0;
color: #4c4c4c;
text-decoration: none;
}
.openerp .oe_kanban_view .oe_kanban_card h3:hover {
text-decoration: none;
}
.openerp .oe_kanban_view .oe_kanban_star {
float: left;
position: inline-block;
margin: 0 4px 0 0;
}
.openerp .oe_kanban_view .oe_kanban_avatar {
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
border-radius: 4px;
-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);
}
.openerp .oe_kanban_view .oe_kanban_status {
display: inline-block;
height: 12px;
width: 12px;
margin: 4px auto;
-moz-border-radius: 6px;
-webkit-border-radius: 6px;
border-radius: 6px;
-moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.6);
-webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.6);
-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.6);
}
.openerp .oe_kanban_view .oe_kanban_status_green {
background: green;
background-position: center center;
background-image: -webkit-radial-gradient(circle, #55dd55 0%, #44aa44 40%, #339933 100%);
background-image: -moz-radial-gradient(#55dd55 0%, #44aa44 40%, #339933 100%);
background-image: -ms-radial-gradient(#55dd55 0%, #44aa44 40%, #339933 100%);
background-image: radial-gradient(#55dd55 0%, #44aa44 40%, #339933 100%);
}
.openerp .oe_kanban_view .oe_kanban_status_red {
background: red;
background-position: center center;
background-image: -webkit-radial-gradient(circle, #ee7777 0%, #cc3333 40%, #bb0808 100%);
background-image: -moz-radial-gradient(#ee7777 0%, #cc3333 40%, #bb0808 100%);
background-image: -ms-radial-gradient(#ee7777 0%, #cc3333 40%, #bb0808 100%);
background-image: radial-gradient(#ee7777 0%, #cc3333 40%, #bb0808 100%);
}
.openerp .oe_kanban_view .oe_kanban_text_red {
background: red;
color: black;
}
.openerp .oe_kanban_view .oe_kanban_ellipsis {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.openerp .oe_kanban_view a.oe_kanban_menuaction {
position: absolute;
top: 0px;
right: 3px;
display: none;
color: #4c4c4c;
cursor: pointer;
}
.openerp .oe_kanban_view a.oe_kanban_menuaction:hover {
text-decoration: none;
}
.openerp .oe_kanban_view .oe_kanban_menu {
display: none;
position: absolute;
top: 30px;
right: -140px;
padding: 4px;
border: 1px solid #afafb6;
min-width: 160px;
overflow-x: hidden;
z-index: 900;
background: white;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
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);
}
.openerp .oe_kanban_view .oe_kanban_menu p {
margin-left: 12px;
}
.openerp .oe_kanban_view .oe_kanban_menu > li > a {
display: block;
padding: 3px 6px;
line-height: 14px;
color: #4c4c4c;
text-decoration: none;
}
.openerp .oe_kanban_view .oe_kanban_menu > li > a:hover {
background: #f0f0fa;
background: -moz-linear-gradient(#f0f0fa, #eeeef6);
background: -webkit-gradient(linear, left top, left bottom, from(#f0f0fa), to(#eeeef6));
background: -webkit-linear-gradient(#f0f0fa, #eeeef6);
-moz-box-shadow: none;
-webkit-box-shadow: none;
-box-shadow: none;
}
.openerp .oe_kanban_view .oe_kanban_colorpicker {
padding: 3px 6px;
}
.openerp .oe_kanban_view .oe_kanban_colorpicker li {
float: left;
}
.openerp .oe_kanban_view .oe_kanban_colorpicker li a {
display: inline-block;
width: 18px;
height: 18px;
border: 1px solid white;
}
.openerp .oe_kanban_view .oe_kanban_colorpicker li a:hover {
border: 1px solid gray !important;
}
.openerp .oe_kanban_view .oe_kanban_colorpicker li:first-child a {
margin-top: 1px;
height: 16px;
border: 1px solid #cccccc;
}
.openerp .oe_kanban_view .oe_kanban_colorpicker li:first-child a:hover {
margin-top: 0px;
height: 18px;
}
.openerp .oe_kanban_view .oe_kanban_color_0 {
background-color: white;
}
.openerp .oe_kanban_view .oe_kanban_color_1 {
background-color: #cccccc;
}
.openerp .oe_kanban_view .oe_kanban_color_2 {
background-color: #ffc7c7;
}
.openerp .oe_kanban_view .oe_kanban_color_3 {
background-color: #fff1c7;
}
.openerp .oe_kanban_view .oe_kanban_color_4 {
background-color: #e3ffc7;
}
.openerp .oe_kanban_view .oe_kanban_color_5 {
background-color: #c7ffd5;
}
.openerp .oe_kanban_view .oe_kanban_color_6 {
background-color: #c7ffff;
}
.openerp .oe_kanban_view .oe_kanban_color_7 {
background-color: #c7d5ff;
}
.openerp .oe_kanban_view .oe_kanban_color_8 {
background-color: #e3c7ff;
}
.openerp .oe_kanban_view .oe_kanban_color_9 {
background-color: #ffc7f1;
}

View File

@ -0,0 +1,395 @@
@charset "utf-8"
// Mixins {{{
@mixin radial-gradient($gradient)
background-position: center center
background-image: -webkit-radial-gradient(circle, $gradient)
background-image: -moz-radial-gradient($gradient)
background-image: -ms-radial-gradient($gradient)
background-image: radial-gradient($gradient)
@mixin radius($radius: 5px)
-moz-border-radius: $radius
-webkit-border-radius: $radius
border-radius: $radius
@mixin box-shadow($bsval: 0px 1px 4px #777)
-moz-box-shadow: $bsval
-webkit-box-shadow: $bsval
-box-shadow: $bsval
// }}}
.openerp .oe_kanban_view
// KanbanView {{{
position: absolute
top: 111px
bottom: 0
.ui-sortable-placeholder
border: 1px dotted black
visibility: visible !important
height: 60px !important
.oe_kanban_left
float: left
.oe_kanban_right
float: right
.oe_kanban_clear
clear: both
// }}}
// KanbanGroups {{{
.oe_kanban_groups
height: 100%
.oe_kanban_group_title
margin: 1px 1px 4px
padding-left: 2px
font-size: 100%
font-weight: bold
color: #333333
text-shadow: 0 1px 0 white
.oe_kanban_column, .oe_kanban_group_header
vertical-align: top
padding: 6px 7px 6px 6px
background: #f0eeee
border-left: 1px solid #f0f8f8
border-right: 1px solid #b9b9b9
.oe_kanban_column
height: 100%
.oe_kanban_aggregates
padding: 0
.oe_kanban_group_header
position: relative
.oe_kanban_group_folded
padding: 0 5px 0 5px
.oe_kanban_group_title, &.oe_kanban_column > *, .oe_kanban_aggregates
display: none
.oe_kanban_group_title_vertical
display: block
.oe_kanban_group_title_undefined
color: #666666
.oe_kanban_group_title_vertical
writing-mode: tb-rl
-webkit-transform: rotate(90deg)
-moz-transform: rotate(90deg)
-o-transform: rotate(90deg)
-ms-transform: rotate(90deg)
transform: rotate(90deg)
width: 30px
height: 20px
font-size: 24px
white-space: nowrap
display: none
position: absolute
top: 10px
.oe_kanban_fold_icon
cursor: pointer
float: left
padding: 2px
width: 16px
height: 16px
background: url(/web_kanban/static/src/img/minus-icon.png) no-repeat
.oe_kanban_group_folded .oe_kanban_fold_icon
background: url(/web_kanban/static/src/img/plus-icon.png) no-repeat
// }}}
// KanbanQuickCreate {{{
.oe_kanban_add
cursor: pointer
position: absolute
top: 6px
right: 6px
width: 16px
height: 16px
background: url(/web_kanban/static/src/img/plus-icon.png) no-repeat
.oe_kanban_quick_create
// apply block formatting context
overflow: hidden
.oe_kanban_no_group .oe_kanban_quick_create
width: 200px
padding: 10px
.oe_kanban_quick_create input
display: block
// margins within width
box-sizing: border-box
width: 100%
.oe_kanban_quick_create button
float: right
// }}}
// KanbanRecords {{{
.oe_kanban_vignette
padding: 8px
min-height: 100px
.oe_kanban_image
display: inline-block
vertical-align: top
width: 64px
height: 64px
text-align: center
overflow: hidden
@include radius(3px)
@include box-shadow(0 1px 4px rgba(0, 0, 0, 0.4))
.oe_kanban_details
display: inline-block
vertical-align: top
width: 240px
font-size: 13px
padding: 0 5px
color: #4c4c4c
min-height: 120px
h4
margin: 0 0 4px 0
.oe_kanban_record
position: relative
display: block
min-height: 50px
margin: 0
display: block
@include radius(4px)
&:last-child
margin-bottom: 0
.oe_kanban_title
font-weight: bold
margin: 2px 4px
.oe_kanban_grouped .oe_kanban_record
margin-bottom: 6px
.oe_kanban_gravatar
display: block
width: 20px
height: 20px
@include radius(3px)
@include box-shadow(0 1px 2px rgba(0,0,0,0.2))
.oe_kanban_avatar_toto
height: 40px
width: 40px
border: 1px solid
border-color: #e5e5e5 #dbdbdb #d2d2d2
@include radius(3px)
@include box-shadow(0 1px 2px rgba(0,0,0,0.2))
.oe_kanban_box
background: #FFF
border: 2px solid #CCC
border-radius: 4px
-moz-border-radius: 4px
-webkit-border-radius: 4px
margin-bottom: 5px
.oe_kanban_box_header
background: #EEE
border-bottom: 1px solid #CCC
.oe_kanban_title
font-size: 95%
font-weight: bold
padding: 0 4px 0 4px
.oe_kanban_small
font-size: 80%
font-weight: normal
.oe_kanban_show_more
clear: both
text-align: center
.oe_kanban_grouped .oe_kanban_show_more .oe_button
width: 100%
.oe_kanban_ungrouped .oe_kanban_record
float: left
padding: 2px
box-sizing: border-box
-moz-box-sizing: border-box
-webkit-box-sizing: border-box
.oe_kanban_action_button
height: 22px
margin: 0
.oe_kanban_action_a
text-decoration: none
.oe_kanban_table
width: 100%
border: none
border-collapse: collapse
margin: 0
padding: 0
.oe_kanban_table tr td
padding: 0
.oe_kanban_table tr td.oe_kanban_title
padding: 2px
.oe_kanban_box_content
padding: 4px
font-size: 90%
.oe_kanban_button
border: 1px solid #8ec1da
background-color: #ddeef6
border-radius: 3px
-moz-border-radius: 3px
-webkit-border-radius: 3px
color: #000000
text-shadow: 0 1px #fff
padding: 0 4px
font-size: 85%
margin: 1px
a.oe_kanban_button:hover, .openerp button.oe_kanban_button:hover
background-color: #eeddf6
.oe_kanban_buttons_set
border-top: 1px dotted
white-space: nowrap
padding-top: 2px
position: relative
clear: both
a
padding: 2px
.oe_kanban_box_show_onclick
display: none
.oe_kanban_draghandle
cursor: move
.oe_kanban_color_border
border-color: #CCCCCC
.oe_kanban_color_border
border-color: #CCCCCC
.oe_kanban_tooltip ul, ul.oe_kanban_tooltip
padding: 0 0 4px 0
margin: 5px 0 0 15px
list-style: circle
.oe_kanban_highlight
border-radius: 2px
-moz-border-radius: 2px
-webkit-border-radius: 2px
padding: 1px 5px
margin: 1px 4px
white-space: nowrap
display: inline-block
line-height: 1em
.oe_kanban_card
position: relative
display: block
min-height: 50px
background: white
border: 1px solid #d8d8d8
border-bottom-color: #b9b9b9
padding: 6px
display: block
@include radius(4px)
&:last-child
margin-bottom: 0
&:hover
@include box-shadow(0 0 3px rgba(0,0,0,0.6))
.oe_kanban_menuaction
display: block
h3
margin: 0 16px 0 0
color: #4c4c4c
text-decoration: none
h3:hover
text-decoration: none
.oe_kanban_star
float: left
position: inline-block
margin: 0 4px 0 0
.oe_kanban_avatar
@include radius(4px)
@include box-shadow(0 1px 2px rgba(0,0,0,0.2))
//.oe_kanban_footer_left
// float: left
.oe_kanban_status
display: inline-block
height: 12px
width: 12px
margin: 4px auto
@include radius(6px)
@include box-shadow(0 1px 3px rgba(0,0,0,0.6))
.oe_kanban_status_green
background: green
@include radial-gradient((#55dd55 0%, #44aa44 40%, #339933 100%))
.oe_kanban_status_red
background: red
@include radial-gradient((#ee7777 0%, #cc3333 40%, #bb0808 100%))
.oe_kanban_text_red
background: red
color: #000
.oe_kanban_ellipsis
overflow: hidden
text-overflow: ellipsis
white-space: nowrap
// }}}
// KanbanDropDown {{{
a.oe_kanban_menuaction
position: absolute
top: 0px
right: 3px
display: none
color: #4c4c4c
cursor: pointer
&:hover
text-decoration: none
.oe_kanban_menu
display: none
position: absolute
top: 30px
right: -140px
padding: 4px
border: 1px solid #afafb6
min-width: 160px
overflow-x: hidden
z-index: 900
background: white
@include radius(3px)
@include box-shadow(0 1px 4px rgba(0,0,0,0.3))
p
margin-left: 12px
> li > a
display: block
padding: 3px 6px
line-height: 14px
color: #4c4c4c
text-decoration: none
> li > a:hover
background: #f0f0fa
background: -moz-linear-gradient(#f0f0fa, #eeeef6)
background: -webkit-gradient(linear, left top, left bottom, from(#f0f0fa), to(#eeeef6))
background: -webkit-linear-gradient(#f0f0fa, #eeeef6)
@include box-shadow(none)
// }}}
// KanbanColorPicker {{{
.oe_kanban_colorpicker
padding: 3px 6px
.oe_kanban_colorpicker li
float: left
a
display: inline-block
width: 18px
height: 18px
border: 1px solid white
a:hover
border: 1px solid gray !important
.oe_kanban_colorpicker li:first-child a
margin-top: 1px
height: 16px
border: 1px solid #ccc
&:hover
margin-top: 0px
height: 18px
// }}}
// KanbanColors {{{
.oe_kanban_color_0
background-color: #FFFFFF
.oe_kanban_color_1
background-color: #CCCCCC
.oe_kanban_color_2
background-color: #FFC7C7
.oe_kanban_color_3
background-color: #FFF1C7
.oe_kanban_color_4
background-color: #E3FFC7
.oe_kanban_color_5
background-color: #C7FFD5
.oe_kanban_color_6
background-color: #C7FFFF
.oe_kanban_color_7
background-color: #C7D5FF
.oe_kanban_color_8
background-color: #E3C7FF
.oe_kanban_color_9
background-color: #FFC7F1
// au BufWritePost,FileWritePost *.sass :!sass --style expanded --line-numbers <afile> > "%:p:r.css"
// vim:tabstop=4:shiftwidth=4:softtabstop=4:fdm=marker:

View File

@ -10,6 +10,7 @@ instance.web_kanban.KanbanView = instance.web.View.extend({
display_name: _lt('Kanban'),
default_nr_columns: 3,
view_type: "kanban",
number_of_color_schemes: 10,
init: function (parent, dataset, view_id, options) {
this._super(parent, dataset, view_id, options);
_.defaults(this.options, {"quick_creatable": true, "creatable": true});
@ -34,6 +35,34 @@ instance.web_kanban.KanbanView = instance.web.View.extend({
this.limit = options.limit || 80;
this.add_group_mutex = new $.Mutex();
},
start: function() {
var self = this;
this._super.apply(this, arguments);
// Bind kanban cards dropdown menus
this.$element.on('click', '.oe_kanban_menuaction', function() {
var $menu = $(this).next('.oe_kanban_menu');
var show = !$menu.is(':visible');
self.$element.find('.oe_kanban_menu').hide();
var doc_width = $(document).width();
$menu.toggle(show);
if (show) {
var offset = $menu.offset();
var menu_width = $menu.width();
var x = doc_width - offset.left - menu_width - 15;
if (x < 0) {
$menu.offset({ left: offset.left + x }).width(menu_width);
}
}
return false;
});
$('html').on('click', function() {
self.$element.find('.oe_kanban_menu').hide();
});
},
destroy: function() {
this._super.apply(this, arguments);
$('html').off('click');
},
on_loaded: function(data) {
this.fields_view = data;
this.$buttons = $(QWeb.render("KanbanView.buttons", {'widget': this}));
@ -95,7 +124,7 @@ instance.web_kanban.KanbanView = instance.web.View.extend({
case 'button':
case 'a':
var type = node.attrs.type || '';
if (_.indexOf('action,object,edit,delete,color'.split(','), type) !== -1) {
if (_.indexOf('action,object,edit,delete'.split(','), type) !== -1) {
_.each(node.attrs, function(v, k) {
if (_.indexOf('icon,type,name,args,string,context,states,kanban_states'.split(','), k) != -1) {
node.attrs['data-' + k] = v;
@ -359,7 +388,7 @@ instance.web_kanban.KanbanGroup = instance.web.OldWidget.extend({
if (!this.view.state.groups[key]) {
this.view.state.groups[key] = {
folded: false
}
};
}
this.state = this.view.state.groups[key];
this.$records = null;
@ -405,18 +434,23 @@ instance.web_kanban.KanbanGroup = instance.web.OldWidget.extend({
this.$element.data('widget', this);
this.$records.data('widget', this);
this.$has_been_started.resolve();
this.compute_cards_height();
this.compute_cards_auto_height();
return def;
},
compute_cards_height: function() {
compute_cards_auto_height: function() {
// oe_kanban_auto_height is an empty class used by the kanban view in order
// to normalize height amongst kanban cards. (by group)
var self = this;
var min_height = 0;
var els = [];
_.each(this.records, function(r) {
min_height = Math.max(min_height, r.$element.outerHeight());
});
_.each(this.records, function(r) {
r.$element.css('min-height', min_height);
var $e = r.$element.find('.oe_kanban_auto_height').first().css('min-height', 0);
if ($e.length) {
els.push($e[0]);
min_height = Math.max(min_height, $e.outerHeight());
}
});
$(els).css('min-height', min_height);
},
destroy: function() {
this._super();
@ -534,8 +568,9 @@ instance.web_kanban.KanbanRecord = instance.web.OldWidget.extend({
});
},
bind_events: function() {
var self = this,
$show_on_click = self.$element.find('.oe_kanban_box_show_onclick');
var self = this;
this.setup_color_picker();
var $show_on_click = self.$element.find('.oe_kanban_box_show_onclick');
$show_on_click.toggle(this.state.folded);
this.$element.find('.oe_kanban_box_show_onclick_trigger').click(function() {
$show_on_click.toggle();
@ -559,7 +594,13 @@ instance.web_kanban.KanbanRecord = instance.web.OldWidget.extend({
trigger: 'hover'
});
this.$element.find('.oe_kanban_action').click(function() {
// If no draghandle is found, make the whole card as draghandle
if (!this.$element.find('.oe_kanban_draghandle').length) {
this.$element.children(':first').addClass('oe_kanban_draghandle');
}
this.$element.find('.oe_kanban_action').click(function(ev) {
ev.preventDefault();
var $action = $(this),
type = $action.data('type') || 'button',
method = 'do_action_' + (type === 'action' ? 'object' : type);
@ -570,9 +611,27 @@ instance.web_kanban.KanbanRecord = instance.web.OldWidget.extend({
} else {
self.do_warn("Kanban: no action for type : " + type);
}
return false;
});
},
setup_color_picker: function() {
var self = this;
var $el = this.$element.find('ul.oe_kanban_colorpicker');
if ($el.length) {
$el.html(QWeb.render('KanbanColorPicker', {
widget: this
}));
$el.on('click', 'a', function(ev) {
ev.preventDefault();
var color_field = $(this).parents('.oe_kanban_colorpicker').first().data('field') || 'color';
var data = {};
data[color_field] = $(this).data('color');
self.view.dataset.write(self.id, data, {}, function() {
self.record[color_field] = $(this).data('color');
self.do_reload();
});
});
}
},
do_action_delete: function($action) {
var self = this;
if (confirm(_t("Are you sure you want to delete this record ?"))) {
@ -592,28 +651,6 @@ instance.web_kanban.KanbanRecord = instance.web.OldWidget.extend({
this.view.open_record(this.id);
}
},
do_action_color: function($action) {
var self = this,
colors = '#FFFFFF,#CCCCCC,#FFC7C7,#FFF1C7,#E3FFC7,#C7FFD5,#C7FFFF,#C7D5FF,#E3C7FF,#FFC7F1'.split(','),
$cpicker = $(QWeb.render('KanbanColorPicker', { colors : colors, columns: 2 }));
$action.after($cpicker);
$cpicker.mouseenter(function() {
clearTimeout($cpicker.data('timeoutId'));
}).mouseleave(function(evt) {
var timeoutId = setTimeout(function() { $cpicker.remove() }, 500);
$cpicker.data('timeoutId', timeoutId);
});
$cpicker.find('a').click(function() {
var data = {};
data[$action.data('name')] = $(this).data('color');
self.view.dataset.write(self.id, data, {}, function() {
self.record[$action.data('name')] = $(this).data('color');
self.do_reload();
});
$cpicker.remove();
return false;
});
},
do_action_object: function ($action) {
var button_attrs = $action.data();
this.view.do_execute_action(button_attrs, this.view.dataset, this.id, this.do_reload);
@ -623,19 +660,18 @@ instance.web_kanban.KanbanRecord = instance.web.OldWidget.extend({
this.view.dataset.read_ids([this.id], this.view.fields_keys.concat(['__last_update'])).then(function(records) {
if (records.length) {
self.set_record(records[0]);
self.do_render();
var $render = $(self.render());
self.$element.replaceWith($render);
self.$element = $render;
self.bind_events();
self.group.compute_cards_auto_height();
} else {
self.destroy();
}
});
},
do_render: function() {
this.$element.html(this.render());
this.bind_events();
},
kanban_color: function(variable) {
var number_of_color_schemes = 10,
index = 0;
kanban_getcolor: function(variable) {
var index = 0;
switch (typeof(variable)) {
case 'string':
for (var i=0, ii=variable.length; i<ii; i++) {
@ -648,8 +684,12 @@ instance.web_kanban.KanbanRecord = instance.web.OldWidget.extend({
default:
return '';
}
var color = (index % number_of_color_schemes);
return 'oe_kanban_color_' + color;
var color = (index % this.view.number_of_color_schemes);
return color;
},
kanban_color: function(variable) {
var color = this.kanban_getcolor(variable);
return color === '' ? '' : 'oe_kanban_color_' + color;
},
kanban_gravatar: function(email, size) {
size = size || 22;

View File

@ -18,9 +18,9 @@
</t>
</div>
<t t-name="KanbanView.group_header">
<td>
<td class="oe_kanban_group_header">
<t t-if="widget.view.group_by">
<div class="oe_kanban_group_header">
<div class="oe_kanban_header">
<div class="oe_kanban_fold_icon"></div>
<t t-if="widget.view._is_quick_create_enabled()">
<div class="oe_kanban_add"></div>
@ -57,18 +57,9 @@
</div>
</t>
<t t-name="KanbanColorPicker">
<table cellspacing="0" cellpadding="0" border="0" class="oe_kanban_color_picker">
<tr>
<t t-foreach="colors" t-as="color">
<td t-att-bgcolor="color">
<a href="#" t-att-data-color="color_index">
<span t-if="__debug__"><t t-esc="color_index"/></span>
</a>
</td>
<t t-if="((color_index + 1) % Math.round(colors.length / columns)) == 0">&lt;/tr&gt;&lt;tr&gt;</t>
</t>
</tr>
</table>
<li t-foreach="widget.view.number_of_color_schemes" t-as="color">
<a href="#" t-att-data-color="color_index" t-attf-class="oe_kanban_color_#{color}"/>
</li>
</t>
<div t-name="KanbanView.quick_create" class="oe_kanban_quick_create">
<input t-att-placeholder="_t('Type name to create')"/>

View File

@ -0,0 +1,118 @@
# Slovenian translation for openerp-web
# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
# This file is distributed under the same license as the openerp-web package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
#
msgid ""
msgstr ""
"Project-Id-Version: openerp-web\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-02-07 19:19+0100\n"
"PO-Revision-Date: 2012-05-23 20:57+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Slovenian <sl@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2012-05-24 11:42+0000\n"
"X-Generator: Launchpad (build 15288)\n"
#. openerp-web
#: addons/web_process/static/src/js/process.js:261
msgid "Cancel"
msgstr "Prekliči"
#. openerp-web
#: addons/web_process/static/src/js/process.js:262
msgid "Save"
msgstr "Shrani"
#. openerp-web
#: addons/web_process/static/src/xml/web_process.xml:6
msgid "Process View"
msgstr ""
#. openerp-web
#: addons/web_process/static/src/xml/web_process.xml:19
msgid "Documentation"
msgstr "Dokumentacija"
#. openerp-web
#: addons/web_process/static/src/xml/web_process.xml:19
msgid "Read Documentation Online"
msgstr "Preberi spletno dokumentacijo"
#. openerp-web
#: addons/web_process/static/src/xml/web_process.xml:25
msgid "Forum"
msgstr "Forum"
#. openerp-web
#: addons/web_process/static/src/xml/web_process.xml:25
msgid "Community Discussion"
msgstr "Razprava skupnosti"
#. openerp-web
#: addons/web_process/static/src/xml/web_process.xml:31
msgid "Books"
msgstr "Knjige"
#. openerp-web
#: addons/web_process/static/src/xml/web_process.xml:31
msgid "Get the books"
msgstr ""
#. openerp-web
#: addons/web_process/static/src/xml/web_process.xml:37
msgid "OpenERP Enterprise"
msgstr "OpenERP Enterprise"
#. openerp-web
#: addons/web_process/static/src/xml/web_process.xml:37
msgid "Purchase OpenERP Enterprise"
msgstr ""
#. openerp-web
#: addons/web_process/static/src/xml/web_process.xml:52
msgid "Process"
msgstr "Proces"
#. openerp-web
#: addons/web_process/static/src/xml/web_process.xml:56
msgid "Notes:"
msgstr "Zapiski:"
#. openerp-web
#: addons/web_process/static/src/xml/web_process.xml:59
msgid "Last modified by:"
msgstr "Zadnja sprememba:"
#. openerp-web
#: addons/web_process/static/src/xml/web_process.xml:59
msgid "N/A"
msgstr "N/A"
#. openerp-web
#: addons/web_process/static/src/xml/web_process.xml:62
msgid "Subflows:"
msgstr ""
#. openerp-web
#: addons/web_process/static/src/xml/web_process.xml:75
msgid "Related:"
msgstr ""
#. openerp-web
#: addons/web_process/static/src/xml/web_process.xml:88
msgid "Select Process"
msgstr "Izberi postopek"
#. openerp-web
#: addons/web_process/static/src/xml/web_process.xml:98
msgid "Select"
msgstr "Izberi"
#. openerp-web
#: addons/web_process/static/src/xml/web_process.xml:109
msgid "Edit Process"
msgstr ""

View File

@ -247,6 +247,7 @@ texinfo_documents = [
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'
todo_include_todos = True
# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {

View File

@ -16,14 +16,14 @@ Contents:
async
rpc
search-view
Older stuff
-----------
.. toctree::
:maxdepth: 2
search-view
getting-started
production
widgets

View File

@ -13,217 +13,388 @@ multiple fields). The goal for this change is twofold:
* 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
The internal structure of the faceted search is inspired by
`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.
[#previous]_.
As does VisualSearch, the new search view is based on `Backbone`_ and
makes significant use of Backbone's models and collections (OpenERP
Web's widgets make a good replacement for Backbone's own views). As a
result, understanding the implementation details of the OpenERP Web 7
search view also requires a basic understanding of Backbone's models,
collections and events.
.. 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).
"returning a :js:class:`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
----------------------------------------------------
Working with the search view: creating new inputs
-------------------------------------------------
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.
The primary component of search views, as with all other OpenERP
views, are inputs. The search view has two types of inputs — filters
and fields — but only one is easly customizable: fields.
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:
The mapping from OpenERP field types (and widgets) to search view
objects is stored in the ``openerp.web.search.fields``
:js:class:`~openerp.web.Registry` where new field types and widgets
can be added.
``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.
Search view inputs have four main roles:
``category``
the *name* of the facet, displayed in the first section of a facet
view.
Loading defaults
++++++++++++++++
``value``
the *displayed value* of the facet, it is directly printed to the
right of the category.
Once the search view has initialized all its inputs, it will call
:js:func:`~openerp.web.search.Input.facet_for_defaults` on each input,
passing it a mapping (a javascript object) of ``name:value`` extracted
from the action's context.
The search view uses additional keys to store state and data it needs
to associate with facet objects:
This method should fetch a :js:class:`~openerp.web.search.Facet` (or
an equivalent object) for the field's default value if applicable (if
a default value for the field is found in the ``defaults`` mapping).
``field``
the search field instance which created the facet, used when the
search view needs to serialize the facets.
A default implementation is provided which checks if ``defaults``
contains a non-falsy value for the field's ``@name`` and calls
:js:func:`openerp.web.search.Input.facet_for` with that value.
``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).
There is no default implementation of
:js:func:`openerp.web.search.Input.facet_for` [#no_impl]_, but
:js:class:`openerp.web.search.Field` provides one, which uses the
value as-is to fetch a :js:class:`~openerp.web.search.Facet`.
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).
Providing completions
+++++++++++++++++++++
.. note::
An important component of the new search view is the auto-completion
pane, and the task of providing completion items is delegated to
inputs through the :js:func:`~openerp.web.search.Input.complete`
method.
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
This method should take a single argument (the string being typed by
the user) and should fetch an ``Array`` of possible completions
[#completion]_.
Extensions and patches to VisualSearch
++++++++++++++++++++++++++++++++++++++
A default implementation is provided which fetches nothing.
.. js:function:: VS.model.SearchFacet.value()
A completion item is a javascript object with two keys (technically it
can have any number of keys, but only these two will be used by the
search view):
Bundles the logic of selecting between ``json`` and ``value`` in
order to get the logical value of a facet.
``label``
.. js:attribute:: VS.options.callbacks.make_facet
The string which will be displayed in the completion pane. It may
be formatted using HTML (inline only), as a result if ``value`` is
interpolated into it it *must* be escaped. ``_.escape`` can be
used for this.
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`.
``facet``
This patch should not alter any behavior if
:js:attr:`~VS.options.callbacks.make_facet` is not used.
Either a :js:class:`~openerp.web.search.Facet` object or (more
commonly) the corresponding attributes object. This is the facet
which will be inserted into the search query if the completion
item is selected by the user.
.. js:attribute:: VS.options.callbacks.make_input
If the ``facet`` is not provided (not present, ``null``, ``undefined``
or any other falsy value), the completion item will not be selectable
and will act as a section title of sort (the ``label`` will be
formatted differently). If an input *may* fetch multiple completion
items, it *should* prefix those with a section title using its own
name. This has no technical consequence but is clearer for users.
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`.
Providing drawer/supplementary UI
+++++++++++++++++++++++++++++++++
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.
For some inputs (fields or not), interaction via autocompletion may be
awkward or even impossible.
.. note::
These may opt to being rendered in a "drawer" as well or instead. In
that case, they will undergo the normal widget lifecycle and be
rendered inside the drawer.
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.
.. Found no good type-based way to handle this, since there is no MI
(so no type-tagging) and it's possible for both Field and non-Field
input to be put into the drawer, for whatever reason (e.g. some
sort of auto-detector completion item for date widgets, but a
second more usual calendar widget in the drawer for more
obvious/precise interactions)
Loading Defaults
----------------
Any input can note its desire to be rendered in the drawer by
returning a truthy value from
:js:func:`~openerp.web.search.Input.in_drawer`.
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.
By default, :js:func:`~openerp.web.search.Input.in_drawer` returns the
value of :js:attr:`~openerp.web.search.Input._in_drawer`, which is
``false``. The behavior can be toggled either by redefining the
attribute to ``true`` (either on the class or on the input), or by
overriding :js:func:`~openerp.web.search.Input.in_drawer` itself.
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`.
The input will be rendered in the full width of the drawer, it will be
started only once (per view).
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.
.. todo:: drawer API (if a widget wants to close the drawer in some
way), part of the low-level SearchView API/interactions?
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.
.. todo:: handle filters and filter groups via a "driver" input which
dynamically collects, lays out and renders filters? =>
exercises drawer thingies
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/>`_.
Programmatic interactions: internal model
-----------------------------------------
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:
This new searchview is built around an instance of
:js:class:`~openerp.web.search.SearchQuery` available as
:js:attr:`openerp.web.SearchView.query`.
Actual completion items
+++++++++++++++++++++++
The query is a `backbone collection`_ of
:js:class:`~openerp.web.search.Facet` objects, which can be interacted
with directly by external objects or search view controls
(e.g. widgets displayed in the drawer).
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``.
.. js:class:: openerp.web.search.SearchQuery
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.
The current search query of the search view, provides convenience
behaviors for manipulating :js:class:`~openerp.web.search.Facet`
on top of the usual `backbone collection`_ methods.
.. 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.
The query ensures all of its facets contain at least one
:js:class:`~openerp.web.search.FacetValue` instance. Otherwise,
the facet is automatically removed from the query.
Section titles
++++++++++++++
.. js:function:: openerp.web.search.SearchQuery.add(values, options)
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).
Overridden from the base ``add`` method so that adding a facet
which is *already* in the collection will merge the value of
the new facet into the old one rather than add a second facet
with different values.
.. note::
:param values: facet, facet attributes or array thereof
:returns: the collection itself
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.
.. js:function:: openerp.web.search.SearchQuery.toggle(value, options)
If an input *may* fetch more than one completion item, it *should*
prepend a section title (using its own name) to the completion items.
Convenience method for toggling facet values in a query:
removes the values (through the facet itself) if they are
present, adds them if they are not. If the facet itself is not
in the collection, adds it automatically.
A toggling is atomic: only one change event will be triggered
on the facet regardless of the number of values added to or
removed from the facet (if the facet already exists), and the
facet is only removed from the query if it has no value *at
the end* of the toggling.
:param value: facet or facet attributes
:returns: the collection
.. js:class:: openerp.web.search.Facet
A `backbone model`_ representing a single facet of the current
research. May map to a search field, or to a more complex or
fuzzier input (e.g. a custom filter or an advanced search).
.. js:attribute:: category
The displayed name of the facet, as a ``String``. This is a
backbone model attribute.
.. js:attribute:: field
The :js:class:`~openerp.web.search.Input` instance which
originally created the facet [#facet-field]_, used to delegate
some operations (such as serializing the facet's values to
domains and contexts). This is a backbone model attribute.
.. js:attribute:: values
:js:class:`~openerp.web.search.FacetValues` as a javascript
attribute, stores all the values for the facet and helps
propagate their events to the facet. Is also available as a
backbone attribute (via ``#get`` and ``#set``) in which cases
it serializes to and deserializes from javascript arrays (via
``Collection#toJSON`` and ``Collection#reset``).
.. js:attribute:: [icon]
optional, a single ASCII letter (a-z or A-Z) mapping to the
bundled mnmliconsRegular icon font.
When a facet with an ``icon`` attribute is rendered, the icon
is displayed (in the icon font) in the first section of the
facet instead of the ``category``.
By default, only filters make use of this facility.
.. js:class:: openerp.web.search.FacetValues
`Backbone collection`_ of
:js:class:`~openerp.web.search.FacetValue` instances.
.. js:class:: openerp.web.search.FacetValue
`Backbone model`_ representing a single value within a facet,
represents a pair of (displayed name, logical value).
.. js:attribute:: label
Backbone model attribute storing the "displayable"
representation of the value, visually output to the
user. Must be a string.
.. js:attribute:: value
Backbone model attribute storing the logical/internal value
(of itself), will be used by
:js:class:`~openerp.web.search.Input` to serialize to domains
and contexts.
Can be of any type.
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
the other hand, the OpenERP Web 7 search view's state is modelled
after a collection of :js:class:`~openerp.web.search.Facet`, and each
field of a search view may have special requirements when it comes to
the domains it produces [#]_.
the domains it produces [#special]_.
So there needs to be some way of mapping
:js:class:`~VS.model.SearchFacet` objects to OpenERP search data.
:js:class:`~openerp.web.search.Facet` 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.
:js:class:`~openerp.web.search.Facet` 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
---------------------------
.. note::
The :js:class:`~openerp.web.search.Facet` object can have any
number of values (from 1 upwards)
.. note::
There is a third conversion method,
:js:func:`~openerp.web.search.Input.get_groupby`, which returns an
``Array`` of groupby domains rather than a single context. At this
point, it is only implemented on (and used by) filters.
Field services
++++++++++++++
:js:class:`~openerp.web.search.Field` provides a default
implementation of :js:func:`~openerp.web.search.Input.get_domain` and
:js:func:`~openerp.web.search.Input.get_context` taking care of most
of the peculiarities pertaining to OpenERP's handling of fields in
search views. It also provides finer hooks to let developers of new
fields and widgets customize the behavior they want without
necessarily having to reimplement all of
:js:func:`~openerp.web.search.Input.get_domain` or
:js:func:`~openerp.web.search.Input.get_context`:
.. js:function:: openerp.web.search.Field.get_context(facet)
If the field has no ``@context``, simply returns
``null``. Otherwise, calls
:js:func:`~openerp.web.search.Field.value_from` once for each
:js:class:`~openerp.web.search.FacetValue` of the current
:js:class:`~openerp.web.search.Facet` (in order to extract the
basic javascript object from the
:js:class:`~openerp.web.search.FacetValue` then evaluates
``@context`` with each of these values set as ``self``, and
returns the union of all these contexts.
:param facet:
:type facet: openerp.web.search.Facet
:returns: a context (literal or compound)
.. js:function:: openerp.web.search.Field.get_domain(facet)
If the field has no ``@filter_domain``, calls
:js:func:`~openerp.web.search.Field.make_domain` once with each
:js:class:`~openerp.web.search.FacetValue` of the current
:js:class:`~openerp.web.search.Facet` as well as the field's
``@name`` and either its ``@operator`` or
:js:attr:`~openerp.web.search.Field.default_operator`.
If the field has an ``@filter_value``, calls
:js:func:`~openerp.web.search.Field.value_from` once per
:js:class:`~openerp.web.search.FacetValue` and evaluates
``@filter_value`` with each of these values set as ``self``.
In either case, "ors" all of the resulting domains (using ``|``)
if there is more than one
:js:class:`~openerp.web.search.FacetValue` and returns the union
of the result.
:param facet:
:type facet: openerp.web.search.Facet
:returns: a domain (literal or compound)
.. js:function:: openerp.web.search.Field.make_domain(name, operator, facetValue)
Builds a literal domain from the provided data. Calls
:js:func:`~openerp.web.search.Field.value_from` on the
:js:class:`~openerp.web.search.FacetValue` and evaluates and sets
it as the domain's third value, uses the other two parameters as
the first two values.
Can be overridden to build more complex default domains.
:param String name: the field's name
:param String operator: the operator to use in the field's domain
:param facetValue:
:type facetValue: openerp.web.search.FacetValue
:returns: Array<(String, String, Object)>
.. js:function:: openerp.web.search.Field.value_from(facetValue)
Extracts a "bare" javascript value from the provided
:js:class:`~openerp.web.search.FacetValue`, and returns it.
The default implementation will simply return the ``value``
backbone property of the argument.
:param facetValue:
:type facetValue: openerp.web.search.FacetValue
:returns: Object
.. js:attribute:: openerp.web.search.Field.default_operator
Operator used to build a domain when a field has no ``@operator``
or ``@filter_domain``. ``"="`` for
:js:class:`~openerp.web.search.Field`
Arbitrary data storage
++++++++++++++++++++++
:js:class:`~openerp.web.search.Facet` and
:js:class:`~openerp.web.search.FacetValue` objects (and structures)
provided by your widgets should never be altered by the search view
(or an other widget). This means you are free to add arbitrary fields
in these structures if you need to (because you have more complex
needs than the attributes described in this document).
Ideally this should be avoided, but the possibility remains.
Changes
-------
.. todo:: merge in changelog instead
.. todo:: merge in changelog instead?
The displaying of the search view was significantly altered from
OpenERP Web 6.1 to OpenERP Web 6.2.
OpenERP Web 6.1 to OpenERP Web 7.
As a result, while the external API used to interact with the search
view does not change many internal details — including the interaction
@ -247,11 +418,11 @@ Widgets API
* :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
facets
* :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
:js:class:`~openerp.web.search.Facet` 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
@ -271,19 +442,16 @@ Filters
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`.
* ``get_value`` has been replaced by
:js:func:`~openerp.web.search.Field.value_from` as it now takes a
:js:class:`~openerp.web.search.FacetValue` argument (instead of no
argument). It provides a default implementation returning the
``value`` property of its argument.
* 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.
:js:func:`~openerp.web.search.Field.make_domain` is now a
:js:class:`~openerp.web.search.FacetValue` so child classes have all
the information they need to derive the "right" resulting domain.
Custom filters
++++++++++++++
@ -300,12 +468,82 @@ Many To One
: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
Advanced Search
+++++++++++++++
* The advanced search is now a more standard
:js:class:`~openerp.web.search.Input` configured to be rendered in
the drawer.
* :js:class:`~openerp.web.search.ExtendedSearchProposition.Field` are
now standard widgets, with the "right" behaviors (they don't rebind
their ``$element`` in ``start()``)
* The ad-hoc optional setting of the openerp field descriptor on a
:js:class:`~openerp.web.search.ExtendedSearchProposition.Field` has
been removed, the field descriptor is now passed as second argument
to the
:js:class:`~openerp.web.search.ExtendedSearchProposition.Field`'s
constructor, and bound to its
:js:attr:`~openerp.web.search.ExtendedSearchProposition.Field.field`.
* Instead of its former domain triplet ``(field, operator, value)``,
:js:func:`~openerp.web.search.ExtendedSearchProposition.get_proposition`
now returns an object with two fields ``label`` and ``value``,
respectively a human-readable version of the proposition and the
corresponding domain triplet for the proposition.
.. [#previous]
the original view was implemented on top of a monkey-patched
VisualSearch, but as our needs diverged from VisualSearch's goal
this made less and less sense ultimately leading to a clean-room
reimplementation
.. [#no_impl]
In case you are extending the search view with a brand new type of
input
.. [#completion]
Ideally this array should not hold more than about 10 items, but
the search view does not put any constraint on this at the
moment. Note that this may change.
.. [#facet-field]
``field`` does not actually need to be an instance of
:js:class:`~openerp.web.search.Input`, nor does it need to be what
created the facet, it just needs to provide the three
facet-serialization methods
:js:func:`~openerp.web.search.Input.get_domain`,
:js:func:`~openerp.web.search.Input.get_context` and
:js:func:`~openerp.web.search.Input.get_gropuby`, existing
:js:class:`~openerp.web.search.Input` subtypes merely provide
convenient base implementation for those methods.
Complex search view inputs (especially those living in the drawer)
may prefer using object literals with the right slots returning
closed-over values or some other scheme un-bound to an actual
:js:class:`~openerp.web.search.Input`, as
:js:class:`~openerp.web.search.CustomFilters` and
:js:class:`~openerp.web.search.Advanced` do.
.. [#special]
search view fields may also bundle context data to add to the
search context
.. _Backbone:
http://documentcloud.github.com/backbone/
.. _Backbone.Collection:
.. _Backbone collection:
http://documentcloud.github.com/backbone/#Collection
.. _Backbone model:
http://documentcloud.github.com/backbone/#Model
.. _commit 3fca87101d:
https://github.com/documentcloud/visualsearch/commit/3fca87101d
https://github.com/documentcloud/visualsearch/commit/3fca87101d