algoliasearch-rails 1.9.3 → 1.9.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4c717e0d5fe37fae7e75570ceba23c498cecaa4f
4
- data.tar.gz: c16f748ce4eda2d00cdd79ca26615993c4b8a421
3
+ metadata.gz: 6826be3868adf59a195a87a6ff18d66368bc645d
4
+ data.tar.gz: 02d75cf295aa27237df63c1184e1fbf6ac936e75
5
5
  SHA512:
6
- metadata.gz: 50b34c87258d9849cedf846bc335b17f1e18bff4227ba539c6eed9db86e1c7eb6194694287107e0930df2a61e3a6cf8a26fe8437ce16da4de5c1ae3eee76ec4d
7
- data.tar.gz: 3046f5be4d6c3f169e2904274ef22a5ae0559b662ab06b59c5d8e7985d0feac59995a709e1c1a512a2a4120bbc3042e86e408ba80d9886affdde2ad1a8abf86c
6
+ metadata.gz: a4b81c53b990ca11d49242b5e2954e27d102568675cd4e06c0529bd21b1aae3bd9614c0a105ba6b44012c576e2ecaf45bf26dda67a342c54de5109e046dbaa87
7
+ data.tar.gz: 7db698c108c3c7d40494c6d4ceb9f1bb59010efe39d530cc6860cfe538fbab216c483361b83d7301310c5e1b4dae026d7d35c6a905f1ca83104dd60641f9b4e1
data/ChangeLog CHANGED
@@ -1,5 +1,12 @@
1
1
  CHANGELOG
2
2
 
3
+ 2014-03-30 1.9.4
4
+
5
+ * Ability to index an array of objects using the `index_objects` method. Ref #15
6
+ * Upgrade typeahead.js to 0.10.2 (fixed flickering)
7
+ * Upgrade algoliasearch-client-ruby to 1.2.8 (fixed unhandled exception)
8
+ * Upgrade algoliasearch-client-js to 2.4.5 (embed last ExplainResults helper fixes)
9
+
3
10
  2014-03-26 1.9.3
4
11
 
5
12
  * Ruby 1.8 compatibility
@@ -35,7 +35,7 @@ GEM
35
35
  i18n (~> 0.6, >= 0.6.4)
36
36
  multi_json (~> 1.0)
37
37
  addressable (2.3.6)
38
- algoliasearch (1.2.7)
38
+ algoliasearch (1.2.8)
39
39
  httpclient (~> 2.3)
40
40
  json (>= 1.5.1)
41
41
  arel (3.0.3)
data/README.md CHANGED
@@ -233,6 +233,20 @@ class Post < ActiveRecord::Base
233
233
  end
234
234
  ```
235
235
 
236
+ You can index a subset of your records using either:
237
+
238
+ ```ruby
239
+ # will generate batch API calls (recommended)
240
+ MyModel.where('updated_at > ?', 10.minutes.ago).reindex!
241
+ ```
242
+
243
+ or
244
+
245
+ ```ruby
246
+ MyModel.index_objects MyModel.limit(5)
247
+ ```
248
+
249
+
236
250
  Configuration example
237
251
  ---------------------
238
252
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.9.3
1
+ 1.9.4
@@ -6,11 +6,11 @@
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "algoliasearch-rails"
9
- s.version = "1.9.3"
9
+ s.version = "1.9.4"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
12
12
  s.authors = ["Algolia"]
13
- s.date = "2014-03-26"
13
+ s.date = "2014-03-30"
14
14
  s.description = "AlgoliaSearch integration to your favorite ORM"
15
15
  s.email = "contact@algolia.com"
16
16
  s.extra_rdoc_files = [
@@ -124,6 +124,7 @@ module AlgoliaSearch
124
124
  class <<base
125
125
  alias_method :without_auto_index, :algolia_without_auto_index unless method_defined? :without_auto_index
126
126
  alias_method :reindex!, :algolia_reindex! unless method_defined? :reindex!
127
+ alias_method :index_objects, :algolia_index_objects unless method_defined? :index_objects
127
128
  alias_method :index!, :algolia_index! unless method_defined? :index!
128
129
  alias_method :remove_from_index!, :algolia_remove_from_index! unless method_defined? :remove_from_index!
129
130
  alias_method :clear_index!, :algolia_clear_index! unless method_defined? :clear_index!
@@ -185,6 +186,11 @@ module AlgoliaSearch
185
186
  @algolia_index.wait_task(last_task["taskID"]) if last_task and synchronous == true
186
187
  end
187
188
 
189
+ def algolia_index_objects(objects, synchronous = false)
190
+ task = @algolia_index.save_objects(objects.map { |o| algolia_index_settings.get_attributes(o).merge 'objectID' => algolia_object_id_of(o) })
191
+ @algolia_index.wait_task(task["taskID"]) if synchronous == true
192
+ end
193
+
188
194
  def algolia_index!(object, synchronous = false)
189
195
  return if @algolia_without_auto_index_scope
190
196
  object_id = algolia_object_id_of(object)
@@ -21,7 +21,7 @@
21
21
  * THE SOFTWARE.
22
22
  */
23
23
 
24
- var ALGOLIA_VERSION = '2.4.4';
24
+ var ALGOLIA_VERSION = '2.4.5';
25
25
 
26
26
  /*
27
27
  * Copyright (c) 2013 Algolia
@@ -121,15 +121,23 @@ function AlgoliaExplainResults(hit, titleAttribute, otherAttributes) {
121
121
  }
122
122
 
123
123
  function _getHitExplanationForOneAttr(hit, foundWords, attr) {
124
+ var base = hit._highlightResult || hit;
124
125
  if (attr.indexOf('.') === -1) {
125
- if (attr in hit._highlightResult) {
126
- return _getHitExplanationForOneAttr_recurse(hit._highlightResult[attr], foundWords);
126
+ if (attr in base) {
127
+ return _getHitExplanationForOneAttr_recurse(base[attr], foundWords);
127
128
  }
128
129
  return [];
129
130
  }
130
131
  var array = attr.split('.');
131
- var obj = hit._highlightResult;
132
+ var obj = base;
132
133
  for (var i = 0; i < array.length; ++i) {
134
+ if (Object.prototype.toString.call(obj) === '[object Array]') {
135
+ var res = [];
136
+ for (var j = 0; j < obj.length; ++j) {
137
+ res = res.concat(_getHitExplanationForOneAttr(obj[j], foundWords, array.slice(i).join('.')));
138
+ }
139
+ return res;
140
+ }
133
141
  if (array[i] in obj) {
134
142
  obj = obj[array[i]];
135
143
  } else {
@@ -1,7 +1,7 @@
1
1
  /*!
2
- * algoliasearch 2.4.4
2
+ * algoliasearch 2.4.5
3
3
  * https://github.com/algolia/algoliasearch-client-js
4
4
  * Copyright 2014 Algolia SAS; Licensed MIT
5
5
  */
6
6
 
7
- function AlgoliaExplainResults(a,b,c){function d(a,b){var c=[];if("object"==typeof a&&"matchedWords"in a&&"value"in a){for(var e=!1,f=0;f<a.matchedWords.length;++f){var g=a.matchedWords[f];g in b||(b[g]=1,e=!0)}e&&c.push(a.value)}else if("[object Array]"===Object.prototype.toString.call(a))for(var h=0;h<a.length;++h){var i=d(a[h],b);c=c.concat(i)}else if("object"==typeof a)for(var j in a)a.hasOwnProperty(j)&&(c=c.concat(d(a[j],b)));return c}function e(a,b,c){if(-1===c.indexOf("."))return c in a._highlightResult?d(a._highlightResult[c],b):[];for(var e=c.split("."),f=a._highlightResult,g=0;g<e.length;++g){if(!(e[g]in f))return[];f=f[e[g]]}return d(f,b)}var f={},g={},h=e(a,g,b);if(f.title=h.length>0?h[0]:"",f.subtitles=[],"undefined"!=typeof c)for(var i=0;i<c.length;++i)for(var j=e(a,g,c[i]),k=0;k<j.length;++k)f.subtitles.push({attr:c[i],value:j[k]});return f}var ALGOLIA_VERSION="2.4.4",AlgoliaSearch=function(a,b,c,d,e){this.applicationID=a,this.apiKey=b,this._isUndefined(e)&&(e=[a+"-1.algolia.io",a+"-2.algolia.io",a+"-3.algolia.io"]),this.hosts=[];for(var f=0;f<e.length;++f)Math.random()>.5&&this.hosts.reverse(),this._isUndefined(c)||null==c?this.hosts.push(("https:"==document.location.protocol?"https":"http")+"://"+e[f]):"https"===c||"HTTPS"===c?this.hosts.push("https://"+e[f]):this.hosts.push("http://"+e[f]);Math.random()>.5&&this.hosts.reverse(),(this._isUndefined(d)||d)&&this._jsonRequest({method:"GET",url:"/1/isalive"}),this.extraHeaders=[]};AlgoliaSearch.prototype={deleteIndex:function(a,b){this._jsonRequest({method:"DELETE",url:"/1/indexes/"+encodeURIComponent(a),callback:b})},moveIndex:function(a,b,c){var d={operation:"move",destination:b};this._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(a)+"/operation",body:d,callback:c})},copyIndex:function(a,b,c){var d={operation:"copy",destination:b};this._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(a)+"/operation",body:d,callback:c})},getLogs:function(a,b,c){this._isUndefined(b)&&(b=0),this._isUndefined(c)&&(c=10),this._jsonRequest({method:"GET",url:"/1/logs?offset="+b+"&length="+c,callback:a})},listIndexes:function(a){this._jsonRequest({method:"GET",url:"/1/indexes/",callback:a})},initIndex:function(a){return new this.Index(this,a)},listUserKeys:function(a){this._jsonRequest({method:"GET",url:"/1/keys",callback:a})},getUserKeyACL:function(a,b){this._jsonRequest({method:"GET",url:"/1/keys/"+a,callback:b})},deleteUserKey:function(a,b){this._jsonRequest({method:"DELETE",url:"/1/keys/"+a,callback:b})},addUserKey:function(a,b){var c={};c.acl=a,this._jsonRequest({method:"POST",url:"/1/keys",body:c,callback:b})},addUserKeyWithValidity:function(a,b,c,d,e){var f=this,g={};g.acl=a,g.validity=b,g.maxQueriesPerIPPerHour=c,g.maxHitsPerQuery=d,this._jsonRequest({method:"POST",url:"/1/indexes/"+f.indexName+"/keys",body:g,callback:e})},setSecurityTags:function(a){if("[object Array]"===Object.prototype.toString.call(a)){for(var b=[],c=0;c<a.length;++c)if("[object Array]"===Object.prototype.toString.call(a[c])){for(var d=[],e=0;e<a[c].length;++e)d.push(a[c][e]);b.push("("+d.join(",")+")")}else b.push(a[c]);a=b.join(",")}this.setExtraHeader("X-Algolia-TagFilters",a)},setUserToken:function(a){this.setExtraHeader("X-Algolia-UserToken",a)},startQueriesBatch:function(){this.batch=[]},addQueryInBatch:function(a,b,c){var d="query="+encodeURIComponent(b);this._isUndefined(c)||null==c||(d=this._getSearchParams(c,d)),this.batch.push({indexName:a,params:d})},clearCache:function(){this.cache={}},sendQueriesBatch:function(a,b){for(var c=this,d={requests:[],apiKey:this.apiKey,appID:this.applicationID},e=0;e<c.batch.length;++e)d.requests.push(c.batch[e]);if(window.clearTimeout(c.onDelayTrigger),!this._isUndefined(b)&&null!=b&&b>0){var f=window.setTimeout(function(){c._sendQueriesBatch(d,a)},b);c.onDelayTrigger=f}else this._sendQueriesBatch(d,a)},Index:function(a,b){this.indexName=b,this.as=a,this.typeAheadArgs=null,this.typeAheadValueOption=null},setExtraHeader:function(a,b){this.extraHeaders.push({key:a,value:b})},_sendQueriesBatch:function(a,b){this._jsonRequest({cache:this.cache,method:"POST",url:"/1/indexes/*/queries",body:a,callback:b})},_jsonRequest:function(a){var b=this,c=a.callback,d=null,e=a.url;if(this._isUndefined(a.body)||(e=a.url+"_body_"+JSON.stringify(a.body)),!this._isUndefined(a.cache)&&(d=a.cache,!this._isUndefined(d[e])))return this._isUndefined(c)||c(!0,d[e]),void 0;var f=function(g){var h=0;return b._isUndefined(g)||(h=g),b.hosts.length<=h?(b._isUndefined(c)||c(!1,{message:"Cannot contact server"}),void 0):(a.callback=function(g,i,j,k){i||b._isUndefined(k)||console.log("Error: "+k.message),i&&!b._isUndefined(a.cache)&&(d[e]=k),!i&&g&&h+1<b.hosts.length?f(h+1):b._isUndefined(c)||c(i,k)},a.hostname=b.hosts[h],b._jsonRequestByHost(a),void 0)};f()},_jsonRequestByHost:function(a){var b=null,c=this;this._isUndefined(a.body)||(b=JSON.stringify(a.body));var d=a.hostname+a.url,e=null;if(e=new XMLHttpRequest,"withCredentials"in e){e.open(a.method,d,!0),e.setRequestHeader("X-Algolia-API-Key",this.apiKey),e.setRequestHeader("X-Algolia-Application-Id",this.applicationID);for(var f=0;f<this.extraHeaders.length;++f)e.setRequestHeader(this.extraHeaders[f].key,this.extraHeaders[f].value);null!=b&&e.setRequestHeader("Content-type","application/json")}else"undefined"!=typeof XDomainRequest?(e=new XDomainRequest,e.open(a.method,d)):console.log("your browser is too old to support CORS requests");e.send(b),e.onload=function(b){if(c._isUndefined(b)||null==b.target)a.callback(!1,!0,b,JSON.parse(e.responseText));else{var d=0===b.target.status||503===b.target.status,f=200===b.target.status||201===b.target.status;a.callback(d,f,b.target,null!=b.target.response?JSON.parse(b.target.response):null)}},e.onerror=function(){a.callback(!0,!1,null,{message:"Could not connect to Host"})}},_getSearchParams:function(a,b){if(this._isUndefined(a)||null==a)return b;for(var c in a)null!=c&&a.hasOwnProperty(c)&&(b+=0===b.length?"?":"&",b+=c+"="+encodeURIComponent("[object Array]"===Object.prototype.toString.call(a[c])?JSON.stringify(a[c]):a[c]));return b},_isUndefined:function(a){return void 0===a},applicationID:null,apiKey:null,hosts:[],cache:{},extraHeaders:[]},AlgoliaSearch.prototype.Index.prototype={clearCache:function(){this.cache={}},addObject:function(a,b,c){var d=this;this.as._isUndefined(c)?this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(d.indexName),body:a,callback:b}):this.as._jsonRequest({method:"PUT",url:"/1/indexes/"+encodeURIComponent(d.indexName)+"/"+encodeURIComponent(c),body:a,callback:b})},addObjects:function(a,b){for(var c=this,d={requests:[]},e=0;e<a.length;++e){var f={action:"addObject",body:a[e]};d.requests.push(f)}this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/batch",body:d,callback:b})},getObject:function(a,b,c){var d=this,e="";if(!this.as._isUndefined(c)){e="?attributes=";for(var f=0;f<c.length;++f)0!==f&&(e+=","),e+=c[f]}this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(d.indexName)+"/"+encodeURIComponent(a)+e,callback:b})},partialUpdateObject:function(a,b){var c=this;this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/"+encodeURIComponent(a.objectID)+"/partial",body:a,callback:b})},partialUpdateObjects:function(a,b){for(var c=this,d={requests:[]},e=0;e<a.length;++e){var f={action:"partialUpdateObject",objectID:a[e].objectID,body:a[e]};d.requests.push(f)}this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/batch",body:d,callback:b})},saveObject:function(a,b){var c=this;this.as._jsonRequest({method:"PUT",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/"+encodeURIComponent(a.objectID),body:a,callback:b})},saveObjects:function(a,b){for(var c=this,d={requests:[]},e=0;e<a.length;++e){var f={action:"updateObject",objectID:a[e].objectID,body:a[e]};d.requests.push(f)}this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/batch",body:d,callback:b})},deleteObject:function(a,b){if(null==a||0===a.length)return b(!1,{message:"empty objectID"}),void 0;var c=this;this.as._jsonRequest({method:"DELETE",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/"+encodeURIComponent(a),callback:b})},search:function(a,b,c,d){var e=this,f="query="+encodeURIComponent(a);if(this.as._isUndefined(c)||null==c||(f=this.as._getSearchParams(c,f)),window.clearTimeout(e.onDelayTrigger),!this.as._isUndefined(d)&&null!=d&&d>0){var g=window.setTimeout(function(){e._search(f,b)},d);e.onDelayTrigger=g}else this._search(f,b)},browse:function(a,b,c){var d=this,e="?page="+a;_.isUndefined(c)||(e+="&hitsPerPage="+c),this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(d.indexName)+"/browse"+e,callback:b})},ttAdapter:function(a){var b=this;return function(c,d){b.search(c,function(a,b){a&&d(b.hits)},a)}},waitTask:function(a,b){var c=this;this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/task/"+a,callback:function(d,e){d?"published"===e.status?b(!0,e):setTimeout(function(){c.waitTask(a,b)},100):b(!1,e)}})},clearIndex:function(a){var b=this;this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(b.indexName)+"/clear",callback:a})},getSettings:function(a){var b=this;this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(b.indexName)+"/settings",callback:a})},setSettings:function(a,b){var c=this;this.as._jsonRequest({method:"PUT",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/settings",body:a,callback:b})},listUserKeys:function(a){var b=this;this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(b.indexName)+"/keys",callback:a})},getUserKeyACL:function(a,b){var c=this;this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/keys/"+a,callback:b})},deleteUserKey:function(a,b){var c=this;this.as._jsonRequest({method:"DELETE",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/keys/"+a,callback:b})},addUserKey:function(a,b){var c=this,d={};d.acl=a,this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/keys",body:d,callback:b})},addUserKeyWithValidity:function(a,b,c,d,e){var f=this,g={};g.acl=a,g.validity=b,g.maxQueriesPerIPPerHour=c,g.maxHitsPerQuery=d,this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(f.indexName)+"/keys",body:g,callback:e})},_search:function(a,b){this.as._jsonRequest({cache:this.cache,method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/query",body:{params:a,apiKey:this.as.apiKey,appID:this.as.applicationID},callback:b})},as:null,indexName:null,cache:{},typeAheadArgs:null,typeAheadValueOption:null,emptyConstructor:function(){}},function(){var a,b=function(a){a=a||{};for(var b=1;b<arguments.length;b++)if(arguments[b])for(var c in arguments[b])arguments[b].hasOwnProperty(c)&&(a[c]=arguments[b][c]);return a};window.AlgoliaSearchHelper=function(c,d,e){var f={facets:[],disjunctiveFacets:[],hitsPerPage:20};this.init(c,d,b({},f,e)),a=this},AlgoliaSearchHelper.prototype={init:function(a,b,c){this.client=a,this.index=b,this.options=c,this.page=0,this.refinements={},this.disjunctiveRefinements={}},search:function(a,b,c){this.q=a,this.searchCallback=b,this.searchParams=c||{},this.page=this.page||0,this.refinements=this.refinements||{},this.disjunctiveRefinements=this.disjunctiveRefinements||{},this._search()},toggleRefine:function(a,b){for(var c=0;c<this.options.facets.length;++c)if(this.options.facets[c]==a){var d=a+":"+b;return this.refinements[d]=!this.refinements[d],this.page=0,this._search(),!0}this.disjunctiveRefinements[a]=this.disjunctiveRefinements[a]||{};for(var e=0;e<this.options.disjunctiveFacets.length;++e)if(this.options.disjunctiveFacets[e]==a)return this.disjunctiveRefinements[a][b]=!this.disjunctiveRefinements[a][b],this.page=0,this._search(),!0;return!1},isRefined:function(a,b){var c=a+":"+b;return this.refinements[c]?!0:this.disjunctiveRefinements[a]&&this.disjunctiveRefinements[a][b]?!0:!1},nextPage:function(){this._gotoPage(this.page+1)},previousPage:function(){this.page>0&&this._gotoPage(this.page-1)},_gotoPage:function(a){this.page=a,this._search()},_search:function(){this.client.startQueriesBatch(),this.client.addQueryInBatch(this.index,this.q,this._getHitsSearchParams());for(var b=0;b<this.options.disjunctiveFacets.length;++b)this.client.addQueryInBatch(this.index,this.q,this._getDisjunctiveFacetSearchParams(this.options.disjunctiveFacets[b]));this.client.sendQueriesBatch(function(b,c){if(!b)return a.searchCallback(!1,c),void 0;var d=c.results[0];d.disjunctiveFacets={};for(var e=1;e<c.results.length;++e)for(var f in c.results[e].facets)if(d.disjunctiveFacets[f]=c.results[e].facets[f],a.disjunctiveRefinements[f])for(var g in a.disjunctiveRefinements[f])!d.disjunctiveFacets[f][g]&&a.disjunctiveRefinements[f][g]&&(d.disjunctiveFacets[f][g]=0);a.searchCallback(!0,d)})},_getHitsSearchParams:function(){return b({},this.searchParams,{hitsPerPage:this.options.hitsPerPage,page:this.page,facets:this.options.facets,facetFilters:this._getFacetFilters()})},_getDisjunctiveFacetSearchParams:function(a){return b({},this.searchParams,{hitsPerPage:1,page:0,facets:a,facetFilters:this._getFacetFilters(a)})},_getFacetFilters:function(a){var b=[];for(var c in this.refinements)this.refinements[c]&&b.push(c);for(var d in this.disjunctiveRefinements)if(d!=a){var e=[];for(var f in this.disjunctiveRefinements[d])this.disjunctiveRefinements[d][f]&&e.push(d+":"+f);e.length>0&&b.push(e)}return b}}}();
7
+ function AlgoliaExplainResults(a,b,c){function d(a,b){var c=[];if("object"==typeof a&&"matchedWords"in a&&"value"in a){for(var e=!1,f=0;f<a.matchedWords.length;++f){var g=a.matchedWords[f];g in b||(b[g]=1,e=!0)}e&&c.push(a.value)}else if("[object Array]"===Object.prototype.toString.call(a))for(var h=0;h<a.length;++h){var i=d(a[h],b);c=c.concat(i)}else if("object"==typeof a)for(var j in a)a.hasOwnProperty(j)&&(c=c.concat(d(a[j],b)));return c}function e(a,b,c){var f=a._highlightResult||a;if(-1===c.indexOf("."))return c in f?d(f[c],b):[];for(var g=c.split("."),h=f,i=0;i<g.length;++i){if("[object Array]"===Object.prototype.toString.call(h)){for(var j=[],k=0;k<h.length;++k)j=j.concat(e(h[k],b,g.slice(i).join(".")));return j}if(!(g[i]in h))return[];h=h[g[i]]}return d(h,b)}var f={},g={},h=e(a,g,b);if(f.title=h.length>0?h[0]:"",f.subtitles=[],"undefined"!=typeof c)for(var i=0;i<c.length;++i)for(var j=e(a,g,c[i]),k=0;k<j.length;++k)f.subtitles.push({attr:c[i],value:j[k]});return f}var ALGOLIA_VERSION="2.4.5",AlgoliaSearch=function(a,b,c,d,e){this.applicationID=a,this.apiKey=b,this._isUndefined(e)&&(e=[a+"-1.algolia.io",a+"-2.algolia.io",a+"-3.algolia.io"]),this.hosts=[];for(var f=0;f<e.length;++f)Math.random()>.5&&this.hosts.reverse(),this._isUndefined(c)||null==c?this.hosts.push(("https:"==document.location.protocol?"https":"http")+"://"+e[f]):"https"===c||"HTTPS"===c?this.hosts.push("https://"+e[f]):this.hosts.push("http://"+e[f]);Math.random()>.5&&this.hosts.reverse(),(this._isUndefined(d)||d)&&this._jsonRequest({method:"GET",url:"/1/isalive"}),this.extraHeaders=[]};AlgoliaSearch.prototype={deleteIndex:function(a,b){this._jsonRequest({method:"DELETE",url:"/1/indexes/"+encodeURIComponent(a),callback:b})},moveIndex:function(a,b,c){var d={operation:"move",destination:b};this._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(a)+"/operation",body:d,callback:c})},copyIndex:function(a,b,c){var d={operation:"copy",destination:b};this._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(a)+"/operation",body:d,callback:c})},getLogs:function(a,b,c){this._isUndefined(b)&&(b=0),this._isUndefined(c)&&(c=10),this._jsonRequest({method:"GET",url:"/1/logs?offset="+b+"&length="+c,callback:a})},listIndexes:function(a){this._jsonRequest({method:"GET",url:"/1/indexes/",callback:a})},initIndex:function(a){return new this.Index(this,a)},listUserKeys:function(a){this._jsonRequest({method:"GET",url:"/1/keys",callback:a})},getUserKeyACL:function(a,b){this._jsonRequest({method:"GET",url:"/1/keys/"+a,callback:b})},deleteUserKey:function(a,b){this._jsonRequest({method:"DELETE",url:"/1/keys/"+a,callback:b})},addUserKey:function(a,b){var c={};c.acl=a,this._jsonRequest({method:"POST",url:"/1/keys",body:c,callback:b})},addUserKeyWithValidity:function(a,b,c,d,e){var f=this,g={};g.acl=a,g.validity=b,g.maxQueriesPerIPPerHour=c,g.maxHitsPerQuery=d,this._jsonRequest({method:"POST",url:"/1/indexes/"+f.indexName+"/keys",body:g,callback:e})},setSecurityTags:function(a){if("[object Array]"===Object.prototype.toString.call(a)){for(var b=[],c=0;c<a.length;++c)if("[object Array]"===Object.prototype.toString.call(a[c])){for(var d=[],e=0;e<a[c].length;++e)d.push(a[c][e]);b.push("("+d.join(",")+")")}else b.push(a[c]);a=b.join(",")}this.setExtraHeader("X-Algolia-TagFilters",a)},setUserToken:function(a){this.setExtraHeader("X-Algolia-UserToken",a)},startQueriesBatch:function(){this.batch=[]},addQueryInBatch:function(a,b,c){var d="query="+encodeURIComponent(b);this._isUndefined(c)||null==c||(d=this._getSearchParams(c,d)),this.batch.push({indexName:a,params:d})},clearCache:function(){this.cache={}},sendQueriesBatch:function(a,b){for(var c=this,d={requests:[],apiKey:this.apiKey,appID:this.applicationID},e=0;e<c.batch.length;++e)d.requests.push(c.batch[e]);if(window.clearTimeout(c.onDelayTrigger),!this._isUndefined(b)&&null!=b&&b>0){var f=window.setTimeout(function(){c._sendQueriesBatch(d,a)},b);c.onDelayTrigger=f}else this._sendQueriesBatch(d,a)},Index:function(a,b){this.indexName=b,this.as=a,this.typeAheadArgs=null,this.typeAheadValueOption=null},setExtraHeader:function(a,b){this.extraHeaders.push({key:a,value:b})},_sendQueriesBatch:function(a,b){this._jsonRequest({cache:this.cache,method:"POST",url:"/1/indexes/*/queries",body:a,callback:b})},_jsonRequest:function(a){var b=this,c=a.callback,d=null,e=a.url;if(this._isUndefined(a.body)||(e=a.url+"_body_"+JSON.stringify(a.body)),!this._isUndefined(a.cache)&&(d=a.cache,!this._isUndefined(d[e])))return this._isUndefined(c)||c(!0,d[e]),void 0;var f=function(g){var h=0;return b._isUndefined(g)||(h=g),b.hosts.length<=h?(b._isUndefined(c)||c(!1,{message:"Cannot contact server"}),void 0):(a.callback=function(g,i,j,k){i||b._isUndefined(k)||console.log("Error: "+k.message),i&&!b._isUndefined(a.cache)&&(d[e]=k),!i&&g&&h+1<b.hosts.length?f(h+1):b._isUndefined(c)||c(i,k)},a.hostname=b.hosts[h],b._jsonRequestByHost(a),void 0)};f()},_jsonRequestByHost:function(a){var b=null,c=this;this._isUndefined(a.body)||(b=JSON.stringify(a.body));var d=a.hostname+a.url,e=null;if(e=new XMLHttpRequest,"withCredentials"in e){e.open(a.method,d,!0),e.setRequestHeader("X-Algolia-API-Key",this.apiKey),e.setRequestHeader("X-Algolia-Application-Id",this.applicationID);for(var f=0;f<this.extraHeaders.length;++f)e.setRequestHeader(this.extraHeaders[f].key,this.extraHeaders[f].value);null!=b&&e.setRequestHeader("Content-type","application/json")}else"undefined"!=typeof XDomainRequest?(e=new XDomainRequest,e.open(a.method,d)):console.log("your browser is too old to support CORS requests");e.send(b),e.onload=function(b){if(c._isUndefined(b)||null==b.target)a.callback(!1,!0,b,JSON.parse(e.responseText));else{var d=0===b.target.status||503===b.target.status,f=200===b.target.status||201===b.target.status;a.callback(d,f,b.target,null!=b.target.response?JSON.parse(b.target.response):null)}},e.onerror=function(){a.callback(!0,!1,null,{message:"Could not connect to Host"})}},_getSearchParams:function(a,b){if(this._isUndefined(a)||null==a)return b;for(var c in a)null!=c&&a.hasOwnProperty(c)&&(b+=0===b.length?"?":"&",b+=c+"="+encodeURIComponent("[object Array]"===Object.prototype.toString.call(a[c])?JSON.stringify(a[c]):a[c]));return b},_isUndefined:function(a){return void 0===a},applicationID:null,apiKey:null,hosts:[],cache:{},extraHeaders:[]},AlgoliaSearch.prototype.Index.prototype={clearCache:function(){this.cache={}},addObject:function(a,b,c){var d=this;this.as._isUndefined(c)?this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(d.indexName),body:a,callback:b}):this.as._jsonRequest({method:"PUT",url:"/1/indexes/"+encodeURIComponent(d.indexName)+"/"+encodeURIComponent(c),body:a,callback:b})},addObjects:function(a,b){for(var c=this,d={requests:[]},e=0;e<a.length;++e){var f={action:"addObject",body:a[e]};d.requests.push(f)}this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/batch",body:d,callback:b})},getObject:function(a,b,c){var d=this,e="";if(!this.as._isUndefined(c)){e="?attributes=";for(var f=0;f<c.length;++f)0!==f&&(e+=","),e+=c[f]}this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(d.indexName)+"/"+encodeURIComponent(a)+e,callback:b})},partialUpdateObject:function(a,b){var c=this;this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/"+encodeURIComponent(a.objectID)+"/partial",body:a,callback:b})},partialUpdateObjects:function(a,b){for(var c=this,d={requests:[]},e=0;e<a.length;++e){var f={action:"partialUpdateObject",objectID:a[e].objectID,body:a[e]};d.requests.push(f)}this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/batch",body:d,callback:b})},saveObject:function(a,b){var c=this;this.as._jsonRequest({method:"PUT",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/"+encodeURIComponent(a.objectID),body:a,callback:b})},saveObjects:function(a,b){for(var c=this,d={requests:[]},e=0;e<a.length;++e){var f={action:"updateObject",objectID:a[e].objectID,body:a[e]};d.requests.push(f)}this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/batch",body:d,callback:b})},deleteObject:function(a,b){if(null==a||0===a.length)return b(!1,{message:"empty objectID"}),void 0;var c=this;this.as._jsonRequest({method:"DELETE",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/"+encodeURIComponent(a),callback:b})},search:function(a,b,c,d){var e=this,f="query="+encodeURIComponent(a);if(this.as._isUndefined(c)||null==c||(f=this.as._getSearchParams(c,f)),window.clearTimeout(e.onDelayTrigger),!this.as._isUndefined(d)&&null!=d&&d>0){var g=window.setTimeout(function(){e._search(f,b)},d);e.onDelayTrigger=g}else this._search(f,b)},browse:function(a,b,c){var d=this,e="?page="+a;_.isUndefined(c)||(e+="&hitsPerPage="+c),this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(d.indexName)+"/browse"+e,callback:b})},ttAdapter:function(a){var b=this;return function(c,d){b.search(c,function(a,b){a&&d(b.hits)},a)}},waitTask:function(a,b){var c=this;this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/task/"+a,callback:function(d,e){d?"published"===e.status?b(!0,e):setTimeout(function(){c.waitTask(a,b)},100):b(!1,e)}})},clearIndex:function(a){var b=this;this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(b.indexName)+"/clear",callback:a})},getSettings:function(a){var b=this;this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(b.indexName)+"/settings",callback:a})},setSettings:function(a,b){var c=this;this.as._jsonRequest({method:"PUT",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/settings",body:a,callback:b})},listUserKeys:function(a){var b=this;this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(b.indexName)+"/keys",callback:a})},getUserKeyACL:function(a,b){var c=this;this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/keys/"+a,callback:b})},deleteUserKey:function(a,b){var c=this;this.as._jsonRequest({method:"DELETE",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/keys/"+a,callback:b})},addUserKey:function(a,b){var c=this,d={};d.acl=a,this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/keys",body:d,callback:b})},addUserKeyWithValidity:function(a,b,c,d,e){var f=this,g={};g.acl=a,g.validity=b,g.maxQueriesPerIPPerHour=c,g.maxHitsPerQuery=d,this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(f.indexName)+"/keys",body:g,callback:e})},_search:function(a,b){this.as._jsonRequest({cache:this.cache,method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/query",body:{params:a,apiKey:this.as.apiKey,appID:this.as.applicationID},callback:b})},as:null,indexName:null,cache:{},typeAheadArgs:null,typeAheadValueOption:null,emptyConstructor:function(){}},function(){var a,b=function(a){a=a||{};for(var b=1;b<arguments.length;b++)if(arguments[b])for(var c in arguments[b])arguments[b].hasOwnProperty(c)&&(a[c]=arguments[b][c]);return a};window.AlgoliaSearchHelper=function(c,d,e){var f={facets:[],disjunctiveFacets:[],hitsPerPage:20};this.init(c,d,b({},f,e)),a=this},AlgoliaSearchHelper.prototype={init:function(a,b,c){this.client=a,this.index=b,this.options=c,this.page=0,this.refinements={},this.disjunctiveRefinements={}},search:function(a,b,c){this.q=a,this.searchCallback=b,this.searchParams=c||{},this.page=this.page||0,this.refinements=this.refinements||{},this.disjunctiveRefinements=this.disjunctiveRefinements||{},this._search()},toggleRefine:function(a,b){for(var c=0;c<this.options.facets.length;++c)if(this.options.facets[c]==a){var d=a+":"+b;return this.refinements[d]=!this.refinements[d],this.page=0,this._search(),!0}this.disjunctiveRefinements[a]=this.disjunctiveRefinements[a]||{};for(var e=0;e<this.options.disjunctiveFacets.length;++e)if(this.options.disjunctiveFacets[e]==a)return this.disjunctiveRefinements[a][b]=!this.disjunctiveRefinements[a][b],this.page=0,this._search(),!0;return!1},isRefined:function(a,b){var c=a+":"+b;return this.refinements[c]?!0:this.disjunctiveRefinements[a]&&this.disjunctiveRefinements[a][b]?!0:!1},nextPage:function(){this._gotoPage(this.page+1)},previousPage:function(){this.page>0&&this._gotoPage(this.page-1)},_gotoPage:function(a){this.page=a,this._search()},_search:function(){this.client.startQueriesBatch(),this.client.addQueryInBatch(this.index,this.q,this._getHitsSearchParams());for(var b=0;b<this.options.disjunctiveFacets.length;++b)this.client.addQueryInBatch(this.index,this.q,this._getDisjunctiveFacetSearchParams(this.options.disjunctiveFacets[b]));this.client.sendQueriesBatch(function(b,c){if(!b)return a.searchCallback(!1,c),void 0;var d=c.results[0];d.disjunctiveFacets={};for(var e=1;e<c.results.length;++e)for(var f in c.results[e].facets)if(d.disjunctiveFacets[f]=c.results[e].facets[f],a.disjunctiveRefinements[f])for(var g in a.disjunctiveRefinements[f])!d.disjunctiveFacets[f][g]&&a.disjunctiveRefinements[f][g]&&(d.disjunctiveFacets[f][g]=0);a.searchCallback(!0,d)})},_getHitsSearchParams:function(){return b({},this.searchParams,{hitsPerPage:this.options.hitsPerPage,page:this.page,facets:this.options.facets,facetFilters:this._getFacetFilters()})},_getDisjunctiveFacetSearchParams:function(a){return b({},this.searchParams,{hitsPerPage:1,page:0,facets:a,facetFilters:this._getFacetFilters(a)})},_getFacetFilters:function(a){var b=[];for(var c in this.refinements)this.refinements[c]&&b.push(c);for(var d in this.disjunctiveRefinements)if(d!=a){var e=[];for(var f in this.disjunctiveRefinements[d])this.disjunctiveRefinements[d][f]&&e.push(d+":"+f);e.length>0&&b.push(e)}return b}}}();
@@ -1,7 +1,7 @@
1
1
  /*!
2
- * typeahead.js 0.10.1
2
+ * typeahead.js 0.10.2
3
3
  * https://github.com/twitter/typeahead.js
4
- * Copyright 2013 Twitter, Inc. and other contributors; Licensed MIT
4
+ * Copyright 2013-2014 Twitter, Inc. and other contributors; Licensed MIT
5
5
  */
6
6
 
7
7
  (function($) {
@@ -120,8 +120,31 @@
120
120
  },
121
121
  noop: function() {}
122
122
  };
123
- var VERSION = "0.10.1";
124
- var LruCache = function(root, undefined) {
123
+ var VERSION = "0.10.2";
124
+ var tokenizers = function(root) {
125
+ return {
126
+ nonword: nonword,
127
+ whitespace: whitespace,
128
+ obj: {
129
+ nonword: getObjTokenizer(nonword),
130
+ whitespace: getObjTokenizer(whitespace)
131
+ }
132
+ };
133
+ function whitespace(s) {
134
+ return s.split(/\s+/);
135
+ }
136
+ function nonword(s) {
137
+ return s.split(/\W+/);
138
+ }
139
+ function getObjTokenizer(tokenizer) {
140
+ return function setKey(key) {
141
+ return function tokenize(o) {
142
+ return tokenizer(o[key]);
143
+ };
144
+ };
145
+ }
146
+ }();
147
+ var LruCache = function() {
125
148
  function LruCache(maxSize) {
126
149
  this.maxSize = maxSize || 100;
127
150
  this.size = 0;
@@ -180,7 +203,7 @@
180
203
  this.prev = this.next = null;
181
204
  }
182
205
  return LruCache;
183
- }(this);
206
+ }();
184
207
  var PersistentStorage = function() {
185
208
  var ls, methods;
186
209
  try {
@@ -277,17 +300,20 @@
277
300
  _get: function(url, o, cb) {
278
301
  var that = this, jqXhr;
279
302
  if (jqXhr = pendingRequests[url]) {
280
- jqXhr.done(done);
303
+ jqXhr.done(done).fail(fail);
281
304
  } else if (pendingRequestsCount < maxPendingRequests) {
282
305
  pendingRequestsCount++;
283
- pendingRequests[url] = this._send(url, o).done(done).always(always);
306
+ pendingRequests[url] = this._send(url, o).done(done).fail(fail).always(always);
284
307
  } else {
285
308
  this.onDeckRequestArgs = [].slice.call(arguments, 0);
286
309
  }
287
310
  function done(resp) {
288
- cb && cb(resp);
311
+ cb && cb(null, resp);
289
312
  requestCache.set(url, resp);
290
313
  }
314
+ function fail() {
315
+ cb && cb(true);
316
+ }
291
317
  function always() {
292
318
  pendingRequestsCount--;
293
319
  delete pendingRequests[url];
@@ -298,14 +324,14 @@
298
324
  }
299
325
  },
300
326
  get: function(url, o, cb) {
301
- var that = this, resp;
327
+ var resp;
302
328
  if (_.isFunction(o)) {
303
329
  cb = o;
304
330
  o = {};
305
331
  }
306
332
  if (resp = requestCache.get(url)) {
307
333
  _.defer(function() {
308
- cb && cb(resp);
334
+ cb && cb(null, resp);
309
335
  });
310
336
  } else {
311
337
  this._get(url, o, cb);
@@ -340,8 +366,7 @@
340
366
  }
341
367
  this.datumTokenizer = o.datumTokenizer;
342
368
  this.queryTokenizer = o.queryTokenizer;
343
- this.datums = [];
344
- this.trie = newNode();
369
+ this.reset();
345
370
  }
346
371
  _.mixin(SearchIndex.prototype, {
347
372
  bootstrap: function bootstrap(o) {
@@ -356,7 +381,7 @@
356
381
  id = that.datums.push(datum) - 1;
357
382
  tokens = normalizeTokens(that.datumTokenizer(datum));
358
383
  _.each(tokens, function(token) {
359
- var node, chars, ch, ids;
384
+ var node, chars, ch;
360
385
  node = that.trie;
361
386
  chars = token.split("");
362
387
  while (ch = chars.shift()) {
@@ -391,6 +416,10 @@
391
416
  return that.datums[id];
392
417
  }) : [];
393
418
  },
419
+ reset: function reset() {
420
+ this.datums = [];
421
+ this.trie = newNode();
422
+ },
394
423
  serialize: function serialize() {
395
424
  return {
396
425
  datums: this.datums,
@@ -452,11 +481,7 @@
452
481
  remote: getRemote
453
482
  };
454
483
  function getLocal(o) {
455
- var local = o.local || null;
456
- if (_.isFunction(local)) {
457
- local = local.call(null);
458
- }
459
- return local;
484
+ return o.local || null;
460
485
  }
461
486
  function getPrefetch(o) {
462
487
  var prefetch, defaults;
@@ -516,13 +541,15 @@
516
541
  }
517
542
  }
518
543
  }();
519
- var Bloodhound = window.Bloodhound = function() {
520
- var keys;
544
+ (function(root) {
545
+ var old, keys;
546
+ old = root.Bloodhound;
521
547
  keys = {
522
548
  data: "data",
523
549
  protocol: "protocol",
524
550
  thumbprint: "thumbprint"
525
551
  };
552
+ root.Bloodhound = Bloodhound;
526
553
  function Bloodhound(o) {
527
554
  if (!o || !o.local && !o.prefetch && !o.remote) {
528
555
  $.error("one of local, prefetch, or remote is required");
@@ -540,14 +567,11 @@
540
567
  });
541
568
  this.storage = this.cacheKey ? new PersistentStorage(this.cacheKey) : null;
542
569
  }
543
- Bloodhound.tokenizers = {
544
- whitespace: function whitespaceTokenizer(s) {
545
- return s.split(/\s+/);
546
- },
547
- nonword: function nonwordTokenizer(s) {
548
- return s.split(/\W+/);
549
- }
570
+ Bloodhound.noConflict = function noConflict() {
571
+ root.Bloodhound = old;
572
+ return Bloodhound;
550
573
  };
574
+ Bloodhound.tokenizers = tokenizers;
551
575
  _.mixin(Bloodhound.prototype, {
552
576
  _loadPrefetch: function loadPrefetch(o) {
553
577
  var that = this, serialized, deferred;
@@ -559,9 +583,8 @@
559
583
  }
560
584
  return deferred;
561
585
  function handlePrefetchResponse(resp) {
562
- var filtered;
563
- filtered = o.filter ? o.filter(resp) : resp;
564
- that.add(filtered);
586
+ that.clear();
587
+ that.add(o.filter ? o.filter(resp) : resp);
565
588
  that._saveToStorage(that.index.serialize(), o.thumbprint, o.ttl);
566
589
  }
567
590
  },
@@ -571,9 +594,8 @@
571
594
  uriEncodedQuery = encodeURIComponent(query);
572
595
  url = this.remote.replace ? this.remote.replace(this.remote.url, query) : this.remote.url.replace(this.remote.wildcard, uriEncodedQuery);
573
596
  return this.transport.get(url, this.remote.ajax, handleRemoteResponse);
574
- function handleRemoteResponse(resp) {
575
- var filtered = that.remote.filter ? that.remote.filter(resp) : resp;
576
- cb(filtered);
597
+ function handleRemoteResponse(err, resp) {
598
+ err ? cb([]) : cb(that.remote.filter ? that.remote.filter(resp) : resp);
577
599
  }
578
600
  },
579
601
  _saveToStorage: function saveToStorage(data, thumbprint, ttl) {
@@ -593,30 +615,32 @@
593
615
  isExpired = stored.thumbprint !== thumbprint || stored.protocol !== location.protocol;
594
616
  return stored.data && !isExpired ? stored.data : null;
595
617
  },
596
- initialize: function initialize() {
597
- var that = this, deferred;
618
+ _initialize: function initialize() {
619
+ var that = this, local = this.local, deferred;
598
620
  deferred = this.prefetch ? this._loadPrefetch(this.prefetch) : $.Deferred().resolve();
599
- this.local && deferred.done(addLocalToIndex);
621
+ local && deferred.done(addLocalToIndex);
600
622
  this.transport = this.remote ? new Transport(this.remote) : null;
601
- this.initialize = function initialize() {
602
- return deferred.promise();
603
- };
604
- return deferred.promise();
623
+ return this.initPromise = deferred.promise();
605
624
  function addLocalToIndex() {
606
- that.add(that.local);
625
+ that.add(_.isFunction(local) ? local() : local);
607
626
  }
608
627
  },
628
+ initialize: function initialize(force) {
629
+ return !this.initPromise || force ? this._initialize() : this.initPromise;
630
+ },
609
631
  add: function add(data) {
610
632
  this.index.add(data);
611
633
  },
612
634
  get: function get(query, cb) {
613
- var that = this, matches, cacheHit = false;
635
+ var that = this, matches = [], cacheHit = false;
614
636
  matches = this.index.get(query);
615
637
  matches = this.sorter(matches).slice(0, this.limit);
616
638
  if (matches.length < this.limit && this.transport) {
617
639
  cacheHit = this._getFromRemote(query, returnRemoteMatches);
618
640
  }
619
- !cacheHit && cb && cb(matches);
641
+ if (!cacheHit) {
642
+ (matches.length > 0 || !this.transport) && cb && cb(matches);
643
+ }
620
644
  function returnRemoteMatches(remoteMatches) {
621
645
  var matchesWithBackfill = matches.slice(0);
622
646
  _.each(remoteMatches, function(remoteMatch) {
@@ -630,6 +654,15 @@
630
654
  cb && cb(that.sorter(matchesWithBackfill));
631
655
  }
632
656
  },
657
+ clear: function clear() {
658
+ this.index.reset();
659
+ },
660
+ clearPrefetchCache: function clearPrefetchCache() {
661
+ this.storage && this.storage.clear();
662
+ },
663
+ clearRemoteCache: function clearRemoteCache() {
664
+ this.transport && Transport.resetCache();
665
+ },
633
666
  ttAdapter: function ttAdapter() {
634
667
  return _.bind(this.get, this);
635
668
  }
@@ -647,5 +680,5 @@
647
680
  function ignoreDuplicates() {
648
681
  return false;
649
682
  }
650
- }();
683
+ })(this);
651
684
  })(window.jQuery);
@@ -1,7 +1,7 @@
1
1
  /*!
2
- * typeahead.js 0.10.1
2
+ * typeahead.js 0.10.2
3
3
  * https://github.com/twitter/typeahead.js
4
- * Copyright 2013 Twitter, Inc. and other contributors; Licensed MIT
4
+ * Copyright 2013-2014 Twitter, Inc. and other contributors; Licensed MIT
5
5
  */
6
6
 
7
7
  (function($) {
@@ -120,8 +120,31 @@
120
120
  },
121
121
  noop: function() {}
122
122
  };
123
- var VERSION = "0.10.1";
124
- var LruCache = function(root, undefined) {
123
+ var VERSION = "0.10.2";
124
+ var tokenizers = function(root) {
125
+ return {
126
+ nonword: nonword,
127
+ whitespace: whitespace,
128
+ obj: {
129
+ nonword: getObjTokenizer(nonword),
130
+ whitespace: getObjTokenizer(whitespace)
131
+ }
132
+ };
133
+ function whitespace(s) {
134
+ return s.split(/\s+/);
135
+ }
136
+ function nonword(s) {
137
+ return s.split(/\W+/);
138
+ }
139
+ function getObjTokenizer(tokenizer) {
140
+ return function setKey(key) {
141
+ return function tokenize(o) {
142
+ return tokenizer(o[key]);
143
+ };
144
+ };
145
+ }
146
+ }();
147
+ var LruCache = function() {
125
148
  function LruCache(maxSize) {
126
149
  this.maxSize = maxSize || 100;
127
150
  this.size = 0;
@@ -180,7 +203,7 @@
180
203
  this.prev = this.next = null;
181
204
  }
182
205
  return LruCache;
183
- }(this);
206
+ }();
184
207
  var PersistentStorage = function() {
185
208
  var ls, methods;
186
209
  try {
@@ -277,17 +300,20 @@
277
300
  _get: function(url, o, cb) {
278
301
  var that = this, jqXhr;
279
302
  if (jqXhr = pendingRequests[url]) {
280
- jqXhr.done(done);
303
+ jqXhr.done(done).fail(fail);
281
304
  } else if (pendingRequestsCount < maxPendingRequests) {
282
305
  pendingRequestsCount++;
283
- pendingRequests[url] = this._send(url, o).done(done).always(always);
306
+ pendingRequests[url] = this._send(url, o).done(done).fail(fail).always(always);
284
307
  } else {
285
308
  this.onDeckRequestArgs = [].slice.call(arguments, 0);
286
309
  }
287
310
  function done(resp) {
288
- cb && cb(resp);
311
+ cb && cb(null, resp);
289
312
  requestCache.set(url, resp);
290
313
  }
314
+ function fail() {
315
+ cb && cb(true);
316
+ }
291
317
  function always() {
292
318
  pendingRequestsCount--;
293
319
  delete pendingRequests[url];
@@ -298,14 +324,14 @@
298
324
  }
299
325
  },
300
326
  get: function(url, o, cb) {
301
- var that = this, resp;
327
+ var resp;
302
328
  if (_.isFunction(o)) {
303
329
  cb = o;
304
330
  o = {};
305
331
  }
306
332
  if (resp = requestCache.get(url)) {
307
333
  _.defer(function() {
308
- cb && cb(resp);
334
+ cb && cb(null, resp);
309
335
  });
310
336
  } else {
311
337
  this._get(url, o, cb);
@@ -340,8 +366,7 @@
340
366
  }
341
367
  this.datumTokenizer = o.datumTokenizer;
342
368
  this.queryTokenizer = o.queryTokenizer;
343
- this.datums = [];
344
- this.trie = newNode();
369
+ this.reset();
345
370
  }
346
371
  _.mixin(SearchIndex.prototype, {
347
372
  bootstrap: function bootstrap(o) {
@@ -356,7 +381,7 @@
356
381
  id = that.datums.push(datum) - 1;
357
382
  tokens = normalizeTokens(that.datumTokenizer(datum));
358
383
  _.each(tokens, function(token) {
359
- var node, chars, ch, ids;
384
+ var node, chars, ch;
360
385
  node = that.trie;
361
386
  chars = token.split("");
362
387
  while (ch = chars.shift()) {
@@ -391,6 +416,10 @@
391
416
  return that.datums[id];
392
417
  }) : [];
393
418
  },
419
+ reset: function reset() {
420
+ this.datums = [];
421
+ this.trie = newNode();
422
+ },
394
423
  serialize: function serialize() {
395
424
  return {
396
425
  datums: this.datums,
@@ -452,11 +481,7 @@
452
481
  remote: getRemote
453
482
  };
454
483
  function getLocal(o) {
455
- var local = o.local || null;
456
- if (_.isFunction(local)) {
457
- local = local.call(null);
458
- }
459
- return local;
484
+ return o.local || null;
460
485
  }
461
486
  function getPrefetch(o) {
462
487
  var prefetch, defaults;
@@ -516,13 +541,15 @@
516
541
  }
517
542
  }
518
543
  }();
519
- var Bloodhound = window.Bloodhound = function() {
520
- var keys;
544
+ (function(root) {
545
+ var old, keys;
546
+ old = root.Bloodhound;
521
547
  keys = {
522
548
  data: "data",
523
549
  protocol: "protocol",
524
550
  thumbprint: "thumbprint"
525
551
  };
552
+ root.Bloodhound = Bloodhound;
526
553
  function Bloodhound(o) {
527
554
  if (!o || !o.local && !o.prefetch && !o.remote) {
528
555
  $.error("one of local, prefetch, or remote is required");
@@ -540,14 +567,11 @@
540
567
  });
541
568
  this.storage = this.cacheKey ? new PersistentStorage(this.cacheKey) : null;
542
569
  }
543
- Bloodhound.tokenizers = {
544
- whitespace: function whitespaceTokenizer(s) {
545
- return s.split(/\s+/);
546
- },
547
- nonword: function nonwordTokenizer(s) {
548
- return s.split(/\W+/);
549
- }
570
+ Bloodhound.noConflict = function noConflict() {
571
+ root.Bloodhound = old;
572
+ return Bloodhound;
550
573
  };
574
+ Bloodhound.tokenizers = tokenizers;
551
575
  _.mixin(Bloodhound.prototype, {
552
576
  _loadPrefetch: function loadPrefetch(o) {
553
577
  var that = this, serialized, deferred;
@@ -559,9 +583,8 @@
559
583
  }
560
584
  return deferred;
561
585
  function handlePrefetchResponse(resp) {
562
- var filtered;
563
- filtered = o.filter ? o.filter(resp) : resp;
564
- that.add(filtered);
586
+ that.clear();
587
+ that.add(o.filter ? o.filter(resp) : resp);
565
588
  that._saveToStorage(that.index.serialize(), o.thumbprint, o.ttl);
566
589
  }
567
590
  },
@@ -571,9 +594,8 @@
571
594
  uriEncodedQuery = encodeURIComponent(query);
572
595
  url = this.remote.replace ? this.remote.replace(this.remote.url, query) : this.remote.url.replace(this.remote.wildcard, uriEncodedQuery);
573
596
  return this.transport.get(url, this.remote.ajax, handleRemoteResponse);
574
- function handleRemoteResponse(resp) {
575
- var filtered = that.remote.filter ? that.remote.filter(resp) : resp;
576
- cb(filtered);
597
+ function handleRemoteResponse(err, resp) {
598
+ err ? cb([]) : cb(that.remote.filter ? that.remote.filter(resp) : resp);
577
599
  }
578
600
  },
579
601
  _saveToStorage: function saveToStorage(data, thumbprint, ttl) {
@@ -593,30 +615,32 @@
593
615
  isExpired = stored.thumbprint !== thumbprint || stored.protocol !== location.protocol;
594
616
  return stored.data && !isExpired ? stored.data : null;
595
617
  },
596
- initialize: function initialize() {
597
- var that = this, deferred;
618
+ _initialize: function initialize() {
619
+ var that = this, local = this.local, deferred;
598
620
  deferred = this.prefetch ? this._loadPrefetch(this.prefetch) : $.Deferred().resolve();
599
- this.local && deferred.done(addLocalToIndex);
621
+ local && deferred.done(addLocalToIndex);
600
622
  this.transport = this.remote ? new Transport(this.remote) : null;
601
- this.initialize = function initialize() {
602
- return deferred.promise();
603
- };
604
- return deferred.promise();
623
+ return this.initPromise = deferred.promise();
605
624
  function addLocalToIndex() {
606
- that.add(that.local);
625
+ that.add(_.isFunction(local) ? local() : local);
607
626
  }
608
627
  },
628
+ initialize: function initialize(force) {
629
+ return !this.initPromise || force ? this._initialize() : this.initPromise;
630
+ },
609
631
  add: function add(data) {
610
632
  this.index.add(data);
611
633
  },
612
634
  get: function get(query, cb) {
613
- var that = this, matches, cacheHit = false;
635
+ var that = this, matches = [], cacheHit = false;
614
636
  matches = this.index.get(query);
615
637
  matches = this.sorter(matches).slice(0, this.limit);
616
638
  if (matches.length < this.limit && this.transport) {
617
639
  cacheHit = this._getFromRemote(query, returnRemoteMatches);
618
640
  }
619
- !cacheHit && cb && cb(matches);
641
+ if (!cacheHit) {
642
+ (matches.length > 0 || !this.transport) && cb && cb(matches);
643
+ }
620
644
  function returnRemoteMatches(remoteMatches) {
621
645
  var matchesWithBackfill = matches.slice(0);
622
646
  _.each(remoteMatches, function(remoteMatch) {
@@ -630,6 +654,15 @@
630
654
  cb && cb(that.sorter(matchesWithBackfill));
631
655
  }
632
656
  },
657
+ clear: function clear() {
658
+ this.index.reset();
659
+ },
660
+ clearPrefetchCache: function clearPrefetchCache() {
661
+ this.storage && this.storage.clear();
662
+ },
663
+ clearRemoteCache: function clearRemoteCache() {
664
+ this.transport && Transport.resetCache();
665
+ },
633
666
  ttAdapter: function ttAdapter() {
634
667
  return _.bind(this.get, this);
635
668
  }
@@ -647,13 +680,13 @@
647
680
  function ignoreDuplicates() {
648
681
  return false;
649
682
  }
650
- }();
683
+ })(this);
651
684
  var html = {
652
685
  wrapper: '<span class="twitter-typeahead"></span>',
653
686
  dropdown: '<span class="tt-dropdown-menu"></span>',
654
687
  dataset: '<div class="tt-dataset-%CLASS%"></div>',
655
688
  suggestions: '<span class="tt-suggestions"></span>',
656
- suggestion: '<div class="tt-suggestion">%BODY%</div>'
689
+ suggestion: '<div class="tt-suggestion"></div>'
657
690
  };
658
691
  var css = {
659
692
  wrapper: {
@@ -771,7 +804,7 @@
771
804
  return this;
772
805
  }
773
806
  function trigger(types) {
774
- var that = this, type, callbacks, args, syncFlush, asyncFlush;
807
+ var type, callbacks, args, syncFlush, asyncFlush;
775
808
  if (!this._callbacks) {
776
809
  return this;
777
810
  }
@@ -795,7 +828,7 @@
795
828
  }
796
829
  }
797
830
  function getNextTick() {
798
- var nextTickFn, messageChannel;
831
+ var nextTickFn;
799
832
  if (window.setImmediate) {
800
833
  nextTickFn = function nextTickSetImmediate(fn) {
801
834
  setImmediate(function() {
@@ -892,7 +925,7 @@
892
925
  this.$hint = $(o.hint);
893
926
  this.$input = $(o.input).on("blur.tt", onBlur).on("focus.tt", onFocus).on("keydown.tt", onKeydown);
894
927
  if (this.$hint.length === 0) {
895
- this.setHintValue = this.getHintValue = this.clearHint = _.noop;
928
+ this.setHint = this.getHint = this.clearHint = this.clearHintIfInvalid = _.noop;
896
929
  }
897
930
  if (!_.isMsie()) {
898
931
  this.$input.on("input.tt", onInput);
@@ -911,11 +944,11 @@
911
944
  return (str || "").replace(/^\s*/g, "").replace(/\s{2,}/g, " ");
912
945
  };
913
946
  _.mixin(Input.prototype, EventEmitter, {
914
- _onBlur: function onBlur($e) {
947
+ _onBlur: function onBlur() {
915
948
  this.resetInputValue();
916
949
  this.trigger("blurred");
917
950
  },
918
- _onFocus: function onFocus($e) {
951
+ _onFocus: function onFocus() {
919
952
  this.trigger("focused");
920
953
  },
921
954
  _onKeydown: function onKeydown($e) {
@@ -925,14 +958,14 @@
925
958
  this.trigger(keyName + "Keyed", $e);
926
959
  }
927
960
  },
928
- _onInput: function onInput($e) {
961
+ _onInput: function onInput() {
929
962
  this._checkInputValue();
930
963
  },
931
964
  _managePreventDefault: function managePreventDefault(keyName, $e) {
932
965
  var preventDefault, hintValue, inputValue;
933
966
  switch (keyName) {
934
967
  case "tab":
935
- hintValue = this.getHintValue();
968
+ hintValue = this.getHint();
936
969
  inputValue = this.getInputValue();
937
970
  preventDefault = hintValue && hintValue !== inputValue && !withModifier($e);
938
971
  break;
@@ -987,19 +1020,27 @@
987
1020
  },
988
1021
  setInputValue: function setInputValue(value, silent) {
989
1022
  this.$input.val(value);
990
- !silent && this._checkInputValue();
1023
+ silent ? this.clearHint() : this._checkInputValue();
991
1024
  },
992
- getHintValue: function getHintValue() {
1025
+ resetInputValue: function resetInputValue() {
1026
+ this.setInputValue(this.query, true);
1027
+ },
1028
+ getHint: function getHint() {
993
1029
  return this.$hint.val();
994
1030
  },
995
- setHintValue: function setHintValue(value) {
1031
+ setHint: function setHint(value) {
996
1032
  this.$hint.val(value);
997
1033
  },
998
- resetInputValue: function resetInputValue() {
999
- this.$input.val(this.query);
1000
- },
1001
1034
  clearHint: function clearHint() {
1002
- this.$hint.val("");
1035
+ this.setHint("");
1036
+ },
1037
+ clearHintIfInvalid: function clearHintIfInvalid() {
1038
+ var val, hint, valIsPrefixOfHint, isValid;
1039
+ val = this.getInputValue();
1040
+ hint = this.getHint();
1041
+ valIsPrefixOfHint = val !== hint && hint.indexOf(val) === 0;
1042
+ isValid = val !== "" && valIsPrefixOfHint && !this.hasOverflow();
1043
+ !isValid && this.clearHint();
1003
1044
  },
1004
1045
  getLanguageDirection: function getLanguageDirection() {
1005
1046
  return (this.$input.css("direction") || "ltr").toLowerCase();
@@ -1033,7 +1074,7 @@
1033
1074
  return $('<pre aria-hidden="true"></pre>').css({
1034
1075
  position: "absolute",
1035
1076
  visibility: "hidden",
1036
- whiteSpace: "nowrap",
1077
+ whiteSpace: "pre",
1037
1078
  fontFamily: $input.css("font-family"),
1038
1079
  fontSize: $input.css("font-size"),
1039
1080
  fontStyle: $input.css("font-style"),
@@ -1112,10 +1153,8 @@
1112
1153
  });
1113
1154
  return $suggestions;
1114
1155
  function getSuggestionNode(suggestion) {
1115
- var $el, innerHtml, outerHtml;
1116
- innerHtml = that.templates.suggestion(suggestion);
1117
- outerHtml = html.suggestion.replace("%BODY%", innerHtml);
1118
- $el = $(outerHtml).data(datasetKey, that.name).data(valueKey, that.displayFn(suggestion)).data(datumKey, suggestion);
1156
+ var $el;
1157
+ $el = $(html.suggestion).append(that.templates.suggestion(suggestion)).data(datasetKey, that.name).data(valueKey, that.displayFn(suggestion)).data(datumKey, suggestion);
1119
1158
  $el.children().each(function() {
1120
1159
  $(this).css(css.suggestionChild);
1121
1160
  });
@@ -1141,13 +1180,21 @@
1141
1180
  update: function update(query) {
1142
1181
  var that = this;
1143
1182
  this.query = query;
1144
- this.source(query, renderIfQueryIsSame);
1145
- function renderIfQueryIsSame(suggestions) {
1146
- query === that.query && that._render(query, suggestions);
1183
+ this.canceled = false;
1184
+ this.source(query, render);
1185
+ function render(suggestions) {
1186
+ if (!that.canceled && query === that.query) {
1187
+ that._render(query, suggestions);
1188
+ }
1147
1189
  }
1148
1190
  },
1191
+ cancel: function cancel() {
1192
+ this.canceled = true;
1193
+ },
1149
1194
  clear: function clear() {
1150
- this._render(this.query || "");
1195
+ this.cancel();
1196
+ this.$el.empty();
1197
+ this.trigger("rendered");
1151
1198
  },
1152
1199
  isEmpty: function isEmpty() {
1153
1200
  return this.$el.is(":empty");
@@ -1206,7 +1253,7 @@
1206
1253
  this._removeCursor();
1207
1254
  this._setCursor($($e.currentTarget), true);
1208
1255
  },
1209
- _onSuggestionMouseLeave: function onSuggestionMouseLeave($e) {
1256
+ _onSuggestionMouseLeave: function onSuggestionMouseLeave() {
1210
1257
  this._removeCursor();
1211
1258
  },
1212
1259
  _onRendered: function onRendered() {
@@ -1341,17 +1388,34 @@
1341
1388
  var Typeahead = function() {
1342
1389
  var attrsKey = "ttAttrs";
1343
1390
  function Typeahead(o) {
1344
- var $menu, $input, $hint, datasets;
1391
+ var $menu, $input, $hint;
1345
1392
  o = o || {};
1346
1393
  if (!o.input) {
1347
1394
  $.error("missing input");
1348
1395
  }
1396
+ this.isActivated = false;
1349
1397
  this.autoselect = !!o.autoselect;
1350
1398
  this.minLength = _.isNumber(o.minLength) ? o.minLength : 1;
1351
1399
  this.$node = buildDomStructure(o.input, o.withHint);
1352
1400
  $menu = this.$node.find(".tt-dropdown-menu");
1353
1401
  $input = this.$node.find(".tt-input");
1354
1402
  $hint = this.$node.find(".tt-hint");
1403
+ $input.on("blur.tt", function($e) {
1404
+ var active, isActive, hasActive;
1405
+ active = document.activeElement;
1406
+ isActive = $menu.is(active);
1407
+ hasActive = $menu.has(active).length > 0;
1408
+ if (_.isMsie() && (isActive || hasActive)) {
1409
+ $e.preventDefault();
1410
+ $e.stopImmediatePropagation();
1411
+ _.defer(function() {
1412
+ $input.focus();
1413
+ });
1414
+ }
1415
+ });
1416
+ $menu.on("mousedown.tt", function($e) {
1417
+ $e.preventDefault();
1418
+ });
1355
1419
  this.eventBus = o.eventBus || new EventBus({
1356
1420
  el: $input
1357
1421
  });
@@ -1363,15 +1427,7 @@
1363
1427
  input: $input,
1364
1428
  hint: $hint
1365
1429
  }).onSync("focused", this._onFocused, this).onSync("blurred", this._onBlurred, this).onSync("enterKeyed", this._onEnterKeyed, this).onSync("tabKeyed", this._onTabKeyed, this).onSync("escKeyed", this._onEscKeyed, this).onSync("upKeyed", this._onUpKeyed, this).onSync("downKeyed", this._onDownKeyed, this).onSync("leftKeyed", this._onLeftKeyed, this).onSync("rightKeyed", this._onRightKeyed, this).onSync("queryChanged", this._onQueryChanged, this).onSync("whitespaceChanged", this._onWhitespaceChanged, this);
1366
- $menu.on("mousedown.tt", function($e) {
1367
- if (_.isMsie() && _.isMsie() < 9) {
1368
- $input[0].onbeforedeactivate = function() {
1369
- window.event.returnValue = false;
1370
- $input[0].onbeforedeactivate = null;
1371
- };
1372
- }
1373
- $e.preventDefault();
1374
- });
1430
+ this._setLanguageDirection();
1375
1431
  }
1376
1432
  _.mixin(Typeahead.prototype, {
1377
1433
  _onSuggestionClicked: function onSuggestionClicked(type, $el) {
@@ -1382,7 +1438,6 @@
1382
1438
  },
1383
1439
  _onCursorMoved: function onCursorMoved() {
1384
1440
  var datum = this.dropdown.getDatumForCursor();
1385
- this.input.clearHint();
1386
1441
  this.input.setInputValue(datum.value, true);
1387
1442
  this.eventBus.trigger("cursorchanged", datum.raw, datum.datasetName);
1388
1443
  },
@@ -1402,10 +1457,12 @@
1402
1457
  this.eventBus.trigger("closed");
1403
1458
  },
1404
1459
  _onFocused: function onFocused() {
1405
- this.dropdown.empty();
1460
+ this.isActivated = true;
1406
1461
  this.dropdown.open();
1407
1462
  },
1408
1463
  _onBlurred: function onBlurred() {
1464
+ this.isActivated = false;
1465
+ this.dropdown.empty();
1409
1466
  this.dropdown.close();
1410
1467
  },
1411
1468
  _onEnterKeyed: function onEnterKeyed(type, $e) {
@@ -1426,7 +1483,7 @@
1426
1483
  this._select(datum);
1427
1484
  $e.preventDefault();
1428
1485
  } else {
1429
- this._autocomplete();
1486
+ this._autocomplete(true);
1430
1487
  }
1431
1488
  },
1432
1489
  _onEscKeyed: function onEscKeyed() {
@@ -1435,19 +1492,13 @@
1435
1492
  },
1436
1493
  _onUpKeyed: function onUpKeyed() {
1437
1494
  var query = this.input.getQuery();
1438
- if (!this.dropdown.isOpen && query.length >= this.minLength) {
1439
- this.dropdown.update(query);
1440
- }
1495
+ this.dropdown.isEmpty && query.length >= this.minLength ? this.dropdown.update(query) : this.dropdown.moveCursorUp();
1441
1496
  this.dropdown.open();
1442
- this.dropdown.moveCursorUp();
1443
1497
  },
1444
1498
  _onDownKeyed: function onDownKeyed() {
1445
1499
  var query = this.input.getQuery();
1446
- if (!this.dropdown.isOpen && query.length >= this.minLength) {
1447
- this.dropdown.update(query);
1448
- }
1500
+ this.dropdown.isEmpty && query.length >= this.minLength ? this.dropdown.update(query) : this.dropdown.moveCursorDown();
1449
1501
  this.dropdown.open();
1450
- this.dropdown.moveCursorDown();
1451
1502
  },
1452
1503
  _onLeftKeyed: function onLeftKeyed() {
1453
1504
  this.dir === "rtl" && this._autocomplete();
@@ -1456,9 +1507,8 @@
1456
1507
  this.dir === "ltr" && this._autocomplete();
1457
1508
  },
1458
1509
  _onQueryChanged: function onQueryChanged(e, query) {
1459
- this.input.clearHint();
1460
- this.dropdown.empty();
1461
- query.length >= this.minLength && this.dropdown.update(query);
1510
+ this.input.clearHintIfInvalid();
1511
+ query.length >= this.minLength ? this.dropdown.update(query) : this.dropdown.empty();
1462
1512
  this.dropdown.open();
1463
1513
  this._setLanguageDirection();
1464
1514
  },
@@ -1475,29 +1525,31 @@
1475
1525
  }
1476
1526
  },
1477
1527
  _updateHint: function updateHint() {
1478
- var datum, inputValue, query, escapedQuery, frontMatchRegEx, match;
1528
+ var datum, val, query, escapedQuery, frontMatchRegEx, match;
1479
1529
  datum = this.dropdown.getDatumForTopSuggestion();
1480
1530
  if (datum && this.dropdown.isVisible() && !this.input.hasOverflow()) {
1481
- inputValue = this.input.getInputValue();
1482
- query = Input.normalizeQuery(inputValue);
1531
+ val = this.input.getInputValue();
1532
+ query = Input.normalizeQuery(val);
1483
1533
  escapedQuery = _.escapeRegExChars(query);
1484
- frontMatchRegEx = new RegExp("^(?:" + escapedQuery + ")(.*$)", "i");
1534
+ frontMatchRegEx = new RegExp("^(?:" + escapedQuery + ")(.+$)", "i");
1485
1535
  match = frontMatchRegEx.exec(datum.value);
1486
- this.input.setHintValue(inputValue + (match ? match[1] : ""));
1536
+ match ? this.input.setHint(val + match[1]) : this.input.clearHint();
1537
+ } else {
1538
+ this.input.clearHint();
1487
1539
  }
1488
1540
  },
1489
- _autocomplete: function autocomplete() {
1490
- var hint, query, datum;
1491
- hint = this.input.getHintValue();
1541
+ _autocomplete: function autocomplete(laxCursor) {
1542
+ var hint, query, isCursorAtEnd, datum;
1543
+ hint = this.input.getHint();
1492
1544
  query = this.input.getQuery();
1493
- if (hint && query !== hint && this.input.isCursorAtEnd()) {
1545
+ isCursorAtEnd = laxCursor || this.input.isCursorAtEnd();
1546
+ if (hint && query !== hint && isCursorAtEnd) {
1494
1547
  datum = this.dropdown.getDatumForTopSuggestion();
1495
1548
  datum && this.input.setInputValue(datum.value);
1496
1549
  this.eventBus.trigger("autocompleted", datum.raw, datum.datasetName);
1497
1550
  }
1498
1551
  },
1499
1552
  _select: function select(datum) {
1500
- this.input.clearHint();
1501
1553
  this.input.setQuery(datum.value);
1502
1554
  this.input.setInputValue(datum.value, true);
1503
1555
  this._setLanguageDirection();
@@ -1511,11 +1563,17 @@
1511
1563
  close: function close() {
1512
1564
  this.dropdown.close();
1513
1565
  },
1514
- getQuery: function getQuery() {
1515
- return this.input.getQuery();
1566
+ setVal: function setVal(val) {
1567
+ if (this.isActivated) {
1568
+ this.input.setInputValue(val);
1569
+ } else {
1570
+ this.input.setQuery(val);
1571
+ this.input.setInputValue(val, true);
1572
+ }
1573
+ this._setLanguageDirection();
1516
1574
  },
1517
- setQuery: function setQuery(val) {
1518
- this.input.setInputValue(val);
1575
+ getVal: function getVal() {
1576
+ return this.input.getQuery();
1519
1577
  },
1520
1578
  destroy: function destroy() {
1521
1579
  this.input.destroy();
@@ -1617,17 +1675,17 @@
1617
1675
  }
1618
1676
  },
1619
1677
  val: function val(newVal) {
1620
- return !arguments.length ? getQuery(this.first()) : this.each(setQuery);
1621
- function setQuery() {
1678
+ return !arguments.length ? getVal(this.first()) : this.each(setVal);
1679
+ function setVal() {
1622
1680
  var $input = $(this), typeahead;
1623
1681
  if (typeahead = $input.data(typeaheadKey)) {
1624
- typeahead.setQuery(newVal);
1682
+ typeahead.setVal(newVal);
1625
1683
  }
1626
1684
  }
1627
- function getQuery($input) {
1685
+ function getVal($input) {
1628
1686
  var typeahead, query;
1629
1687
  if (typeahead = $input.data(typeaheadKey)) {
1630
- query = typeahead.getQuery();
1688
+ query = typeahead.getVal();
1631
1689
  }
1632
1690
  return query;
1633
1691
  }