algoliasearch-rails 1.16.3 → 1.17.0

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.
Files changed (28) hide show
  1. checksums.yaml +4 -4
  2. data/ChangeLog +8 -0
  3. data/Gemfile +6 -1
  4. data/Gemfile.lock +3 -3
  5. data/README.md +153 -94
  6. data/VERSION +1 -1
  7. data/algoliasearch-rails.gemspec +1 -1
  8. data/lib/algoliasearch-rails.rb +75 -36
  9. data/spec/spec_helper.rb +7 -0
  10. data/vendor/assets/javascripts/algolia/algoliasearch.angular.js +23 -12
  11. data/vendor/assets/javascripts/algolia/algoliasearch.angular.min.js +2 -2
  12. data/vendor/assets/javascripts/algolia/algoliasearch.jquery.js +23 -12
  13. data/vendor/assets/javascripts/algolia/algoliasearch.jquery.min.js +2 -2
  14. data/vendor/assets/javascripts/algolia/algoliasearch.js +22 -12
  15. data/vendor/assets/javascripts/algolia/algoliasearch.min.js +2 -2
  16. data/vendor/assets/javascripts/algolia/v2/algoliasearch.angular.js +23 -12
  17. data/vendor/assets/javascripts/algolia/v2/algoliasearch.angular.min.js +2 -2
  18. data/vendor/assets/javascripts/algolia/v2/algoliasearch.jquery.js +23 -12
  19. data/vendor/assets/javascripts/algolia/v2/algoliasearch.jquery.min.js +2 -2
  20. data/vendor/assets/javascripts/algolia/v2/algoliasearch.js +22 -12
  21. data/vendor/assets/javascripts/algolia/v2/algoliasearch.min.js +2 -2
  22. data/vendor/assets/javascripts/algolia/v3/algoliasearch.angular.js +2020 -1301
  23. data/vendor/assets/javascripts/algolia/v3/algoliasearch.angular.min.js +3 -3
  24. data/vendor/assets/javascripts/algolia/v3/algoliasearch.jquery.js +2019 -1300
  25. data/vendor/assets/javascripts/algolia/v3/algoliasearch.jquery.min.js +3 -3
  26. data/vendor/assets/javascripts/algolia/v3/algoliasearch.js +2003 -1284
  27. data/vendor/assets/javascripts/algolia/v3/algoliasearch.min.js +3 -3
  28. metadata +5 -6
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.16.3
1
+ 1.17.0
@@ -77,7 +77,7 @@ Gem::Specification.new do |s|
77
77
 
78
78
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
79
79
  s.add_runtime_dependency(%q<json>, [">= 1.5.1"])
80
- s.add_runtime_dependency(%q<algoliasearch>, ["~> 1.12.1"])
80
+ s.add_runtime_dependency(%q<algoliasearch>, ["~> 1.12.4"])
81
81
  s.add_development_dependency(%q<will_paginate>, [">= 2.3.15"])
82
82
  s.add_development_dependency(%q<kaminari>, [">= 0"])
83
83
  s.add_development_dependency "travis"
@@ -30,6 +30,7 @@ module AlgoliaSearch
30
30
  class NotConfigured < StandardError; end
31
31
  class BadConfiguration < StandardError; end
32
32
  class NoBlockGiven < StandardError; end
33
+ class MixedSlavesAndReplicas < StandardError; end
33
34
 
34
35
  autoload :Configuration, 'algoliasearch/configuration'
35
36
  extend Configuration
@@ -57,13 +58,13 @@ module AlgoliaSearch
57
58
  # AlgoliaSearch settings
58
59
  OPTIONS = [:minWordSizefor1Typo, :minWordSizefor2Typos, :typoTolerance,
59
60
  :hitsPerPage, :attributesToRetrieve,
60
- :attributesToHighlight, :attributesToSnippet, :attributesToIndex,
61
+ :attributesToHighlight, :attributesToSnippet, :attributesToIndex, :searchableAttributes,
61
62
  :highlightPreTag, :highlightPostTag,
62
63
  :ranking, :customRanking, :queryType, :attributesForFaceting,
63
64
  :separatorsToIndex, :optionalWords, :attributeForDistinct,
64
65
  :synonyms, :placeholders, :removeWordsIfNoResults, :replaceSynonymsInHighlight,
65
66
  :unretrievableAttributes, :disableTypoToleranceOnWords, :disableTypoToleranceOnAttributes, :altCorrections,
66
- :ignorePlurals, :maxValuesPerFacet, :distinct, :numericAttributesToIndex,
67
+ :ignorePlurals, :maxValuesPerFacet, :distinct, :numericAttributesToIndex, :numericAttributesForFiltering,
67
68
  :allowTyposOnNumericTokens, :allowCompressionOfIntegerArray,
68
69
  :advancedSyntax]
69
70
  OPTIONS.each do |k|
@@ -79,7 +80,7 @@ module AlgoliaSearch
79
80
 
80
81
  def attribute(*names, &block)
81
82
  raise ArgumentError.new('Cannot pass multiple attribute names if block given') if block_given? and names.length > 1
82
- raise ArgumentError.new('Cannot specify additional attributes on a slave index') if @options[:slave]
83
+ raise ArgumentError.new('Cannot specify additional attributes on a replica index') if @options[:slave] || @options[:replica]
83
84
  @attributes ||= {}
84
85
  names.flatten.each do |name|
85
86
  @attributes[name.to_s] = block_given? ? Proc.new { |o| o.instance_eval(&block) } : Proc.new { |o| o.send(name) }
@@ -89,7 +90,7 @@ module AlgoliaSearch
89
90
 
90
91
  def add_attribute(*names, &block)
91
92
  raise ArgumentError.new('Cannot pass multiple attribute names if block given') if block_given? and names.length > 1
92
- raise ArgumentError.new('Cannot specify additional attributes on a slave index') if @options[:slave]
93
+ raise ArgumentError.new('Cannot specify additional attributes on a replica index') if @options[:slave] || @options[:replica]
93
94
  @additional_attributes ||= {}
94
95
  names.each do |name|
95
96
  @additional_attributes[name.to_s] = block_given? ? Proc.new { |o| o.instance_eval(&block) } : Proc.new { |o| o.send(name) }
@@ -201,14 +202,14 @@ module AlgoliaSearch
201
202
  end
202
203
 
203
204
  def geoloc(lat_attr, lng_attr)
204
- raise ArgumentError.new('Cannot specify additional attributes on a slave index') if @options[:slave]
205
+ raise ArgumentError.new('Cannot specify additional attributes on a replica index') if @options[:slave] || @options[:replica]
205
206
  add_attribute :_geoloc do |o|
206
207
  { :lat => o.send(lat_attr).to_f, :lng => o.send(lng_attr).to_f }
207
208
  end
208
209
  end
209
210
 
210
211
  def tags(*args, &block)
211
- raise ArgumentError.new('Cannot specify additional attributes on a slave index') if @options[:slave]
212
+ raise ArgumentError.new('Cannot specify additional attributes on a replica index') if @options[:slave] || @options[:replica]
212
213
  add_attribute :_tags do |o|
213
214
  v = block_given? ? o.instance_eval(&block) : args
214
215
  v.is_a?(Array) ? v : [v]
@@ -225,25 +226,41 @@ module AlgoliaSearch
225
226
  v = get_setting(k)
226
227
  settings[k] = v if !v.nil?
227
228
  end
228
- settings[:slaves] = additional_indexes.select { |options, s| options[:slave] }.map do |options, s|
229
- name = options[:index_name]
230
- name = "#{name}_#{Rails.env.to_s}" if options[:per_environment]
231
- name
232
- end if !@options[:slave]
229
+ if !@options[:slave] && !@options[:replica]
230
+ settings[:slaves] = additional_indexes.select { |opts, s| opts[:slave] }.map do |opts, s|
231
+ name = opts[:index_name]
232
+ name = "#{name}_#{Rails.env.to_s}" if opts[:per_environment]
233
+ name
234
+ end
235
+ settings.delete(:slaves) if settings[:slaves].empty?
236
+ settings[:replicas] = additional_indexes.select { |opts, s| opts[:replica] }.map do |opts, s|
237
+ name = opts[:index_name]
238
+ name = "#{name}_#{Rails.env.to_s}" if opts[:per_environment]
239
+ name
240
+ end
241
+ settings.delete(:replicas) if settings[:replicas].empty?
242
+ end
233
243
  settings
234
244
  end
235
245
 
236
246
  def add_index(index_name, options = {}, &block)
237
- raise ArgumentError.new('Cannot specify additional index on a slave index') if @options[:slave]
247
+ raise ArgumentError.new('Cannot specify additional index on a replica index') if @options[:slave] || @options[:replica]
238
248
  raise ArgumentError.new('No block given') if !block_given?
239
249
  raise ArgumentError.new('Options auto_index and auto_remove cannot be set on nested indexes') if options[:auto_index] || options[:auto_remove]
240
- options[:index_name] = index_name
241
250
  @additional_indexes ||= {}
251
+ raise MixedSlavesAndReplicas.new('Cannot mix slaves and replicas in the same configuration (add_slave is deprecated)') if (options[:slave] && @additional_indexes.any? { |opts, _| opts[:replica] }) || (options[:replica] && @additional_indexes.any? { |opts, _| opts[:slave] })
252
+ options[:index_name] = index_name
242
253
  @additional_indexes[options] = IndexSettings.new(options, Proc.new)
243
254
  end
244
255
 
256
+ def add_replica(index_name, options = {}, &block)
257
+ raise ArgumentError.new('Cannot specify additional replicas on a replica index') if @options[:slave] || @options[:replica]
258
+ raise ArgumentError.new('No block given') if !block_given?
259
+ add_index(index_name, options.merge({ :replica => true }), &block)
260
+ end
261
+
245
262
  def add_slave(index_name, options = {}, &block)
246
- raise ArgumentError.new('Cannot specify additional slaves on a slave index') if @options[:slave]
263
+ raise ArgumentError.new('Cannot specify additional slaves on a slave index') if @options[:slave] || @options[:replica]
247
264
  raise ArgumentError.new('No block given') if !block_given?
248
265
  add_index(index_name, options.merge({ :slave => true }), &block)
249
266
  end
@@ -287,7 +304,7 @@ module AlgoliaSearch
287
304
 
288
305
  # special handling of get_settings to avoid raising errors on 404
289
306
  def get_settings(*args)
290
- SafeIndex.log_or_throw(:move_index) do
307
+ SafeIndex.log_or_throw(:get_settings) do
291
308
  begin
292
309
  @index.get_settings(*args)
293
310
  rescue Algolia::AlgoliaError => e
@@ -452,7 +469,7 @@ module AlgoliaSearch
452
469
  algolia_configurations.each do |options, settings|
453
470
  next if algolia_indexing_disabled?(options)
454
471
  index = algolia_ensure_init(options, settings)
455
- next if options[:slave]
472
+ next if options[:slave] || options[:replica]
456
473
  last_task = nil
457
474
 
458
475
  algolia_find_in_batches(batch_size) do |group|
@@ -472,7 +489,7 @@ module AlgoliaSearch
472
489
  end
473
490
  last_task = index.save_objects(objects)
474
491
  end
475
- index.wait_task(last_task["taskID"]) if last_task and synchronous == true
492
+ index.wait_task(last_task["taskID"]) if last_task and (synchronous || options[:synchronous])
476
493
  end
477
494
  nil
478
495
  end
@@ -482,16 +499,18 @@ module AlgoliaSearch
482
499
  return if @algolia_without_auto_index_scope
483
500
  algolia_configurations.each do |options, settings|
484
501
  next if algolia_indexing_disabled?(options)
485
- next if options[:slave]
502
+ next if options[:slave] || options[:replica]
486
503
 
487
504
  # fetch the master settings
488
505
  master_index = algolia_ensure_init(options, settings)
489
506
  master_settings = master_index.get_settings rescue {} # if master doesn't exist yet
490
507
  master_settings.merge!(JSON.parse(settings.to_settings.to_json)) # convert symbols to strings
491
508
 
492
- # remove the slaves of the temporary index
509
+ # remove the replicas of the temporary index
493
510
  master_settings.delete :slaves
494
511
  master_settings.delete 'slaves'
512
+ master_settings.delete :replicas
513
+ master_settings.delete 'replicas'
495
514
 
496
515
  # init temporary index
497
516
  index_name = algolia_index_name(options)
@@ -510,7 +529,7 @@ module AlgoliaSearch
510
529
  end
511
530
 
512
531
  move_task = SafeIndex.move_index(tmp_index.name, index_name)
513
- tmp_index.wait_task(move_task["taskID"]) if synchronous == true
532
+ master_index.wait_task(move_task["taskID"]) if synchronous || options[:synchronous]
514
533
  end
515
534
  nil
516
535
  end
@@ -519,9 +538,9 @@ module AlgoliaSearch
519
538
  algolia_configurations.each do |options, settings|
520
539
  next if algolia_indexing_disabled?(options)
521
540
  index = algolia_ensure_init(options, settings)
522
- next if options[:slave]
541
+ next if options[:slave] || options[:replica]
523
542
  task = index.save_objects(objects.map { |o| settings.get_attributes(o).merge 'objectID' => algolia_object_id_of(o, options) })
524
- index.wait_task(task["taskID"]) if synchronous == true
543
+ index.wait_task(task["taskID"]) if synchronous || options[:synchronous]
525
544
  end
526
545
  end
527
546
 
@@ -531,17 +550,17 @@ module AlgoliaSearch
531
550
  next if algolia_indexing_disabled?(options)
532
551
  object_id = algolia_object_id_of(object, options)
533
552
  index = algolia_ensure_init(options, settings)
534
- next if options[:slave]
553
+ next if options[:slave] || options[:replica]
535
554
  if algolia_indexable?(object, options)
536
555
  raise ArgumentError.new("Cannot index a record with a blank objectID") if object_id.blank?
537
- if synchronous
556
+ if synchronous || options[:synchronous]
538
557
  index.add_object!(settings.get_attributes(object), object_id)
539
558
  else
540
559
  index.add_object(settings.get_attributes(object), object_id)
541
560
  end
542
561
  elsif algolia_conditional_index?(options) && !object_id.blank?
543
562
  # remove non-indexable objects
544
- if synchronous
563
+ if synchronous || options[:synchronous]
545
564
  index.delete_object!(object_id)
546
565
  else
547
566
  index.delete_object(object_id)
@@ -558,8 +577,8 @@ module AlgoliaSearch
558
577
  algolia_configurations.each do |options, settings|
559
578
  next if algolia_indexing_disabled?(options)
560
579
  index = algolia_ensure_init(options, settings)
561
- next if options[:slave]
562
- if synchronous
580
+ next if options[:slave] || options[:replica]
581
+ if synchronous || options[:synchronous]
563
582
  index.delete_object!(object_id)
564
583
  else
565
584
  index.delete_object(object_id)
@@ -572,15 +591,20 @@ module AlgoliaSearch
572
591
  algolia_configurations.each do |options, settings|
573
592
  next if algolia_indexing_disabled?(options)
574
593
  index = algolia_ensure_init(options, settings)
575
- next if options[:slave]
576
- synchronous ? index.clear! : index.clear
594
+ next if options[:slave] || options[:replica]
595
+ synchronous || options[:synchronous] ? index.clear! : index.clear
577
596
  @algolia_indexes[settings] = nil
578
597
  end
579
598
  nil
580
599
  end
581
600
 
582
601
  def algolia_raw_search(q, params = {})
583
- index_name = params.delete(:index) || params.delete('index') || params.delete(:slave) || params.delete('slave')
602
+ index_name = params.delete(:index) ||
603
+ params.delete('index') ||
604
+ params.delete(:slave) ||
605
+ params.delete('slave') ||
606
+ params.delete(:replica) ||
607
+ params.delete('replica')
584
608
  index = algolia_index(index_name)
585
609
  index.search(q, Hash[params.map { |k,v| [k.to_s, v.to_s] }])
586
610
  end
@@ -641,7 +665,12 @@ module AlgoliaSearch
641
665
  end
642
666
 
643
667
  def algolia_search_for_facet_values(facet, text, params = {})
644
- index_name = params.delete(:index) || params.delete('index') || params.delete(:slave) || params.delete('slave')
668
+ index_name = params.delete(:index) ||
669
+ params.delete('index') ||
670
+ params.delete(:slave) ||
671
+ params.delete('slave') ||
672
+ params.delete(:replica) ||
673
+ params.delete('replicas')
645
674
  index = algolia_index(index_name)
646
675
  query = Hash[params.map { |k, v| [k.to_s, v.to_s] }]
647
676
  index.search_facet(facet, text, query)['facetHits']
@@ -655,7 +684,7 @@ module AlgoliaSearch
655
684
  algolia_configurations.each do |o, s|
656
685
  return algolia_ensure_init(o, s) if o[:index_name].to_s == name.to_s
657
686
  end
658
- raise ArgumentError.new("Invalid index/slave name: #{name}")
687
+ raise ArgumentError.new("Invalid index/replica name: #{name}")
659
688
  end
660
689
  algolia_ensure_init
661
690
  end
@@ -669,7 +698,7 @@ module AlgoliaSearch
669
698
 
670
699
  def algolia_must_reindex?(object)
671
700
  algolia_configurations.each do |options, settings|
672
- next if options[:slave]
701
+ next if options[:slave] || options[:replica]
673
702
  return true if algolia_object_id_changed?(object, options)
674
703
  settings.get_attribute_names(object).each do |k|
675
704
  changed_method = "#{k}_changed?"
@@ -682,6 +711,10 @@ module AlgoliaSearch
682
711
  changed_method = "#{condition}_changed?"
683
712
  return true if !object.respond_to?(changed_method) || object.send(changed_method)
684
713
  else
714
+ # if the :if, :unless condition is a anything else,
715
+ # we have no idea whether we should reindex or not
716
+ # let's always reindex then
717
+ return true
685
718
  end
686
719
  end
687
720
  end
@@ -700,6 +733,12 @@ module AlgoliaSearch
700
733
  current_settings = @algolia_indexes[settings].get_settings rescue nil # if the index doesn't exist
701
734
  if !algolia_indexing_disabled?(options) && (index_settings || algoliasearch_settings_changed?(current_settings, settings.to_settings))
702
735
  index_settings ||= settings.to_settings
736
+ used_slaves = !current_settings.nil? && !current_settings['slaves'].nil?
737
+ replicas = index_settings.delete(:replicas) ||
738
+ index_settings.delete('replicas') ||
739
+ index_settings.delete(:slaves) ||
740
+ index_settings.delete('slaves')
741
+ index_settings[used_slaves ? :slaves : :replicas] = replicas
703
742
  @algolia_indexes[settings].set_settings(index_settings)
704
743
  end
705
744
  @algolia_indexes[settings]
@@ -851,15 +890,15 @@ module AlgoliaSearch
851
890
 
852
891
  def algolia_enqueue_remove_from_index!(synchronous)
853
892
  if algoliasearch_options[:enqueue]
854
- algoliasearch_options[:enqueue].call(self, true)
893
+ algoliasearch_options[:enqueue].call(self, true) unless self.class.send(:algolia_indexing_disabled?, algoliasearch_options)
855
894
  else
856
- algolia_remove_from_index!(synchronous)
895
+ algolia_remove_from_index!(synchronous || algolia_synchronous?)
857
896
  end
858
897
  end
859
898
 
860
899
  def algolia_enqueue_index!(synchronous)
861
900
  if algoliasearch_options[:enqueue]
862
- algoliasearch_options[:enqueue].call(self, false)
901
+ algoliasearch_options[:enqueue].call(self, false) unless self.class.send(:algolia_indexing_disabled?, algoliasearch_options)
863
902
  else
864
903
  algolia_index!(synchronous)
865
904
  end
data/spec/spec_helper.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'rubygems'
2
2
  require 'bundler'
3
+ require 'timeout'
3
4
 
4
5
  Bundler.setup :test
5
6
 
@@ -19,6 +20,12 @@ RSpec.configure do |c|
19
20
  c.filter_run :focus => true
20
21
  c.run_all_when_everything_filtered = true
21
22
  c.formatter = 'documentation'
23
+
24
+ c.around(:each) do |example|
25
+ Timeout::timeout(120) {
26
+ example.run
27
+ }
28
+ end
22
29
  end
23
30
 
24
31
  # avoid concurrent access to the same index
@@ -21,7 +21,7 @@
21
21
  * THE SOFTWARE.
22
22
  */
23
23
 
24
- var ALGOLIA_VERSION = '2.9.4';
24
+ var ALGOLIA_VERSION = '2.9.7';
25
25
 
26
26
  /*
27
27
  * Copyright (c) 2013 Algolia
@@ -106,9 +106,9 @@ var AlgoliaSearch = function(applicationID, apiKey, methodOrOptions, resolveDNS,
106
106
  // If hosts is undefined, initialize it with applicationID
107
107
  if (this._isUndefined(hosts)) {
108
108
  hosts = [
109
- this.applicationID + '-1.algolia.' + tld,
110
- this.applicationID + '-2.algolia.' + tld,
111
- this.applicationID + '-3.algolia.' + tld
109
+ this.applicationID + '-1.algolianet.com',
110
+ this.applicationID + '-2.algolianet.com',
111
+ this.applicationID + '-3.algolianet.com'
112
112
  ];
113
113
  }
114
114
  // detect is we use http or https
@@ -118,16 +118,10 @@ var AlgoliaSearch = function(applicationID, apiKey, methodOrOptions, resolveDNS,
118
118
  } else if (method === 'https' || method === 'HTTPS') {
119
119
  this.host_protocol = 'https://';
120
120
  }
121
- // Add hosts in random order
121
+ // Add protocol to hosts
122
122
  for (var i = 0; i < hosts.length; ++i) {
123
- if (Math.random() > 0.5) {
124
- this.hosts.reverse();
125
- }
126
123
  this.hosts.push(this.host_protocol + hosts[i]);
127
124
  }
128
- if (Math.random() > 0.5) {
129
- this.hosts.reverse();
130
- }
131
125
  // then add Distributed Search Network host if there is one
132
126
  if (this.dsn || this.dsnHost != null) {
133
127
  if (this.dsnHost) {
@@ -143,6 +137,8 @@ var AlgoliaSearch = function(applicationID, apiKey, methodOrOptions, resolveDNS,
143
137
  self.options.angular.$http = $http;
144
138
  }]);
145
139
  }
140
+
141
+ this._ua = this.options._ua || 'Algolia for vanilla JavaScript ' + window.ALGOLIA_VERSION;
146
142
  };
147
143
 
148
144
  // This holds the number of JSONP requests done accross clients
@@ -595,6 +591,7 @@ AlgoliaSearch.prototype = {
595
591
 
596
592
  opts.successiveRetryCount = 0;
597
593
  var impl = function() {
594
+
598
595
  if (opts.successiveRetryCount >= self.hosts.length) {
599
596
  var error = { message: 'Cannot connect the Algolia\'s Search API. Please send an email to support@algolia.com to report the issue.' };
600
597
  if (!self._isUndefined(callback) && callback) {
@@ -665,6 +662,7 @@ AlgoliaSearch.prototype = {
665
662
  if (this.tagFilters) {
666
663
  url += '&X-Algolia-TagFilters=' + encodeURIComponent(this.tagFilters);
667
664
  }
665
+ url += '&X-Algolia-Agent=' + encodeURIComponent(this._ua);
668
666
  for (var i = 0; i < this.extraHeaders.length; ++i) {
669
667
  url += '&' + this.extraHeaders[i].key + '=' + this.extraHeaders[i].value;
670
668
  }
@@ -711,6 +709,7 @@ AlgoliaSearch.prototype = {
711
709
  if (this.tagFilters) {
712
710
  url += '&X-Algolia-TagFilters=' + encodeURIComponent(this.tagFilters);
713
711
  }
712
+ url += '&X-Algolia-Agent=' + encodeURIComponent(this._ua);
714
713
  for (var i = 0; i < this.extraHeaders.length; ++i) {
715
714
  url += '&' + this.extraHeaders[i].key + '=' + this.extraHeaders[i].value;
716
715
  }
@@ -786,6 +785,8 @@ AlgoliaSearch.prototype = {
786
785
  url += '&X-Algolia-UserToken=' + encodeURIComponent(this.userToken);
787
786
  }
788
787
 
788
+ url += '&X-Algolia-Agent=' + encodeURIComponent(this._ua);
789
+
789
790
  for (var i = 0; i < this.extraHeaders.length; ++i) {
790
791
  url += '&' + this.extraHeaders[i].key + '=' + this.extraHeaders[i].value;
791
792
  }
@@ -799,7 +800,7 @@ AlgoliaSearch.prototype = {
799
800
  clean();
800
801
 
801
802
  opts.callback(true, false, { 'message': 'Timeout - Failed to load JSONP script.' });
802
- }, this.requestTimeoutInMs);
803
+ }, this.requestTimeoutInMs * (opts.successiveRetryCount + 1));
803
804
 
804
805
  success = function() {
805
806
  if (done || timedOut) {
@@ -896,6 +897,8 @@ AlgoliaSearch.prototype = {
896
897
  url += '&X-Algolia-TagFilters=' + encodeURIComponent(this.tagFilters);
897
898
  }
898
899
 
900
+ url += '&X-Algolia-Agent=' + encodeURIComponent(this._ua);
901
+
899
902
  for (var i = 0; i < this.extraHeaders.length; ++i) {
900
903
  url += '&' + this.extraHeaders[i].key + '=' + this.extraHeaders[i].value;
901
904
  }
@@ -958,6 +961,13 @@ AlgoliaSearch.prototype = {
958
961
  opts.callback(retry, success, response);
959
962
  };
960
963
 
964
+ // we set an empty onprogress listener
965
+ // so that XDomainRequest on IE9 is not aborted
966
+ // refs:
967
+ // - https://github.com/algolia/algoliasearch-client-js/issues/76
968
+ // - https://social.msdn.microsoft.com/Forums/ie/en-US/30ef3add-767c-4436-b8a9-f1ca19b4812e/ie9-rtm-xdomainrequest-issued-requests-may-abort-if-all-event-handlers-not-specified?forum=iewebdevelopment
969
+ request.onprogress = function noop() {};
970
+
961
971
  if (this._support.timeout) {
962
972
  // .timeout supported by both XHR and XDR,
963
973
  // we do receive timeout event, tested
@@ -2661,6 +2671,7 @@ angular.module('algoliasearch', [])
2661
2671
  options.angular = {
2662
2672
  '$injector': $injector
2663
2673
  };
2674
+ options._ua = 'Algolia for AngularJS ' + window.ALGOLIA_VERSION;
2664
2675
  return new AlgoliaSearch(applicationID, apiKey, options);
2665
2676
  }
2666
2677
  };