[IMP] web: replace fuzzy lib
This commit is contained in:
@@ -96,7 +96,6 @@ This module provides the core of the Odoo Web Client.
|
||||
'web/static/src/env.js',
|
||||
|
||||
'web/static/lib/jquery.scrollTo/jquery.scrollTo.js',
|
||||
'web/static/lib/fuzzy-master/fuzzy.js',
|
||||
'web/static/lib/luxon/luxon.js',
|
||||
'web/static/lib/py.js/lib/py.js',
|
||||
'web/static/lib/py.js/lib/py_extras.js',
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
Copyright (c) 2012 Matt York
|
||||
|
||||
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.
|
||||
@@ -1,150 +0,0 @@
|
||||
/*
|
||||
* Fuzzy
|
||||
* https://github.com/myork/fuzzy
|
||||
*
|
||||
* Copyright (c) 2012 Matt York
|
||||
* Licensed under the MIT license.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
|
||||
var root = this;
|
||||
|
||||
var fuzzy = {};
|
||||
|
||||
// Use in node or in browser
|
||||
if (typeof exports !== 'undefined') {
|
||||
module.exports = fuzzy;
|
||||
} else {
|
||||
root.fuzzy = fuzzy;
|
||||
}
|
||||
|
||||
// Return all elements of `array` that have a fuzzy
|
||||
// match against `pattern`.
|
||||
fuzzy.simpleFilter = function(pattern, array) {
|
||||
return array.filter(function(string) {
|
||||
return fuzzy.test(pattern, string);
|
||||
});
|
||||
};
|
||||
|
||||
// Does `pattern` fuzzy match `string`?
|
||||
fuzzy.test = function(pattern, string) {
|
||||
return fuzzy.match(pattern, string) !== null;
|
||||
};
|
||||
|
||||
// If `pattern` matches `string`, wrap each matching character
|
||||
// in `opts.pre` and `opts.post`. If no match, return null
|
||||
fuzzy.match = function(pattern, string, opts) {
|
||||
opts = opts || {};
|
||||
var patternIdx = 0
|
||||
, result = []
|
||||
, len = string.length
|
||||
, totalScore = 0
|
||||
, currScore = 0
|
||||
// prefix
|
||||
, pre = opts.pre || ''
|
||||
// suffix
|
||||
, post = opts.post || ''
|
||||
// String to compare against. This might be a lowercase version of the
|
||||
// raw string
|
||||
, compareString = opts.caseSensitive && string || string.toLowerCase()
|
||||
, ch, compareChar;
|
||||
|
||||
pattern = opts.caseSensitive && pattern || pattern.toLowerCase();
|
||||
|
||||
// For each character in the string, either add it to the result
|
||||
// or wrap in template if it's the next string in the pattern
|
||||
for(var idx = 0; idx < len; idx++) {
|
||||
ch = string[idx];
|
||||
if(compareString[idx] === pattern[patternIdx]) {
|
||||
if (pattern[patternIdx] === ' ') {
|
||||
// we don't want a space character to accumulate a larger score
|
||||
currScore = 1 - idx/200;
|
||||
} else {
|
||||
// consecutive characters should increase the score more than linearly
|
||||
currScore += 1 + currScore - idx/200;
|
||||
}
|
||||
|
||||
ch = pre + ch + post;
|
||||
patternIdx += 1;
|
||||
} else {
|
||||
currScore = 0;
|
||||
}
|
||||
totalScore += currScore;
|
||||
if (compareString[idx] === ' ') {
|
||||
// we don't want characters after a space to accumulate a larger score
|
||||
currScore = 0;
|
||||
}
|
||||
result[result.length] = ch;
|
||||
}
|
||||
|
||||
// return rendered string if we have a match for every char
|
||||
if(patternIdx === pattern.length) {
|
||||
return {rendered: result.join(''), score: totalScore};
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
// The normal entry point. Filters `arr` for matches against `pattern`.
|
||||
// It returns an array with matching values of the type:
|
||||
//
|
||||
// [{
|
||||
// string: '<b>lah' // The rendered string
|
||||
// , index: 2 // The index of the element in `arr`
|
||||
// , original: 'blah' // The original element in `arr`
|
||||
// }]
|
||||
//
|
||||
// `opts` is an optional argument bag. Details:
|
||||
//
|
||||
// opts = {
|
||||
// // string to put before a matching character
|
||||
// pre: '<b>'
|
||||
//
|
||||
// // string to put after matching character
|
||||
// , post: '</b>'
|
||||
//
|
||||
// // Optional function. Input is an entry in the given arr`,
|
||||
// // output should be the string to test `pattern` against.
|
||||
// // In this example, if `arr = [{crying: 'koala'}]` we would return
|
||||
// // 'koala'.
|
||||
// , extract: function(arg) { return arg.crying; }
|
||||
// }
|
||||
fuzzy.filter = function(pattern, arr, opts) {
|
||||
if(!arr || arr.length === 0) {
|
||||
return []
|
||||
}
|
||||
if (typeof pattern !== 'string') {
|
||||
return arr
|
||||
}
|
||||
opts = opts || {};
|
||||
return arr
|
||||
.reduce(function(prev, element, idx, arr) {
|
||||
var str = element;
|
||||
if(opts.extract) {
|
||||
str = opts.extract(element);
|
||||
}
|
||||
var rendered = fuzzy.match(pattern, str, opts);
|
||||
if(rendered != null) {
|
||||
prev[prev.length] = {
|
||||
string: rendered.rendered
|
||||
, score: rendered.score
|
||||
, index: idx
|
||||
, original: element
|
||||
};
|
||||
}
|
||||
return prev;
|
||||
}, [])
|
||||
|
||||
// Sort by score. Browsers are inconsistent wrt stable/unstable
|
||||
// sorting, so force stable by using the index in the case of tie.
|
||||
// See http://ofb.net/~sethml/is-sort-stable.html
|
||||
.sort(function(a,b) {
|
||||
var compare = b.score - a.score;
|
||||
if(compare) return compare;
|
||||
return a.index - b.index;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
}());
|
||||
@@ -0,0 +1,59 @@
|
||||
/** @odoo-module */
|
||||
|
||||
/**
|
||||
* This private function computes a score that represent the fact that the
|
||||
* string contains the pattern, or not
|
||||
*
|
||||
* - If the score is 0, the string does not contain the letters of the pattern in
|
||||
* the correct order.
|
||||
* - if the score is > 0, it actually contains the letters.
|
||||
*
|
||||
* Better matches will get a higher score: consecutive letters are better,
|
||||
* and a match closer to the beginning of the string is also scored higher.
|
||||
*/
|
||||
function match(pattern, str) {
|
||||
let totalScore = 0;
|
||||
let currentScore = 0;
|
||||
let len = str.length;
|
||||
let patternIndex = 0;
|
||||
|
||||
pattern = pattern.toLowerCase();
|
||||
str = str.toLowerCase();
|
||||
|
||||
for (let i = 0; i < len; i++) {
|
||||
if (str[i] === pattern[patternIndex]) {
|
||||
patternIndex++;
|
||||
currentScore += 100 + currentScore - i / 200;
|
||||
} else {
|
||||
currentScore = 0;
|
||||
}
|
||||
totalScore = totalScore + currentScore;
|
||||
}
|
||||
|
||||
return patternIndex === pattern.length ? totalScore : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of things that matches a pattern, ordered by their 'score' (
|
||||
* higher score first). An higher score means that the match is better. For
|
||||
* example, consecutive letters are considered a better match.
|
||||
*/
|
||||
export function fuzzyLookup(pattern, list, fn) {
|
||||
const results = [];
|
||||
list.forEach((data) => {
|
||||
const score = match(pattern, fn(data));
|
||||
if (score > 0) {
|
||||
results.push({ score, elem: data });
|
||||
}
|
||||
});
|
||||
|
||||
// we want better matches first
|
||||
results.sort((a, b) => b.score - a.score);
|
||||
|
||||
return results.map((r) => r.elem);
|
||||
}
|
||||
|
||||
// Does `pattern` fuzzy match `string`?
|
||||
export function fuzzyTest(pattern, string) {
|
||||
return match(pattern, string) !== 0;
|
||||
}
|
||||
@@ -5,6 +5,7 @@ odoo.define('web.SearchBar', function (require) {
|
||||
const field_utils = require('web.field_utils');
|
||||
const { useAutofocus } = require('web.custom_hooks');
|
||||
const { useModel } = require('web.Model');
|
||||
const { fuzzyTest } = require('@web/core/utils/search');
|
||||
|
||||
const CHAR_FIELDS = ['char', 'html', 'many2many', 'many2one', 'one2many', 'text'];
|
||||
const { Component, hooks } = owl;
|
||||
@@ -199,7 +200,7 @@ odoo.define('web.SearchBar', function (require) {
|
||||
if (source.selection) {
|
||||
const options = [];
|
||||
source.selection.forEach(result => {
|
||||
if (fuzzy.test(query, result[1].toLowerCase())) {
|
||||
if (fuzzyTest(query, result[1].toLowerCase())) {
|
||||
options.push(this._createSubSource(source, result));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -3,6 +3,7 @@ odoo.define("web.ModelFieldSelector", function (require) {
|
||||
|
||||
var core = require("web.core");
|
||||
var Widget = require("web.Widget");
|
||||
const { fuzzyLookup } = require('@web/core/utils/search');
|
||||
|
||||
var _t = core._t;
|
||||
|
||||
@@ -381,10 +382,7 @@ var ModelFieldSelector = Widget.extend({
|
||||
|
||||
var lines = _.filter(page, this.options.filter);
|
||||
if (this.searchValue) {
|
||||
var matches = fuzzy.filter(this.searchValue, _.pluck(lines, 'string'));
|
||||
lines = _.map(_.pluck(matches, 'index'), function (i) {
|
||||
return lines[i];
|
||||
});
|
||||
lines = fuzzyLookup(this.searchValue, lines, (l) => l.string);
|
||||
}
|
||||
|
||||
this.$(".o_field_selector_page").replaceWith(core.qweb.render(this.template + ".page", {
|
||||
|
||||
Reference in New Issue
Block a user