FIX: ensures search box is working after multiple page loads

FIX: ensures search box is working after multiple page loads

diff --git a/assets/javascripts/discourse/initializers/discourse-algolia.js.es6 b/assets/javascripts/discourse/initializers/discourse-algolia.js.es6
index 6ac72d0..44d75c0 100644
--- a/assets/javascripts/discourse/initializers/discourse-algolia.js.es6
+++ b/assets/javascripts/discourse/initializers/discourse-algolia.js.es6
@@ -1,26 +1,33 @@
 import I18n from "I18n";
 import { h } from "virtual-dom";
-import { on } from "ember-addons/ember-computed-decorators";
 import DiscourseURL from "discourse/lib/url";
 import { withPluginApi } from "discourse/lib/plugin-api";
 import discourseAutocomplete from "./discourse-autocomplete";
+import { schedule } from "@ember/runloop";
 
 export default {
   name: "discourse-algolia",
   initialize() {
     withPluginApi("0.8.8", (api) => {
-      api.modifyClass("component:site-header", {
-        @on("didInsertElement")
-        initializeAlgolia() {
-          this._super();
+      api.createWidget("algolia", {
+        tagName: "li.algolia-holder",
+
+        didRenderWidget() {
           if (
             this.siteSettings.algolia_enabled &&
             this.siteSettings.algolia_autocomplete_enabled
           ) {
-            $("body").addClass("algolia-enabled");
+            schedule("afterRender", () => {
+              document.body.classList.add("algolia-enabled");
 
-            setTimeout(() => {
-              discourseAutocomplete._initialize({
+              const searchBox = document.querySelector("#search-box");
+              searchBox &&
+                searchBox.addEventListener(
+                  "focus",
+                  this._selectSearchBoxContent
+                );
+
+              this._search = discourseAutocomplete._initialize({
                 algoliaApplicationId: this.siteSettings.algolia_application_id,
                 algoliaSearchApiKey: this.siteSettings.algolia_search_api_key,
                 imageBaseURL: "",
@@ -29,13 +36,18 @@ export default {
                   DiscourseURL.routeTo(suggestion.url);
                 },
               });
-            }, 100);
+            });
           }
         },
-      });
 
-      api.createWidget("algolia", {
-        tagName: "li.algolia-holder",
+        willRerenderWidget() {
+          const searchBox = document.querySelector("#search-box");
+          searchBox &&
+            searchBox.removeEventListener("focus", this._selectSearchBox);
+
+          this._search && this._search.autocomplete.destroy();
+        },
+
         html() {
           return [
             h(
@@ -54,6 +66,10 @@ export default {
             ),
           ];
         },
+
+        _selectSearchBoxContent(event) {
+          event.target.select();
+        },
       });
 
       api.decorateWidget("header-icons:before", function (helper) {
diff --git a/assets/javascripts/discourse/initializers/discourse-autocomplete.js.es6 b/assets/javascripts/discourse/initializers/discourse-autocomplete.js.es6
index f301120..5671f0d 100644
--- a/assets/javascripts/discourse/initializers/discourse-autocomplete.js.es6
+++ b/assets/javascripts/discourse/initializers/discourse-autocomplete.js.es6
@@ -1,3 +1,5 @@
+/* eslint-disable */
+
 export default {
   name: "discourse-autocomplete",
   initialize() {},
@@ -11,7 +13,7 @@ export default {
     let tagsIndex = client.initIndex("discourse-tags");
     let usersIndex = client.initIndex("discourse-users");
 
-    autocomplete(
+    return autocomplete(
       searchInput,
       {
         openOnFocus: true,
@@ -157,9 +159,7 @@ export default {
         },
       ]
     ).on("autocomplete:selected", options.onSelect);
-
-    $("#search-box").on("focus", function () {
-      $(this).select();
-    });
   },
 };
+
+/* eslint-enable */
diff --git a/assets/lib/algoliasearch.js b/assets/lib/algoliasearch.js
index b34d97a..9007ef0 100644
--- a/assets/lib/algoliasearch.js
+++ b/assets/lib/algoliasearch.js
@@ -1,3 +1,5 @@
+/* eslint-disable */
+
 /*! algoliasearch 3.22.1 | © 2014, 2015 Algolia SAS | github.com/algolia/algoliasearch-client-js */
 (function(f){var g;if(typeof window!=='undefined'){g=window}else if(typeof self!=='undefined'){g=self}g.ALGOLIA_MIGRATION_LAYER=f()})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
 
@@ -1477,7 +1479,7 @@ Promise.prototype = {
     The primary way of interacting with a promise is through its `then` method,
     which registers callbacks to receive either a promise's eventual value or the
     reason why the promise cannot be fulfilled.
-  
+
     `‍``js
     findUser().then(function(user){
       // user is available
@@ -1485,14 +1487,14 @@ Promise.prototype = {
       // user is unavailable, and you are given the reason why
     });
     `‍``
-  
+
     Chaining
     --------
-  
+
     The return value of `then` is itself a promise.  This second, 'downstream'
     promise is resolved with the return value of the first promise's fulfillment
     or rejection handler, or rejected if the handler throws an exception.
-  
+
     `‍``js
     findUser().then(function (user) {
       return user.name;
@@ -1502,7 +1504,7 @@ Promise.prototype = {
       // If `findUser` fulfilled, `userName` will be the user's name, otherwise it
       // will be `'default name'`
     });
-  
+
     findUser().then(function (user) {
       throw new Error('Found user, but still unhappy');
     }, function (reason) {
@@ -1515,7 +1517,7 @@ Promise.prototype = {
     });
     `‍``
     If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream.
-  
+
     `‍``js
     findUser().then(function (user) {
       throw new PedagogicalException('Upstream error');
@@ -1527,15 +1529,15 @@ Promise.prototype = {
       // The `PedgagocialException` is propagated all the way down to here
     });
     `‍``
-  
+
     Assimilation
     ------------
-  
+
     Sometimes the value you want to propagate to a downstream promise can only be
     retrieved asynchronously. This can be achieved by returning a promise in the
     fulfillment or rejection handler. The downstream promise will then be pending
     until the returned promise is settled. This is called *assimilation*.
-  
+
     `‍``js
     findUser().then(function (user) {
       return findCommentsByAuthor(user);
@@ -1543,9 +1545,9 @@ Promise.prototype = {
       // The user's comments are now available
     });
     `‍``
-  
+
     If the assimliated promise rejects, then the downstream promise will also reject.
-  
+
     `‍``js
     findUser().then(function (user) {
       return findCommentsByAuthor(user);
@@ -1555,15 +1557,15 @@ Promise.prototype = {
       // If `findCommentsByAuthor` rejects, we'll have the reason here
     });
     `‍``
-  
+
     Simple Example
     --------------
-  
+
     Synchronous Example
-  
+
     `‍``javascript
     let result;
-  
+
     try {
       result = findResult();
       // success
@@ -1571,9 +1573,9 @@ Promise.prototype = {
       // failure
     }
     `‍``
-  
+
     Errback Example
-  
+
     `‍``js
     findResult(function(result, err){
       if (err) {
@@ -1583,9 +1585,9 @@ Promise.prototype = {
       }
     });
     `‍``
-  
+
     Promise Example;
-  
+
     `‍``javascript
     findResult().then(function(result){
       // success
@@ -1593,15 +1595,15 @@ Promise.prototype = {
       // failure
     });
     `‍``
-  
+
     Advanced Example
     --------------
-  
+
     Synchronous Example
-  
+
     `‍``javascript
     let author, books;
-  
+
     try {
       author = findAuthor();

[... diff too long, it was truncated ...]

GitHub sha: 86c4af71