Search fixes (#2746)
* GS in awesome bar, UI fixes: scroll nav,lists * awesome bar specificity * Add fuzzy search in awesome bar * Add fuzzy specific boldening * List subtype buttons * Update global_search.py
This commit is contained in:
parent
82e64d2cbf
commit
e9f2aadd38
8 changed files with 422 additions and 178 deletions
|
|
@ -408,7 +408,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_global_search": 1,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Communication Type",
|
||||
|
|
@ -759,7 +759,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 1,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Reference Name",
|
||||
|
|
@ -1379,7 +1379,7 @@
|
|||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2017-02-17 16:41:05.429760",
|
||||
"modified": "2017-02-21 04:57:33.141998",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Core",
|
||||
"name": "Communication",
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 1,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Last Name",
|
||||
|
|
@ -554,7 +554,7 @@
|
|||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2017-01-31 00:15:30.298287",
|
||||
"modified": "2017-02-20 14:54:33.723052",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Email",
|
||||
"name": "Contact",
|
||||
|
|
@ -805,6 +805,7 @@
|
|||
"quick_entry": 0,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_order": "ASC",
|
||||
"track_changes": 0,
|
||||
"track_seen": 0
|
||||
|
|
|
|||
|
|
@ -687,8 +687,18 @@ fieldset[disabled] .form-control {
|
|||
padding: 0px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.search-dialog .layout-side-section {
|
||||
padding-left: 15px;
|
||||
.search-dialog .layout-side-section .help-link {
|
||||
padding-top: 20px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.search-dialog .layout-side-section .nav > li > a {
|
||||
padding-left: 20px;
|
||||
}
|
||||
.search-dialog .results-area a {
|
||||
color: #5E64FF;
|
||||
}
|
||||
.search-dialog .results-area .single-link a {
|
||||
color: #36414c;
|
||||
}
|
||||
.search-dialog .module-section .back-link {
|
||||
margin-bottom: 20px;
|
||||
|
|
@ -698,11 +708,19 @@ fieldset[disabled] .form-control {
|
|||
font-family: 'Octicons';
|
||||
content: '\f0a4';
|
||||
}
|
||||
.search-dialog .dual-section .result a {
|
||||
color: black;
|
||||
.search-dialog .full-list .result {
|
||||
border-bottom: 1px solid #d1d8dd;
|
||||
margin-top: 10px;
|
||||
}
|
||||
.search-dialog .dual-section .result a b {
|
||||
color: #4e6161;
|
||||
.search-dialog .full-list .result .result-subtype{
|
||||
float: right;
|
||||
margin-left: 10px;
|
||||
}
|
||||
.search-dialog .full-list .section-head {
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
.search-dialog .dual-section .result-subtype {
|
||||
display: none;
|
||||
}
|
||||
.search-dialog .result-status {
|
||||
margin-top: 30px;
|
||||
|
|
|
|||
|
|
@ -12,17 +12,21 @@ frappe.search.AwesomeBar = Class.extend({
|
|||
this.nav = new frappe.search.NavSearch();
|
||||
this.help = new frappe.search.HelpSearch();
|
||||
|
||||
this.options = [];
|
||||
this.global_results = [];
|
||||
|
||||
var awesomplete = new Awesomplete(input, {
|
||||
minChars: 0,
|
||||
maxItems: 99,
|
||||
autoFirst: true,
|
||||
list: [],
|
||||
filter: function (text, term) {
|
||||
return true;
|
||||
filter: function (text, term) {
|
||||
return true;
|
||||
},
|
||||
data: function (item, input) {
|
||||
var label = item.label + "%%%" + item.value + "%%%" +
|
||||
(item.description || "") + "%%%" + (item.index || "");
|
||||
var label = item.label + "%%%" + item.value + "%%%" +
|
||||
(item.description || "") + "%%%" + (item.index || "")
|
||||
+ "%%%" + (item.type || "") + "%%%" + (item.prefix || "");
|
||||
return {
|
||||
label: label,
|
||||
value: item.value
|
||||
|
|
@ -31,9 +35,16 @@ frappe.search.AwesomeBar = Class.extend({
|
|||
item: function(item, term) {
|
||||
var d = item;
|
||||
var parts = item.split("%%%"),
|
||||
d = { label: parts[0], value: parts[1], description: parts[2] };
|
||||
d = { label: parts[0], value: parts[1], description: parts[2],
|
||||
type: parts[4], prefix: parts[5]};
|
||||
|
||||
var html = "<span>" + __(d.label || d.value) + "</span>";
|
||||
if(d.prefix) {
|
||||
var html = "<span>" + __((d.prefix + ' ' + d.label)) + "</span>";
|
||||
} else if(d.type) {
|
||||
var html = "<span>" + __((d.label + ' ' + d.type)) + "</span>";
|
||||
} else {
|
||||
var html = "<span>" + __(d.label || d.value) + "</span>";
|
||||
}
|
||||
if(d.description && d.value!==d.description) {
|
||||
html += '<br><span class="text-muted">' + __(d.description) + '</span>';
|
||||
}
|
||||
|
|
@ -42,29 +53,37 @@ frappe.search.AwesomeBar = Class.extend({
|
|||
.html('<a style="font-weight:normal"><p>' + html + '</p></a>')
|
||||
.get(0);
|
||||
},
|
||||
sort: function(a, b) {
|
||||
sort: function(a, b) {
|
||||
var a_index = a.split("%%%")[3];
|
||||
var b_index = b.split("%%%")[3];
|
||||
return (a_index - b_index);
|
||||
return (a_index - b_index);
|
||||
}
|
||||
});
|
||||
|
||||
$input.on("input", function(e) {
|
||||
var value = e.target.value;
|
||||
var txt = value.trim().replace(/\s\s+/g, ' ');
|
||||
var last_space = txt.lastIndexOf(' ');
|
||||
|
||||
if(txt && txt.length > 2) {
|
||||
me.global.get_awesome_bar_options(txt.toLowerCase(), me);
|
||||
}
|
||||
|
||||
var $this = $(this);
|
||||
clearTimeout($this.data('timeout'));
|
||||
|
||||
$this.data('timeout', setTimeout(function(){
|
||||
var value = e.target.value;
|
||||
var txt = strip(value);
|
||||
me.options = [];
|
||||
if(txt) {
|
||||
var keywords = strip(txt.toLowerCase());
|
||||
me.build_options(keywords);
|
||||
if(me.options.length < 2) {
|
||||
me.global.get_awesome_bar_options(keywords, me);
|
||||
if(txt && txt.length > 2) {
|
||||
if(last_space !== -1) {
|
||||
me.set_specifics(txt.slice(0,last_space), txt.slice(last_space+1));
|
||||
}
|
||||
me.options = me.options.concat(me.build_options(txt));
|
||||
me.build_defaults(txt);
|
||||
me.options = me.options.concat(me.global_results);
|
||||
}
|
||||
|
||||
me.make_calculator(txt);
|
||||
me.add_recent(txt || "");
|
||||
me.add_help();
|
||||
|
||||
|
|
@ -112,6 +131,7 @@ frappe.search.AwesomeBar = Class.extend({
|
|||
}
|
||||
|
||||
if(item.onclick) {
|
||||
// frappe.new_doc(item.match, true);
|
||||
item.onclick(item.match);
|
||||
} else {
|
||||
var previous_hash = window.location.hash;
|
||||
|
|
@ -135,7 +155,8 @@ frappe.search.AwesomeBar = Class.extend({
|
|||
this.options.push({
|
||||
label: __("Help on Search"),
|
||||
value: "Help on Search",
|
||||
index: 20,
|
||||
index: 50,
|
||||
default: "Help",
|
||||
onclick: function() {
|
||||
var txt = '<table class="table table-bordered">\
|
||||
<tr><td style="width: 50%">'+__("Make a new record")+'</td><td>'+
|
||||
|
|
@ -194,7 +215,8 @@ frappe.search.AwesomeBar = Class.extend({
|
|||
out.label = match[0].bold();
|
||||
out.value = match[0];
|
||||
}
|
||||
out.index = 10
|
||||
out.index = 29;
|
||||
out.default = "Recent";
|
||||
return out;
|
||||
}, true);
|
||||
},
|
||||
|
|
@ -231,45 +253,106 @@ frappe.search.AwesomeBar = Class.extend({
|
|||
setup_recent: function() {
|
||||
this.recent = JSON.parse(frappe.boot.user.recent || "[]") || [];
|
||||
},
|
||||
|
||||
is_present: function(txt, item) {
|
||||
($.isArray(item)) ? _item = item[0] : _item = item;
|
||||
_item = __(_item || '').toLowerCase().replace(/-/g, " ");
|
||||
if(txt===_item || _item.indexOf(txt) !== -1) {
|
||||
return item;
|
||||
|
||||
fuzzy_search: function(txt, _item, index) {
|
||||
item = __(_item || '').toLowerCase().replace(/-/g, " ");
|
||||
|
||||
txt = txt.toLowerCase();
|
||||
|
||||
var ilen = item.length;
|
||||
var tlen = txt.length;
|
||||
var match_level1 = 0.5;
|
||||
var match_level2 = 0.8;
|
||||
var index = ((tlen/ilen) > match_level1) ? 24 : index;
|
||||
var rendered_label = "";
|
||||
var i, j, skips = 0, mismatches = 0;
|
||||
|
||||
if (tlen > ilen) {
|
||||
return [];
|
||||
}
|
||||
if (item.indexOf(txt) !== -1) {
|
||||
// prefer single words
|
||||
index = (item.indexOf(' ') === -1) ? index-1 : index;
|
||||
index = ((tlen/ilen) > match_level2) ? 21 : index;
|
||||
|
||||
var regEx = new RegExp("("+ txt +")", "ig");
|
||||
rendered_label = _item.replace(regEx, '<b>$1</b>');
|
||||
|
||||
return [_item, index, rendered_label];
|
||||
}
|
||||
outer: for (i = 0, j = 0; i < tlen; i++) {
|
||||
var t_ch = txt.charCodeAt(i);
|
||||
if(mismatches !== 0) skips++;
|
||||
if(skips > 3) return [];
|
||||
mismatches = 0;
|
||||
while (j < ilen) {
|
||||
var i_ch = item.charCodeAt(j);
|
||||
if (i_ch === t_ch) {
|
||||
var item_char = _item.charAt(j);
|
||||
if(item_char === item_char.toLowerCase()){
|
||||
rendered_label += '<b>' + txt.charAt(i) + '</b>';
|
||||
} else {
|
||||
rendered_label += '<b>' + txt.charAt(i).toUpperCase() + '</b>';
|
||||
}
|
||||
j++;
|
||||
continue outer;
|
||||
}
|
||||
mismatches++;
|
||||
if(mismatches > 2) return [];
|
||||
rendered_label += _item.charAt(j);
|
||||
j++;
|
||||
}
|
||||
return [];
|
||||
}
|
||||
rendered_label += _item.slice(j);
|
||||
return [_item, index + 10, rendered_label];
|
||||
},
|
||||
|
||||
set_global_results: function(global_results){
|
||||
this.options = this.options.concat(global_results);
|
||||
set_specifics: function(txt, end_txt) {
|
||||
var me = this;
|
||||
var results = this.build_options(txt);
|
||||
results.forEach(function(r) {
|
||||
if((r.type).toLowerCase().indexOf(end_txt.toLowerCase()) === 0) {
|
||||
if(r.index < 25) {
|
||||
r.index = 21;
|
||||
}
|
||||
me.options.push(r);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
build_options: function(txt) {
|
||||
this.options =
|
||||
this.make_global_search(txt).concat(
|
||||
this.make_search_in_current(txt),
|
||||
this.make_calculator(txt),
|
||||
this.make_new_doc(txt),
|
||||
this.make_search_in_list(txt),
|
||||
this.get_doctypes(txt),
|
||||
this.get_reports(txt),
|
||||
this.get_pages(txt),
|
||||
this.get_modules(txt)
|
||||
);
|
||||
build_defaults: function(txt) {
|
||||
this.make_global_search(txt);
|
||||
this.make_search_in_current(txt);
|
||||
this.options = this.options.concat(this.make_search_in_list(txt));
|
||||
},
|
||||
|
||||
build_options: function(txt) {
|
||||
return this.make_new_doc(txt).concat(
|
||||
this.get_doctypes(txt),
|
||||
this.get_reports(txt),
|
||||
this.get_pages(txt),
|
||||
this.get_modules(txt)
|
||||
);
|
||||
},
|
||||
|
||||
set_global_results: function(global_results, txt){
|
||||
this.global_results = this.global_results.concat(global_results);
|
||||
},
|
||||
|
||||
make_global_search: function(txt) {
|
||||
var me = this;
|
||||
return [{
|
||||
this.options.push({
|
||||
label: __("Search for '" + txt.bold() + "'"),
|
||||
value: __("Search for '" + txt + "'"),
|
||||
match: txt,
|
||||
index: 5,
|
||||
index: 22,
|
||||
default: "Search",
|
||||
onclick: function() {
|
||||
me.search.search_dialog.show();
|
||||
me.search.setup_search(txt, [me.global, me.nav, me.help]);
|
||||
}
|
||||
}];
|
||||
});
|
||||
},
|
||||
|
||||
make_search_in_current: function(txt) {
|
||||
|
|
@ -280,17 +363,18 @@ frappe.search.AwesomeBar = Class.extend({
|
|||
var search_field = meta.title_field || "name";
|
||||
var options = {};
|
||||
options[search_field] = ["like", "%" + txt + "%"];
|
||||
return [{
|
||||
this.options.push({
|
||||
label: __('Find {0} in {1}', [txt.bold(), route[1].bold()]),
|
||||
value: __('Find {0} in {1}', [txt, route[1]]),
|
||||
route_options: options,
|
||||
index: 10,
|
||||
index: 23,
|
||||
onclick: function() {
|
||||
cur_list.refresh();
|
||||
},
|
||||
default: "Current",
|
||||
match: txt
|
||||
}];
|
||||
} else { return []; }
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
make_calculator: function(txt) {
|
||||
|
|
@ -302,54 +386,36 @@ frappe.search.AwesomeBar = Class.extend({
|
|||
try {
|
||||
var val = eval(txt);
|
||||
var formatted_value = __('{0} = {1}', [txt, (val + '').bold()]);
|
||||
return [{
|
||||
this.options.push({
|
||||
label: formatted_value,
|
||||
value: __('{0} = {1}', [txt, val]),
|
||||
match: val,
|
||||
index: 10,
|
||||
index: 24,
|
||||
default: "Calculator",
|
||||
onclick: function() {
|
||||
msgprint(formatted_value, "Result");
|
||||
}
|
||||
}];
|
||||
});
|
||||
} catch(e) {
|
||||
// pass
|
||||
}
|
||||
} else { return []; }
|
||||
},
|
||||
|
||||
make_new_doc: function(txt) {
|
||||
var me = this;
|
||||
var out = [];
|
||||
if(txt.split(" ")[0]==="new") {
|
||||
frappe.boot.user.can_create.forEach(function (item) {
|
||||
var target = me.is_present(txt.substr(4), item);
|
||||
if(target) {
|
||||
out.push({
|
||||
label: __("New {0}", [target.bold()]),
|
||||
value: __("New {0}", [target]),
|
||||
index: 10,
|
||||
match: target,
|
||||
onclick: function() { frappe.new_doc(target, true); }
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
return out;
|
||||
},
|
||||
|
||||
make_search_in_list: function(txt) {
|
||||
var me = this;
|
||||
var out = [];
|
||||
if(in_list(txt.split(" "), "in")) {
|
||||
if(in_list(txt.split(" "), "in") && (txt.slice(-2) !== "in")) {
|
||||
parts = txt.split(" in ");
|
||||
frappe.boot.user.can_read.forEach(function (item) {
|
||||
target = me.is_present(parts[1], item);
|
||||
var target = me.fuzzy_search(parts[1], item, 21)[0];
|
||||
if(target) {
|
||||
out.push({
|
||||
label: __('Find {0} in {1}', [__(parts[0]).bold(), __(target).bold()]),
|
||||
value: __('Find {0} in {1}', [__(parts[0]), __(target)]),
|
||||
route_options: {"name": ["like", "%" + parts[0] + "%"]},
|
||||
index: 10,
|
||||
index: 21,
|
||||
default: "In List",
|
||||
route: ["List", target]
|
||||
});
|
||||
}
|
||||
|
|
@ -358,36 +424,62 @@ frappe.search.AwesomeBar = Class.extend({
|
|||
return out;
|
||||
},
|
||||
|
||||
get_doctypes: function(txt) {
|
||||
make_new_doc: function(txt) {
|
||||
var me = this;
|
||||
var out = [];
|
||||
|
||||
var target, index;
|
||||
var option = function(type, route) {
|
||||
return {
|
||||
label: __("{0} " + type, [__(target).bold()]),
|
||||
value: __(target),
|
||||
route: route,
|
||||
index: index,
|
||||
match: target
|
||||
}
|
||||
};
|
||||
frappe.boot.user.can_read.forEach(function (item) {
|
||||
target = me.is_present(txt, item);
|
||||
if(target) {
|
||||
var match_ratio = txt.length / item.length;
|
||||
index = (match_ratio > 0.7) ? 10 : 12;
|
||||
|
||||
// include 'making new' option
|
||||
if(in_list(frappe.boot.user.can_create, target)) {
|
||||
if(txt.split(" ")[0]==="new") {
|
||||
frappe.boot.user.can_create.forEach(function (item) {
|
||||
var result = me.fuzzy_search(txt.substr(4), item, 21);
|
||||
var target = result[0];
|
||||
var rendered_label = result[2];
|
||||
if(target) {
|
||||
out.push({
|
||||
label: __("New {0}", [target.bold()]),
|
||||
label: rendered_label,
|
||||
value: __("New {0}", [target]),
|
||||
index: 21,
|
||||
type: "New",
|
||||
prefix: "New",
|
||||
match: target,
|
||||
index: 12,
|
||||
onclick: function() { frappe.new_doc(target, true); }
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
return out;
|
||||
},
|
||||
|
||||
get_doctypes: function(txt) {
|
||||
var me = this;
|
||||
var out = [];
|
||||
|
||||
var result, target, index, rendered_label;
|
||||
var option = function(type, route) {
|
||||
return {
|
||||
label: rendered_label,
|
||||
value: __(target),
|
||||
route: route,
|
||||
index: index,
|
||||
match: target,
|
||||
type: type
|
||||
}
|
||||
};
|
||||
frappe.boot.user.can_read.forEach(function (item) {
|
||||
result = me.fuzzy_search(txt, item, 25);
|
||||
target = result[0];
|
||||
index = result[1];
|
||||
rendered_label = result[2];
|
||||
if(target) {
|
||||
// include 'making new' option (not working)
|
||||
// if(in_list(frappe.boot.user.can_create, target)) {
|
||||
// out.push({
|
||||
// label: rendered_label,
|
||||
// value: __("New {0}", [target]),
|
||||
// index: index,
|
||||
// type: "New",
|
||||
// prefix: "New",
|
||||
// onclick: function() { frappe.new_doc(target, true); }
|
||||
// });
|
||||
// }
|
||||
if(in_list(frappe.boot.single_types, target)) {
|
||||
out.push(option("", ["Form", target, target]));
|
||||
|
||||
|
|
@ -395,7 +487,7 @@ frappe.search.AwesomeBar = Class.extend({
|
|||
out.push(option("Tree", ["Tree", target]));
|
||||
|
||||
} else {
|
||||
out.push(option("List", ["List", target]));
|
||||
out.push(option("List", ["List", target]));
|
||||
if(frappe.model.can_get_report(target)) {
|
||||
out.push(option("Report", ["Report", target]));
|
||||
}
|
||||
|
|
@ -414,11 +506,12 @@ frappe.search.AwesomeBar = Class.extend({
|
|||
var me = this;
|
||||
var out = [];
|
||||
Object.keys(frappe.boot.user.all_reports).forEach(function(item) {
|
||||
var target = me.is_present(txt, item);
|
||||
var result = me.fuzzy_search(txt, item, 26);
|
||||
var target = result[0];
|
||||
var index = result[1];
|
||||
var rendered_label = result[2];
|
||||
if(target) {
|
||||
var report = frappe.boot.user.all_reports[target];
|
||||
var match_ratio = txt.length / item.length;
|
||||
var index = (match_ratio > 0.7) ? 10 : 13;
|
||||
var route = [];
|
||||
if(report.report_type == "Report Builder")
|
||||
route = ["Report", report.ref_doctype, target];
|
||||
|
|
@ -426,10 +519,12 @@ frappe.search.AwesomeBar = Class.extend({
|
|||
route = ["query-report", target];
|
||||
|
||||
out.push({
|
||||
label: __("Report {0}", [__(target).bold()]),
|
||||
label: rendered_label,
|
||||
value: __("Report {0}" , [__(target)]),
|
||||
match: txt,
|
||||
index: index,
|
||||
type: "Report",
|
||||
prefix: "Report",
|
||||
route: route
|
||||
});
|
||||
}
|
||||
|
|
@ -446,16 +541,19 @@ frappe.search.AwesomeBar = Class.extend({
|
|||
p.name = name;
|
||||
});
|
||||
Object.keys(this.pages).forEach(function(item) {
|
||||
var target = me.is_present(txt, item);
|
||||
var result = me.fuzzy_search(txt, item, 27);
|
||||
var target = result[0];
|
||||
var index = result[1];
|
||||
var rendered_label = result[2];
|
||||
if(target) {
|
||||
var match_ratio = txt.length / item.length;
|
||||
var index = (match_ratio > 0.7) ? 10 : 14;
|
||||
var page = me.pages[target];
|
||||
out.push({
|
||||
label: __("Open {0}", [__(target).bold()]),
|
||||
label: rendered_label,
|
||||
value: __("Open {0}", [__(target)]),
|
||||
match: txt,
|
||||
index: index,
|
||||
type: "Page",
|
||||
prefix: "Open",
|
||||
route: [page.route || page.name]
|
||||
});
|
||||
}
|
||||
|
|
@ -464,10 +562,12 @@ frappe.search.AwesomeBar = Class.extend({
|
|||
var target = 'Calendar';
|
||||
if(__('calendar').indexOf(txt.toLowerCase()) === 0) {
|
||||
out.push({
|
||||
label: __("Open {0}", [__(target).bold()]),
|
||||
label: rendered_label,
|
||||
value: __("Open {0}", [__(target)]),
|
||||
route: [target, 'Event'],
|
||||
index: 14,
|
||||
index: 27,
|
||||
type: "Calendar",
|
||||
prefix: "Open",
|
||||
match: target
|
||||
});
|
||||
}
|
||||
|
|
@ -478,17 +578,20 @@ frappe.search.AwesomeBar = Class.extend({
|
|||
var me = this;
|
||||
var out = [];
|
||||
Object.keys(frappe.modules).forEach(function(item) {
|
||||
var target = me.is_present(txt, item);
|
||||
var result = me.fuzzy_search(txt, item, 28);
|
||||
var target = result[0];
|
||||
var index = result[1];
|
||||
var rendered_label = result[2];
|
||||
if(target) {
|
||||
var match_ratio = txt.length / item.length;
|
||||
var index = (match_ratio > 0.7) ? 10 : 15;
|
||||
var module = frappe.modules[target];
|
||||
if(module._doctype) return;
|
||||
ret = {
|
||||
label: __("Open {0}", [__(target).bold()]),
|
||||
label: rendered_label,
|
||||
value: __("Open {0}", [__(target)]),
|
||||
match: txt,
|
||||
index: index
|
||||
index: index,
|
||||
type: "Module",
|
||||
prefix: "Open"
|
||||
}
|
||||
if(module.link) {
|
||||
ret.route = [module.link];
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
<div class="row">
|
||||
<div class="col-md-2 col-sm-2 hidden-xs layout-side-section search-sidebar">
|
||||
<ul class="module-sidebar-nav overlay-sidebar nav nav-pills nav-stacked search-sidelist">
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-md-10 col-sm-10 layout-main-section results-area">
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ frappe.search.UnifiedSearch = Class.extend({
|
|||
this.search_modal.addClass('search-dialog');
|
||||
|
||||
this.input = this.search_modal.find(".search-input");
|
||||
this.sidebar = this.search_modal.find(".search-sidebar");
|
||||
this.sidelist = this.search_modal.find(".search-sidelist");
|
||||
this.results_area = this.search_modal.find(".results-area");
|
||||
},
|
||||
|
||||
|
|
@ -32,19 +32,19 @@ frappe.search.UnifiedSearch = Class.extend({
|
|||
$this.data('timeout', setTimeout(function(){
|
||||
var keywords = me.input.val();
|
||||
me.reset();
|
||||
if(keywords.length > 1) {
|
||||
if(keywords.length > 2) {
|
||||
me.build_results(keywords);
|
||||
} else {
|
||||
me.current_type = '';
|
||||
}
|
||||
}, 250));
|
||||
}, 600));
|
||||
});
|
||||
this.build_results(keywords);
|
||||
setTimeout(function() { me.input.select(); }, 500);
|
||||
},
|
||||
|
||||
reset: function() {
|
||||
this.sidebar.empty();
|
||||
this.sidelist.empty();
|
||||
this.results_area.empty();
|
||||
},
|
||||
|
||||
|
|
@ -59,7 +59,9 @@ frappe.search.UnifiedSearch = Class.extend({
|
|||
render_results: function(results_obj, keywords){
|
||||
var me = this;
|
||||
if(this.current === 0) { this.reset() }
|
||||
this.sidebar.append(results_obj.sidelist);
|
||||
results_obj.sidelist.forEach(function(list_item) {
|
||||
me.sidelist.append(list_item);
|
||||
})
|
||||
this.results_area.find('.results-status').remove();
|
||||
results_obj.sections.forEach(function(section) {
|
||||
me.summary.append(section);
|
||||
|
|
@ -70,18 +72,35 @@ frappe.search.UnifiedSearch = Class.extend({
|
|||
|
||||
bind_events: function() {
|
||||
var me = this;
|
||||
this.sidebar.find('.list-link').on('click', function() {
|
||||
me.set_sidebar_link_action($(this));
|
||||
this.results_area.on('scroll', function() {
|
||||
if(me.results_area.find('.all-results-link').length !== 0) {
|
||||
return;
|
||||
}
|
||||
var r = me.results_area.find('.module-section')[1];
|
||||
me.results_area.find('.module-section').each(function() {
|
||||
if(($(this).position().top < 120) && ($(this).position().top + $(this).height() > 120)) {
|
||||
var types = $(this).attr('data-type').split(',');
|
||||
me.sidelist.find('.list-link').removeClass('active');
|
||||
types.forEach(function(type) {
|
||||
me.sidelist.find('*[data-category="'+ type +'"]').addClass('active');
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
this.sidelist.find('.list-link').on('click', function() {
|
||||
me.set_sidelist_link_action($(this));
|
||||
});
|
||||
this.results_area.find('.section-more').on('click', function() {
|
||||
var type = $(this).attr('data-category');
|
||||
me.sidebar.find('*[data-category="'+ type +'"]').trigger('click');
|
||||
me.sidelist.find('*[data-category="'+ type +'"]').trigger('click');
|
||||
});
|
||||
},
|
||||
|
||||
set_sidebar_link_action: function(link) {
|
||||
this.sidebar.find(".list-link a").removeClass("disabled");
|
||||
link.find('a').addClass("disabled");
|
||||
set_sidelist_link_action: function(link) {
|
||||
this.sidelist.find(".list-link").removeClass("active");
|
||||
this.sidelist.find(".list-link i").addClass("hide");
|
||||
link.addClass("active");
|
||||
link.find("i").removeClass("hide");
|
||||
var type = link.attr('data-category');
|
||||
this.results_area.empty().html(this.full_lists[type]);
|
||||
|
||||
|
|
@ -101,6 +120,9 @@ frappe.search.UnifiedSearch = Class.extend({
|
|||
|
||||
show_summary: function() {
|
||||
this.current_type = '';
|
||||
this.sidelist.find(".list-link i").addClass("hide");
|
||||
this.sidelist.find(".list-link").removeClass("active");
|
||||
this.sidelist.find(".list-link").first().addClass("active");
|
||||
this.results_area.empty().html(this.summary);
|
||||
this.bind_events();
|
||||
},
|
||||
|
|
@ -125,7 +147,7 @@ frappe.search.UnifiedSearch = Class.extend({
|
|||
var no_of_results = this.results_area.find('.result').length;
|
||||
var no_of_results_cue = $('<p class="results-status text-muted small">'+
|
||||
no_of_results +' results found</p>');
|
||||
this.results_area.find(".result:last").append(no_of_results_cue);
|
||||
this.results_area.find(".more-results:last").append(no_of_results_cue);
|
||||
}
|
||||
this.results_area.find('.more-results.last').slideDown(200, function() {
|
||||
var height = me.results_area.find('.module-body').height() - 750;
|
||||
|
|
@ -144,20 +166,20 @@ frappe.search.UnifiedSearch = Class.extend({
|
|||
// More searches to go
|
||||
this.search_objects[this.current].build_results_object(this, keywords);
|
||||
} else {
|
||||
// If there's only one link in sidebar, there's no summary (show its full list)
|
||||
if(this.sidebar.find('.list-link').length === 1) {
|
||||
// If there's only one link in sidelist, there's no summary (show its full list)
|
||||
if(this.sidelist.find('.list-link').length === 1) {
|
||||
this.bind_events();
|
||||
this.sidebar.find('.list-link').trigger('click');
|
||||
this.sidelist.find('.list-link').trigger('click');
|
||||
this.results_area.find('.all-results-link').hide();
|
||||
|
||||
} else if (this.sidebar.find('.list-link').length === 0) {
|
||||
} else if (this.sidelist.find('.list-link').length === 0) {
|
||||
this.results_area.html('<p class="results-status text-muted" style="text-align: center;">'+
|
||||
'No results found for: '+ "'"+ keywords +"'" +'</p>');
|
||||
} else {
|
||||
var list_types = this.get_all_list_types();
|
||||
if(list_types.indexOf(this.current_type) >= 0) {
|
||||
this.bind_events();
|
||||
this.sidebar.find('*[data-category="'+ this.current_type +'"]').trigger('click');
|
||||
this.sidelist.find('*[data-category="'+ this.current_type +'"]').trigger('click');
|
||||
} else {
|
||||
this.show_summary();
|
||||
}
|
||||
|
|
@ -167,7 +189,7 @@ frappe.search.UnifiedSearch = Class.extend({
|
|||
|
||||
get_all_list_types: function() {
|
||||
var types = [];
|
||||
this.sidebar.find('.list-link').each(function() {
|
||||
this.sidelist.find('.list-link').each(function() {
|
||||
types.push($(this).attr('data-category'));
|
||||
});
|
||||
return types;
|
||||
|
|
@ -214,18 +236,16 @@ frappe.search.GlobalSearch = Class.extend({
|
|||
|
||||
make_sidelist: function() {
|
||||
var me = this;
|
||||
var sidelist = $('<ul class="list-unstyled sidebar-menu nav-list"></ul>');
|
||||
sidelist.append('<li class="h6">'+ me.search_type +'</li>');
|
||||
var sidelist = [];
|
||||
this.types.forEach(function(type) {
|
||||
sidelist.append(me.make_sidelist_item(type));
|
||||
sidelist.push(me.make_sidelist_item(type));
|
||||
});
|
||||
sidelist.append('<li class="divider"></li>');
|
||||
return sidelist;
|
||||
},
|
||||
|
||||
make_sidelist_item: function(type) {
|
||||
var sidelist_item = '<li class="list-link" data-search="{0}"' +
|
||||
'data-category="{1}"><a>{1}</a></li>';
|
||||
var sidelist_item = '<li class="strong module-sidebar-item list-link" data-search="{0}"' +
|
||||
'data-category="{1}"><a><span>{1}</span><i class="fa fa-chevron-right pull-right hide"></a></li>';
|
||||
return $(__(sidelist_item, [this.search_type, type]));
|
||||
},
|
||||
|
||||
|
|
@ -319,7 +339,7 @@ frappe.search.GlobalSearch = Class.extend({
|
|||
|
||||
make_section: function(type, results) {
|
||||
var me = this;
|
||||
var results_section = $('<div class="row module-section '+type+'-section">'+
|
||||
var results_section = $('<div class="row module-section" data-type="'+type+'">'+
|
||||
'<div class="col-sm-12 module-section-column">' +
|
||||
'<div class="h4 section-head">'+type+'</div>' +
|
||||
'<div class="section-body"></div>'+
|
||||
|
|
@ -329,27 +349,53 @@ frappe.search.GlobalSearch = Class.extend({
|
|||
results_col.append(me.make_result_item(type, result));
|
||||
});
|
||||
if(results.length > this.section_length) {
|
||||
results_col.append('<a class="small section-more" data-category="'
|
||||
+ type + '">More...</a>');
|
||||
results_col.append('<button class="btn btn-default btn-xs text-muted section-more" data-category="'
|
||||
+ type + '" style="margin-top:10px">More...</button>');
|
||||
|
||||
}
|
||||
return results_section;
|
||||
},
|
||||
|
||||
make_result_subtypes_property: function(results) {
|
||||
var compressed_results = [];
|
||||
var labels = [];
|
||||
results.forEach(function(r) {
|
||||
if(labels.indexOf(r.label) === -1) {
|
||||
labels.push(r.label);
|
||||
}
|
||||
});
|
||||
labels.forEach(function(l) {
|
||||
var item_group = {
|
||||
title: l,
|
||||
subtypes: []
|
||||
};
|
||||
results.forEach(function(r) {
|
||||
if (r.label === l) {
|
||||
item_group.subtypes.push(r);
|
||||
}
|
||||
});
|
||||
compressed_results.push(item_group);
|
||||
});
|
||||
return compressed_results;
|
||||
},
|
||||
|
||||
make_full_list: function(type, results, more) {
|
||||
var me = this;
|
||||
var results_list = $(' <div class="module-body"><div class="row module-section '+
|
||||
var results_list = $(' <div class="module-body"><div class="row module-section full-list '+
|
||||
type+'-section">'+'<div class="col-sm-12 module-section-column">' +
|
||||
'<div class="back-link"><a class="all-results-link small"> All Results</a></div>' +
|
||||
'<div class="h4 section-head">'+type+'</div>' +
|
||||
'<div class="section-body"></div>'+
|
||||
'</div></div></div>');
|
||||
'<div class="section-body"></div></div></div></div>');
|
||||
if(type === "Lists") {
|
||||
results = this.make_result_subtypes_property(results);
|
||||
}
|
||||
var results_col = results_list.find('.module-section-column');
|
||||
results.forEach(function(result) {
|
||||
results_col.append(me.make_result_item(type, result));
|
||||
});
|
||||
if(more) {
|
||||
results_col.append('<a class="small list-more" data-search="'+ this.search_type +'" data-category="'
|
||||
+ type + '">More...</a>');
|
||||
results_col.append('<button class="btn btn-default btn-xs text-muted list-more" data-search="'+
|
||||
this.search_type +'" data-category="'+ type + '" style="margin-top:10px"> More...</button>');
|
||||
}
|
||||
return results_list;
|
||||
},
|
||||
|
|
@ -386,7 +432,6 @@ frappe.search.GlobalSearch = Class.extend({
|
|||
},
|
||||
|
||||
get_awesome_bar_options: function(keywords, ref) {
|
||||
|
||||
var me = this;
|
||||
var doctypes = [];
|
||||
var current = 0;
|
||||
|
|
@ -426,7 +471,7 @@ frappe.search.GlobalSearch = Class.extend({
|
|||
if(current < doctypes.length) {
|
||||
get_results();
|
||||
} else {
|
||||
ref.set_global_results(results);
|
||||
ref.set_global_results(results, keywords);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -434,13 +479,13 @@ frappe.search.GlobalSearch = Class.extend({
|
|||
};
|
||||
|
||||
var make_option = function(data) {
|
||||
console.log("GS search", me.get_finds(data.content, keywords).slice(0,86) + '...');
|
||||
return {
|
||||
label: __("{0}: {1}", [__(data.doctype).bold(), data.name]),
|
||||
value: __("{0}: {1}", [__(data.doctype), data.name]),
|
||||
route: ["Form", data.doctype, data.name],
|
||||
match: data.doctype,
|
||||
index: 5,
|
||||
index: 41,
|
||||
default: "Global",
|
||||
description: me.get_finds(data.content, keywords).slice(0,86) + '...'
|
||||
}
|
||||
};
|
||||
|
|
@ -455,7 +500,6 @@ frappe.search.NavSearch = frappe.search.GlobalSearch.extend({
|
|||
init: function() {
|
||||
this.search_type = 'Navigation';
|
||||
},
|
||||
|
||||
set_types: function() {
|
||||
var me = this;
|
||||
this.section_length = 4;
|
||||
|
|
@ -520,9 +564,47 @@ frappe.search.NavSearch = frappe.search.GlobalSearch.extend({
|
|||
},
|
||||
|
||||
make_result_item: function(type, result) {
|
||||
var link_html = '<div class="result '+ type +'-result single-link">' +
|
||||
'<a href="{0}" class="module-section-link small">{1}</a>' +
|
||||
'<p class="small"></p></div>';
|
||||
if(!result.subtypes) {
|
||||
var link_html = '<div class="result '+ type +'-result single-link">' +
|
||||
'<a href="{0}" class="module-section-link small">{1}</a>' +
|
||||
'<p class="small"></p></div>';
|
||||
return this.make_result_link(type, result, link_html);
|
||||
|
||||
} else {
|
||||
var result_div = $('<div class="result '+ type +'-result single-link"></div>');
|
||||
var button_html = '<button class="btn btn-default btn-xs text-muted result-subtype"'+
|
||||
'>{0}</button>'
|
||||
result.subtypes.forEach(function(s) {
|
||||
if(["Gantt", "Report", "Calendar"].indexOf(s.type) !== -1) {
|
||||
var button = $(__(button_html, [s.type]));
|
||||
button.on('click', function() {
|
||||
if(s.route_options) {
|
||||
frappe.route_options = s.route_options;
|
||||
}
|
||||
frappe.set_route(s.route);
|
||||
return false;
|
||||
});
|
||||
result_div.append(button);
|
||||
} else {
|
||||
title_link_html = '<a href="{0}" class="module-section-link small">{1}</a>';
|
||||
var link = $(__(title_link_html, ['#', result.title + ' ' + s.type]));
|
||||
link.on('click', function() {
|
||||
if(s.route_options) {
|
||||
frappe.route_options = s.route_options;
|
||||
}
|
||||
frappe.set_route(s.route);
|
||||
return false;
|
||||
});
|
||||
result_div.append(link);
|
||||
}
|
||||
})
|
||||
result_div.append($('<p class="small"></p>'));
|
||||
return result_div;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
make_result_link: function(type, result, link_html) {
|
||||
if(!result.onclick) {
|
||||
var link = $(__(link_html, ['#', result.label]));
|
||||
link.on('click', function() {
|
||||
|
|
@ -545,9 +627,14 @@ frappe.search.NavSearch = frappe.search.GlobalSearch.extend({
|
|||
|
||||
make_dual_sections: function() {
|
||||
this.dual_sections = [];
|
||||
var section_html = '<div class="row module-section dual-section"></div>';
|
||||
for(var i = 0; i < this.sections.length; i++) {
|
||||
var results_section = $(section_html);
|
||||
var types;
|
||||
if(i+1 < this.types.length) {
|
||||
types = this.types[i] + ',' + this.types[i+1];
|
||||
} else {
|
||||
types = this.types[i];
|
||||
}
|
||||
var results_section = $('<div class="row module-section dual-section" data-type="'+ types +'"></div>');
|
||||
for(var j = 0; j < 2 && i < this.sections.length; j++, i++){
|
||||
results_section.append(this.sections[i]);
|
||||
}
|
||||
|
|
@ -574,12 +661,15 @@ frappe.search.NavSearch = frappe.search.GlobalSearch.extend({
|
|||
'<div class="h4 section-head">'+type+'</div>' +
|
||||
'<div class="section-body"></div>'+
|
||||
'</div>');
|
||||
if(type === "Lists") {
|
||||
results = this.make_result_subtypes_property(results);
|
||||
}
|
||||
results.slice(0, this.section_length).forEach(function(result) {
|
||||
results_column.append(me.make_result_item(type, result));
|
||||
});
|
||||
if(results.length > this.section_length) {
|
||||
results_column.append('<a class="small section-more" data-category="'
|
||||
+ type + '">More...</a>');
|
||||
results_column.append('<button class="btn btn-default btn-xs text-muted section-more" data-category="'
|
||||
+ type + '" style="margin-top:10px">More...</button>');
|
||||
}
|
||||
return results_column;
|
||||
}
|
||||
|
|
@ -597,12 +687,11 @@ frappe.search.HelpSearch = frappe.search.GlobalSearch.extend({
|
|||
},
|
||||
|
||||
make_sidelist: function() {
|
||||
var sidelist = $('<ul class="list-unstyled sidebar-menu nav-list"></ul>');
|
||||
var sidelist_item = '<li class="h6 list-link" data-search="'+ this.search_type + '"' +
|
||||
'data-category="'+ this.search_type + '"><a style="font-size: 11px;">'+
|
||||
this.search_type +'</a></li>';
|
||||
sidelist.append(sidelist_item);
|
||||
sidelist.append('<li class="divider"></li>');
|
||||
var sidelist = [];
|
||||
var sidelist_item = '<li class="strong module-sidebar-item list-link help-link" '+
|
||||
'data-search="'+ this.search_type + '" data-category="'+ this.search_type + '"><a><span>'+
|
||||
this.search_type +'</span><i class="fa fa-chevron-right pull-right hide"></a></li>';
|
||||
sidelist.push(sidelist_item);
|
||||
return sidelist;
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -563,12 +563,26 @@ textarea.form-control {
|
|||
}
|
||||
|
||||
.layout-side-section {
|
||||
padding-left: 15px;
|
||||
.help-link {
|
||||
padding-top: 20px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.nav > li > a {
|
||||
padding-left: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.results-area {
|
||||
a {
|
||||
color: #5E64FF;
|
||||
}
|
||||
|
||||
.single-link a {
|
||||
color: #36414c;
|
||||
}
|
||||
}
|
||||
|
||||
// .results-area a {
|
||||
// color: #5E64FF;
|
||||
// }
|
||||
.module-section {
|
||||
.back-link {
|
||||
margin-bottom: 20px;
|
||||
|
|
@ -580,13 +594,29 @@ textarea.form-control {
|
|||
content: '\f0a4';
|
||||
}
|
||||
}
|
||||
.dual-section .result a {
|
||||
color: black;
|
||||
|
||||
.full-list {
|
||||
.result {
|
||||
border-bottom: 1px solid #d1d8dd;
|
||||
margin-top: 10px;
|
||||
|
||||
.result-subtype{
|
||||
float: right;
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.section-head {
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
}
|
||||
|
||||
.dual-section .result a b{
|
||||
color: #4e6161;
|
||||
.dual-section {
|
||||
.result-subtype{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.result-status {
|
||||
margin-top: 30px;
|
||||
text-align: center;
|
||||
|
|
|
|||
|
|
@ -148,4 +148,5 @@ def search_in_doctype(doctype, text, start, limit):
|
|||
doctype = %s AND
|
||||
match(content) against (%s IN BOOLEAN MODE)
|
||||
limit {start}, {limit}'''.format(start=start, limit=limit), (doctype, text), as_dict=True)
|
||||
return results
|
||||
|
||||
return results
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue