1*4773e145SAndreas Gohr/** 2*4773e145SAndreas Gohr * Web component for searchindex manager plugin 3*4773e145SAndreas Gohr * 4*4773e145SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org> 5*4773e145SAndreas Gohr * @author Symon Bent <hendrybadao@gmail.com> 6*4773e145SAndreas Gohr */ 7*4773e145SAndreas Gohr 8*4773e145SAndreas Gohrclass SearchIndexManager extends HTMLElement { 9*4773e145SAndreas Gohr #pages = null; 10*4773e145SAndreas Gohr #page = null; 11*4773e145SAndreas Gohr #url = null; 12*4773e145SAndreas Gohr #done = 1; 13*4773e145SAndreas Gohr #count = 0; 14*4773e145SAndreas Gohr #$msg = null; 15*4773e145SAndreas Gohr #$buttons = null; 16*4773e145SAndreas Gohr #force = ''; 17*4773e145SAndreas Gohr #lang = { 18*4773e145SAndreas Gohr rebuild: '*Rebuild Index', 19*4773e145SAndreas Gohr rebuild_tip: '*Clears the current index and then adds all pages from scratch.', 20*4773e145SAndreas Gohr update: '*Update Index', 21*4773e145SAndreas Gohr update_tip: '*Updates the index for any changed pages since the last update.', 22*4773e145SAndreas Gohr finding: '*Finding pages...', 23*4773e145SAndreas Gohr pages: '*Found %d pages.', 24*4773e145SAndreas Gohr indexing: '*Indexing', 25*4773e145SAndreas Gohr indexed: '*indexed', 26*4773e145SAndreas Gohr notindexed: '*not indexed', 27*4773e145SAndreas Gohr done: '*Finished indexing.', 28*4773e145SAndreas Gohr clearing: '*Clearing index...', 29*4773e145SAndreas Gohr }; 30*4773e145SAndreas Gohr 31*4773e145SAndreas Gohr connectedCallback() { 32*4773e145SAndreas Gohr this.#lang = {...this.#lang, ...JSON.parse(this.getAttribute('lang'))}; 33*4773e145SAndreas Gohr this.#url = this.getAttribute('url'); 34*4773e145SAndreas Gohr this.#render(); 35*4773e145SAndreas Gohr this.#$msg = this.querySelector('.msg'); 36*4773e145SAndreas Gohr this.#$buttons = this.querySelector('.buttons'); 37*4773e145SAndreas Gohr 38*4773e145SAndreas Gohr this.querySelector('.rebuild').addEventListener('click', () => this.#rebuild()); 39*4773e145SAndreas Gohr this.querySelector('.update').addEventListener('click', () => this.#update()); 40*4773e145SAndreas Gohr } 41*4773e145SAndreas Gohr 42*4773e145SAndreas Gohr /** 43*4773e145SAndreas Gohr * Render the component HTML 44*4773e145SAndreas Gohr */ 45*4773e145SAndreas Gohr #render() { 46*4773e145SAndreas Gohr this.innerHTML = ` 47*4773e145SAndreas Gohr <div class="buttons"> 48*4773e145SAndreas Gohr <input type="button" class="button rebuild" value="${this.#lang.rebuild}"> 49*4773e145SAndreas Gohr <p>${this.#lang.rebuild_tip}</p> 50*4773e145SAndreas Gohr <input type="button" class="button update" value="${this.#lang.update}"> 51*4773e145SAndreas Gohr <p>${this.#lang.update_tip}</p> 52*4773e145SAndreas Gohr </div> 53*4773e145SAndreas Gohr <div class="msg"></div> 54*4773e145SAndreas Gohr `; 55*4773e145SAndreas Gohr } 56*4773e145SAndreas Gohr 57*4773e145SAndreas Gohr /** 58*4773e145SAndreas Gohr * Gives textual feedback 59*4773e145SAndreas Gohr */ 60*4773e145SAndreas Gohr #message(text) { 61*4773e145SAndreas Gohr if (text.charAt(0) !== '<') { 62*4773e145SAndreas Gohr text = `<p>${text}</p>`; 63*4773e145SAndreas Gohr } 64*4773e145SAndreas Gohr this.#$msg.innerHTML = text; 65*4773e145SAndreas Gohr } 66*4773e145SAndreas Gohr 67*4773e145SAndreas Gohr /** 68*4773e145SAndreas Gohr * Send a POST request to the ajax endpoint 69*4773e145SAndreas Gohr */ 70*4773e145SAndreas Gohr async #post(params) { 71*4773e145SAndreas Gohr const response = await fetch(this.#url, { 72*4773e145SAndreas Gohr method: 'POST', 73*4773e145SAndreas Gohr headers: { 74*4773e145SAndreas Gohr 'Content-Type': 'application/x-www-form-urlencoded', 75*4773e145SAndreas Gohr }, 76*4773e145SAndreas Gohr body: params 77*4773e145SAndreas Gohr }); 78*4773e145SAndreas Gohr return response.json(); 79*4773e145SAndreas Gohr } 80*4773e145SAndreas Gohr 81*4773e145SAndreas Gohr /** 82*4773e145SAndreas Gohr * Starts the indexing of a page. 83*4773e145SAndreas Gohr */ 84*4773e145SAndreas Gohr async #index() { 85*4773e145SAndreas Gohr if (this.#page) { 86*4773e145SAndreas Gohr const indexed = await this.#post(`call=indexpage&page=${encodeURIComponent(this.#page)}&force=${this.#force}`); 87*4773e145SAndreas Gohr const wait = 250; 88*4773e145SAndreas Gohr // next page from queue 89*4773e145SAndreas Gohr this.#page = this.#pages.shift(); 90*4773e145SAndreas Gohr this.#done++; 91*4773e145SAndreas Gohr 92*4773e145SAndreas Gohr const msg = indexed ? this.#lang.indexed : this.#lang.notindexed; 93*4773e145SAndreas Gohr const status = `<p class="status">${msg}</p>`; 94*4773e145SAndreas Gohr this.#message(`<p>${this.#lang.indexing} ${this.#done}/${this.#count}</p><p class="name">${this.#page}</p>${status}`); 95*4773e145SAndreas Gohr // next index run 96*4773e145SAndreas Gohr setTimeout(() => this.#index(), wait); 97*4773e145SAndreas Gohr } else { 98*4773e145SAndreas Gohr this.#finished(); 99*4773e145SAndreas Gohr } 100*4773e145SAndreas Gohr } 101*4773e145SAndreas Gohr 102*4773e145SAndreas Gohr /** 103*4773e145SAndreas Gohr * Called when indexing is complete 104*4773e145SAndreas Gohr */ 105*4773e145SAndreas Gohr #finished() { 106*4773e145SAndreas Gohr this.#throbberOff(); 107*4773e145SAndreas Gohr this.#message(this.#lang.done); 108*4773e145SAndreas Gohr setTimeout(() => { 109*4773e145SAndreas Gohr this.#message(''); 110*4773e145SAndreas Gohr this.#$buttons.style.display = ''; 111*4773e145SAndreas Gohr }, 3000); 112*4773e145SAndreas Gohr } 113*4773e145SAndreas Gohr 114*4773e145SAndreas Gohr /** 115*4773e145SAndreas Gohr * Cleans the index (ready for complete rebuild) 116*4773e145SAndreas Gohr */ 117*4773e145SAndreas Gohr async #clear() { 118*4773e145SAndreas Gohr this.#message(this.#lang.clearing); 119*4773e145SAndreas Gohr const success = await this.#post('call=clearindex'); 120*4773e145SAndreas Gohr if (!success) { 121*4773e145SAndreas Gohr this.#message(this.#lang.clearing + ' - failed, retrying...'); 122*4773e145SAndreas Gohr // retry 123*4773e145SAndreas Gohr setTimeout(() => this.#clear(), 5000); 124*4773e145SAndreas Gohr } else { 125*4773e145SAndreas Gohr // start indexing 126*4773e145SAndreas Gohr this.#force = 'true'; 127*4773e145SAndreas Gohr setTimeout(() => this.#index(), 1000); 128*4773e145SAndreas Gohr } 129*4773e145SAndreas Gohr } 130*4773e145SAndreas Gohr 131*4773e145SAndreas Gohr /** 132*4773e145SAndreas Gohr * Starts a full rebuild (clear + reindex) 133*4773e145SAndreas Gohr */ 134*4773e145SAndreas Gohr #rebuild() { 135*4773e145SAndreas Gohr this.#update(true); 136*4773e145SAndreas Gohr } 137*4773e145SAndreas Gohr 138*4773e145SAndreas Gohr /** 139*4773e145SAndreas Gohr * Starts the index update 140*4773e145SAndreas Gohr */ 141*4773e145SAndreas Gohr async #update(rebuild = false) { 142*4773e145SAndreas Gohr this.#done = 1; 143*4773e145SAndreas Gohr this.#$buttons.style.display = 'none'; 144*4773e145SAndreas Gohr this.#throbberOn(); 145*4773e145SAndreas Gohr this.#message(this.#lang.finding); 146*4773e145SAndreas Gohr this.#pages = await this.#post('call=pagelist'); 147*4773e145SAndreas Gohr if (this.#pages.length) { 148*4773e145SAndreas Gohr this.#count = this.#pages.length; 149*4773e145SAndreas Gohr this.#message(this.#lang.pages.replace(/%d/, this.#pages.length)); 150*4773e145SAndreas Gohr 151*4773e145SAndreas Gohr // move the first page from the queue 152*4773e145SAndreas Gohr this.#page = this.#pages.shift(); 153*4773e145SAndreas Gohr 154*4773e145SAndreas Gohr // complete index rebuild? 155*4773e145SAndreas Gohr if (rebuild === true) { 156*4773e145SAndreas Gohr this.#clear(); 157*4773e145SAndreas Gohr } else { 158*4773e145SAndreas Gohr this.#force = ''; 159*4773e145SAndreas Gohr // just start indexing immediately 160*4773e145SAndreas Gohr setTimeout(() => this.#index(), 1000); 161*4773e145SAndreas Gohr } 162*4773e145SAndreas Gohr } else { 163*4773e145SAndreas Gohr this.#finished(); 164*4773e145SAndreas Gohr } 165*4773e145SAndreas Gohr } 166*4773e145SAndreas Gohr 167*4773e145SAndreas Gohr /** 168*4773e145SAndreas Gohr * Add a throbber image 169*4773e145SAndreas Gohr */ 170*4773e145SAndreas Gohr #throbberOn() { 171*4773e145SAndreas Gohr this.#$msg.classList.add('updating'); 172*4773e145SAndreas Gohr } 173*4773e145SAndreas Gohr 174*4773e145SAndreas Gohr /** 175*4773e145SAndreas Gohr * Stop the throbber 176*4773e145SAndreas Gohr */ 177*4773e145SAndreas Gohr #throbberOff() { 178*4773e145SAndreas Gohr this.#$msg.classList.remove('updating'); 179*4773e145SAndreas Gohr } 180*4773e145SAndreas Gohr} 181*4773e145SAndreas Gohr 182*4773e145SAndreas GohrcustomElements.define('searchindex-manager', SearchIndexManager); 183