mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-08 12:12:48 +01:00
Added fuzzy search using fuse.js
This commit is contained in:
parent
d465c0d019
commit
6a9b2130c5
@ -95,13 +95,14 @@ module.exports = function(grunt) {
|
||||
'public/vendor/bootstrap-datepicker/dist/locales/bootstrap-datepicker.no.min.js',
|
||||
'public/vendor/bootstrap-datepicker/dist/locales/bootstrap-datepicker.es.min.js',
|
||||
'public/vendor/bootstrap-datepicker/dist/locales/bootstrap-datepicker.sv.min.js',
|
||||
'public/vendor/typeahead.js/dist/typeahead.min.js',
|
||||
'public/vendor/typeahead.js/dist/typeahead.jquery.min.js',
|
||||
'public/vendor/accounting/accounting.min.js',
|
||||
'public/vendor/spectrum/spectrum.js',
|
||||
'public/vendor/jspdf/dist/jspdf.min.js',
|
||||
'public/vendor/moment/min/moment.min.js',
|
||||
'public/vendor/moment-timezone/builds/moment-timezone-with-data.min.js',
|
||||
'public/vendor/stacktrace-js/dist/stacktrace-with-polyfills.min.js',
|
||||
'public/vendor/fuse.js/src/fuse.min.js',
|
||||
//'public/vendor/moment-duration-format/lib/moment-duration-format.js',
|
||||
//'public/vendor/handsontable/dist/jquery.handsontable.full.min.js',
|
||||
//'public/vendor/pdfmake/build/pdfmake.min.js',
|
||||
|
@ -74,8 +74,7 @@ class AccountRepository
|
||||
{
|
||||
$data = $this->getAccountSearchData();
|
||||
|
||||
$type = trans('texts.navigation');
|
||||
$data[$type] = $this->getNavigationSearchData();
|
||||
$data['navigation'] = $this->getNavigationSearchData();
|
||||
|
||||
return $data;
|
||||
}
|
||||
@ -83,10 +82,10 @@ class AccountRepository
|
||||
private function getAccountSearchData()
|
||||
{
|
||||
$data = [
|
||||
trans('texts.clients') => [],
|
||||
trans('texts.contacts') => [],
|
||||
trans('texts.invoices') => [],
|
||||
trans('texts.quotes') => [],
|
||||
'clients' => [],
|
||||
'contacts' => [],
|
||||
'invoices' => [],
|
||||
'quotes' => [],
|
||||
];
|
||||
|
||||
$clients = Client::scope()
|
||||
@ -95,26 +94,31 @@ class AccountRepository
|
||||
|
||||
foreach ($clients as $client) {
|
||||
if ($client->name) {
|
||||
$data[trans('texts.clients')][] = [
|
||||
$data['clients'][] = [
|
||||
'value' => $client->name,
|
||||
'tokens' => explode(' ', $client->name),
|
||||
'url' => $client->present()->url,
|
||||
];
|
||||
}
|
||||
|
||||
foreach ($client->contacts as $contact) {
|
||||
$data[trans('texts.contacts')][] = [
|
||||
'value' => $contact->getDisplayName(),
|
||||
'tokens' => explode(' ', $contact->getFullName() . ' ' . $contact->email),
|
||||
'url' => $client->present()->url,
|
||||
];
|
||||
if ($contact->getFullName()) {
|
||||
$data['contacts'][] = [
|
||||
'value' => $contact->getDisplayName(),
|
||||
'url' => $client->present()->url,
|
||||
];
|
||||
}
|
||||
if ($contact->email) {
|
||||
$data[trans('texts.contacts')][] = [
|
||||
'value' => $contact->email,
|
||||
'url' => $client->present()->url,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($client->invoices as $invoice) {
|
||||
$entityType = $invoice->getEntityType();
|
||||
$data[trans("texts.{$entityType}s")][] = [
|
||||
$data["{$entityType}s"][] = [
|
||||
'value' => $invoice->getDisplayName() . ': ' . $client->getDisplayName(),
|
||||
'tokens' => explode(' ', $invoice->invoice_number . ' ' . intval($invoice->invoice_number) . ' ' . $client->getDisplayName()),
|
||||
'url' => $invoice->present()->url,
|
||||
];
|
||||
}
|
||||
|
@ -14,7 +14,7 @@
|
||||
"underscore": "1.7.0",
|
||||
"jspdf": "1.0.272",
|
||||
"bootstrap-datepicker": "1.4.0",
|
||||
"typeahead.js": "0.9.3",
|
||||
"typeahead.js": "0.11.1",
|
||||
"accounting": "0.3.2",
|
||||
"spectrum": "1.3.4",
|
||||
"d3": "3.4.11",
|
||||
@ -25,7 +25,8 @@
|
||||
"moment-timezone": "~0.4.0",
|
||||
"quill": "~0.20.0",
|
||||
"datetimepicker": "~2.4.5",
|
||||
"stacktrace-js": "~1.0.1"
|
||||
"stacktrace-js": "~1.0.1",
|
||||
"fuse.js": "~2.0.2"
|
||||
},
|
||||
"resolutions": {
|
||||
"jquery": "~1.11"
|
||||
|
File diff suppressed because one or more lines are too long
125
public/css/built.css
vendored
125
public/css/built.css
vendored
@ -2054,89 +2054,76 @@ See http://bgrins.github.io/spectrum/themes/ for instructions.
|
||||
.combobox-container:not(.combobox-selected) .fa-times {
|
||||
display: none;
|
||||
}
|
||||
.twitter-typeahead .tt-query,
|
||||
.twitter-typeahead .tt-hint {
|
||||
margin-bottom: 0;
|
||||
/**********************************************************
|
||||
* typeahead.js v0.11.1 - twitter bootstrap v3.3.5 *
|
||||
**********************************************************/
|
||||
|
||||
/*root typeahead class*/
|
||||
.twitter-typeahead {
|
||||
display: inherit !important;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.tt-dropdown-menu {
|
||||
min-width: 160px;
|
||||
margin-top: 2px;
|
||||
padding: 5px 0;
|
||||
background-color: #fff;
|
||||
border: 1px solid #ccc;
|
||||
border: 1px solid rgba(0,0,0,.2);
|
||||
*border-right-width: 2px;
|
||||
*border-bottom-width: 2px;
|
||||
-webkit-border-radius: 6px;
|
||||
-moz-border-radius: 6px;
|
||||
border-radius: 6px;
|
||||
-webkit-box-shadow: 0 5px 10px rgba(0,0,0,.2);
|
||||
-moz-box-shadow: 0 5px 10px rgba(0,0,0,.2);
|
||||
box-shadow: 0 5px 10px rgba(0,0,0,.2);
|
||||
-webkit-background-clip: padding-box;
|
||||
-moz-background-clip: padding;
|
||||
background-clip: padding-box;
|
||||
.twitter-typeahead .tt-input[disabled] {
|
||||
background-color : #eeeeee !important;
|
||||
}
|
||||
|
||||
.tt-suggestion {
|
||||
display: block;
|
||||
/*Added to input that's initialized into a typeahead*/
|
||||
.twitter-typeahead .tt-input {
|
||||
|
||||
}
|
||||
|
||||
/*Added to hint input.*/
|
||||
.twitter-typeahead .hint {
|
||||
|
||||
}
|
||||
|
||||
/*Added to menu element*/
|
||||
.twitter-typeahead .tt-menu {
|
||||
width: 100%;
|
||||
max-height: 500px;
|
||||
overflow-y: none;
|
||||
border: 1px solid #cccccc;
|
||||
border-radius:4px;
|
||||
|
||||
-moz-box-shadow: 12px 14px 30px -7px #616161;
|
||||
-webkit-box-shadow: 12px 14px 30px -7px #616161;
|
||||
box-shadow: 12px 14px 30px -7px #616161;
|
||||
}
|
||||
|
||||
/*Added to dataset elements*/
|
||||
.twitter-typeahead .tt-dataset {
|
||||
|
||||
}
|
||||
|
||||
/*dded to suggestion elements*/
|
||||
.twitter-typeahead .tt-suggestion {
|
||||
padding: 3px 20px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.tt-suggestion.tt-is-under-cursor {
|
||||
color: #fff;
|
||||
background-color: #0081c2;
|
||||
background-image: -moz-linear-gradient(top, #0088cc, #0077b3);
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3));
|
||||
background-image: -webkit-linear-gradient(top, #0088cc, #0077b3);
|
||||
background-image: -o-linear-gradient(top, #0088cc, #0077b3);
|
||||
background-image: linear-gradient(to bottom, #0088cc, #0077b3);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0)
|
||||
/*Added to menu element when it contains no content*/
|
||||
.twitter-typeahead .tt-empty {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.tt-suggestion.tt-is-under-cursor a {
|
||||
color: #fff;
|
||||
/*Added to menu element when it is opened*/
|
||||
.twitter-typeahead .tt-open {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.tt-suggestion p {
|
||||
margin: 0;
|
||||
/*Added to suggestion element when menu cursor moves to said suggestion*/
|
||||
.twitter-typeahead .tt-suggestion:hover,
|
||||
.twitter-typeahead .tt-suggestion:focus,
|
||||
.twitter-typeahead .tt-cursor {
|
||||
cursor: hand !important;
|
||||
background-color: #337ab7;
|
||||
color: white;
|
||||
}
|
||||
|
||||
/*
|
||||
.tt-hint {
|
||||
padding: 6px 12px;
|
||||
}
|
||||
*/
|
||||
/*Added to the element that wraps highlighted text*/
|
||||
.twitter-typeahead .tt-highlight {
|
||||
|
||||
.twitter-typeahead .tt-hint
|
||||
{
|
||||
display: block;
|
||||
height: 34px;
|
||||
padding: 6px 12px;
|
||||
font-size: 14px;
|
||||
line-height: 1.428571429;
|
||||
border: 1px solid transparent;
|
||||
border-radius:4px;
|
||||
}
|
||||
|
||||
.twitter-typeahead .hint-small
|
||||
{
|
||||
height: 30px;
|
||||
padding: 5px 10px;
|
||||
font-size: 12px;
|
||||
border-radius: 3px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.twitter-typeahead .hint-large
|
||||
{
|
||||
height: 45px;
|
||||
padding: 10px 16px;
|
||||
font-size: 18px;
|
||||
border-radius: 6px;
|
||||
line-height: 1.33;
|
||||
}
|
||||
body { background: #f8f8f8 !important;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
|
125
public/css/typeahead.js-bootstrap.css
vendored
125
public/css/typeahead.js-bootstrap.css
vendored
@ -1,84 +1,71 @@
|
||||
.twitter-typeahead .tt-query,
|
||||
.twitter-typeahead .tt-hint {
|
||||
margin-bottom: 0;
|
||||
/**********************************************************
|
||||
* typeahead.js v0.11.1 - twitter bootstrap v3.3.5 *
|
||||
**********************************************************/
|
||||
|
||||
/*root typeahead class*/
|
||||
.twitter-typeahead {
|
||||
display: inherit !important;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.tt-dropdown-menu {
|
||||
min-width: 160px;
|
||||
margin-top: 2px;
|
||||
padding: 5px 0;
|
||||
background-color: #fff;
|
||||
border: 1px solid #ccc;
|
||||
border: 1px solid rgba(0,0,0,.2);
|
||||
*border-right-width: 2px;
|
||||
*border-bottom-width: 2px;
|
||||
-webkit-border-radius: 6px;
|
||||
-moz-border-radius: 6px;
|
||||
border-radius: 6px;
|
||||
-webkit-box-shadow: 0 5px 10px rgba(0,0,0,.2);
|
||||
-moz-box-shadow: 0 5px 10px rgba(0,0,0,.2);
|
||||
box-shadow: 0 5px 10px rgba(0,0,0,.2);
|
||||
-webkit-background-clip: padding-box;
|
||||
-moz-background-clip: padding;
|
||||
background-clip: padding-box;
|
||||
.twitter-typeahead .tt-input[disabled] {
|
||||
background-color : #eeeeee !important;
|
||||
}
|
||||
|
||||
.tt-suggestion {
|
||||
display: block;
|
||||
/*Added to input that's initialized into a typeahead*/
|
||||
.twitter-typeahead .tt-input {
|
||||
|
||||
}
|
||||
|
||||
/*Added to hint input.*/
|
||||
.twitter-typeahead .hint {
|
||||
|
||||
}
|
||||
|
||||
/*Added to menu element*/
|
||||
.twitter-typeahead .tt-menu {
|
||||
width: 100%;
|
||||
max-height: 500px;
|
||||
overflow-y: none;
|
||||
border: 1px solid #cccccc;
|
||||
border-radius:4px;
|
||||
|
||||
-moz-box-shadow: 12px 14px 30px -7px #616161;
|
||||
-webkit-box-shadow: 12px 14px 30px -7px #616161;
|
||||
box-shadow: 12px 14px 30px -7px #616161;
|
||||
}
|
||||
|
||||
/*Added to dataset elements*/
|
||||
.twitter-typeahead .tt-dataset {
|
||||
|
||||
}
|
||||
|
||||
/*dded to suggestion elements*/
|
||||
.twitter-typeahead .tt-suggestion {
|
||||
padding: 3px 20px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.tt-suggestion.tt-is-under-cursor {
|
||||
color: #fff;
|
||||
background-color: #0081c2;
|
||||
background-image: -moz-linear-gradient(top, #0088cc, #0077b3);
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3));
|
||||
background-image: -webkit-linear-gradient(top, #0088cc, #0077b3);
|
||||
background-image: -o-linear-gradient(top, #0088cc, #0077b3);
|
||||
background-image: linear-gradient(to bottom, #0088cc, #0077b3);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0)
|
||||
/*Added to menu element when it contains no content*/
|
||||
.twitter-typeahead .tt-empty {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.tt-suggestion.tt-is-under-cursor a {
|
||||
color: #fff;
|
||||
/*Added to menu element when it is opened*/
|
||||
.twitter-typeahead .tt-open {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.tt-suggestion p {
|
||||
margin: 0;
|
||||
/*Added to suggestion element when menu cursor moves to said suggestion*/
|
||||
.twitter-typeahead .tt-suggestion:hover,
|
||||
.twitter-typeahead .tt-suggestion:focus,
|
||||
.twitter-typeahead .tt-cursor {
|
||||
cursor: hand !important;
|
||||
background-color: #337ab7;
|
||||
color: white;
|
||||
}
|
||||
|
||||
/*
|
||||
.tt-hint {
|
||||
padding: 6px 12px;
|
||||
}
|
||||
*/
|
||||
/*Added to the element that wraps highlighted text*/
|
||||
.twitter-typeahead .tt-highlight {
|
||||
|
||||
.twitter-typeahead .tt-hint
|
||||
{
|
||||
display: block;
|
||||
height: 34px;
|
||||
padding: 6px 12px;
|
||||
font-size: 14px;
|
||||
line-height: 1.428571429;
|
||||
border: 1px solid transparent;
|
||||
border-radius:4px;
|
||||
}
|
||||
|
||||
.twitter-typeahead .hint-small
|
||||
{
|
||||
height: 30px;
|
||||
padding: 5px 10px;
|
||||
font-size: 12px;
|
||||
border-radius: 3px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.twitter-typeahead .hint-large
|
||||
{
|
||||
height: 45px;
|
||||
padding: 10px 16px;
|
||||
font-size: 18px;
|
||||
border-radius: 6px;
|
||||
line-height: 1.33;
|
||||
}
|
@ -68,6 +68,8 @@ We're using the [Git-Flow](http://nvie.com/posts/a-successful-git-branching-mode
|
||||
* [patricktalmadge/bootstrapper](https://github.com/patricktalmadge/bootstrapper) - Laravel Twitter Bootstrap Bundle
|
||||
* [danielfarrell/bootstrap-combobox](https://github.com/danielfarrell/bootstrap-combobox) - A combobox plugin
|
||||
* [eternicode/bootstrap-datepicker](https://github.com/eternicode/bootstrap-datepicker) - A datepicker for @twitter bootstrap
|
||||
* [twitter/typeahead.js](https://github.com/twitter/typeahead.js) - a fast and fully-featured autocomplete library
|
||||
* [krisk/Fuse](https://github.com/krisk/Fuse) - Lightweight fuzzy-search, in JavaScript
|
||||
* [knockout/knockout](https://github.com/knockout/knockout) - Knockout makes it easier to create rich, responsive UIs with JavaScript
|
||||
* [rniemeyer/knockout-sortable](https://github.com/rniemeyer/knockout-sortable) - A Knockout.js binding to connect observableArrays with jQuery UI sortable functionality
|
||||
* [bpampuch/pdfmake](https://github.com/bpampuch/pdfmake) - Client/server side PDF printing in pure JavaScript
|
||||
|
@ -259,37 +259,84 @@
|
||||
}
|
||||
|
||||
function showSearch() {
|
||||
$('#search').typeahead('setQuery', '');
|
||||
console.log('showSearch..');
|
||||
//$('#search').typeahead('setQuery', '');
|
||||
$('#navbar-options').hide();
|
||||
$('#search-form').show();
|
||||
|
||||
if (window.hasOwnProperty('searchData')) {
|
||||
if (window.hasOwnProperty('loadedSearchData')) {
|
||||
console.log('has data');
|
||||
$('#search').focus();
|
||||
} else {
|
||||
trackEvent('/activity', '/search');
|
||||
$.get('{{ URL::route('getSearchData') }}', function(data) {
|
||||
console.log(data);
|
||||
window.searchData = true;
|
||||
var datasets = [];
|
||||
for (var type in data)
|
||||
window.loadedSearchData = true;
|
||||
|
||||
$('#search').typeahead({
|
||||
hint: true,
|
||||
highlight: true,
|
||||
},
|
||||
{
|
||||
if (!data.hasOwnProperty(type)) continue;
|
||||
datasets.push({
|
||||
name: type,
|
||||
header: ' <b>' + type + '</b>',
|
||||
local: data[type]
|
||||
});
|
||||
}
|
||||
if (datasets.length == 0) {
|
||||
return;
|
||||
}
|
||||
$('#search').typeahead(datasets).on('typeahead:selected', function(element, datum, name) {
|
||||
name: 'data',
|
||||
display: 'value',
|
||||
source: searchData(data['clients']),
|
||||
templates: {
|
||||
header: ' <b>{{ trans('texts.clients') }}</b>'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'data',
|
||||
display: 'value',
|
||||
source: searchData(data['contacts']),
|
||||
templates: {
|
||||
header: ' <b>{{ trans('texts.contacts') }}</b>'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'data',
|
||||
display: 'value',
|
||||
source: searchData(data['invoices']),
|
||||
templates: {
|
||||
header: ' <b>{{ trans('texts.contacts') }}</b>'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'data',
|
||||
display: 'value',
|
||||
source: searchData(data['quotes']),
|
||||
templates: {
|
||||
header: ' <b>{{ trans('texts.quotes') }}</b>'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'data',
|
||||
display: 'value',
|
||||
source: searchData(data['navigation']),
|
||||
templates: {
|
||||
header: ' <b>{{ trans('texts.navigation') }}</b>'
|
||||
}
|
||||
}).on('typeahead:selected', function(element, datum, name) {
|
||||
window.location = datum.url;
|
||||
}).focus().typeahead('setQuery', $('#search').val());
|
||||
}).focus();
|
||||
|
||||
//.typeahead('setQuery', $('#search').val());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function searchData(data) {
|
||||
return function findMatches(q, cb) {
|
||||
|
||||
var options = {
|
||||
keys: ['value'],
|
||||
}
|
||||
var fuse = new Fuse(data, options);
|
||||
var matches = fuse.search(q);
|
||||
|
||||
cb(matches);
|
||||
}
|
||||
};
|
||||
|
||||
function hideSearch() {
|
||||
$('#search-form').hide();
|
||||
$('#navbar-options').show();
|
||||
|
Loading…
Reference in New Issue
Block a user