From 48758712233a2e0872f16ff23357a11a40857486 Mon Sep 17 00:00:00 2001 From: pollen8 Date: Tue, 21 Jan 2014 10:50:08 +0100 Subject: [PATCH] refractoring autocomplete, as recent fixes in dbjoin version were not in cdd version. Also (still) trying to resolve loading message not always hiding when multiple requests are sent/cancelled --- media/com_fabrik/js/autocomplete-min.js | 2 +- media/com_fabrik/js/autocomplete.js | 124 ++++++++++++++---------- 2 files changed, 74 insertions(+), 52 deletions(-) diff --git a/media/com_fabrik/js/autocomplete-min.js b/media/com_fabrik/js/autocomplete-min.js index ad79d7edf8c..978d2f68722 100644 --- a/media/com_fabrik/js/autocomplete-min.js +++ b/media/com_fabrik/js/autocomplete-min.js @@ -1 +1 @@ -var FbAutocomplete=new Class({Implements:[Options,Events],options:{menuclass:"auto-complete-container",classes:{ul:"results",li:"result"},url:"index.php",max:10,onSelection:Class.empty,autoLoadSingleResult:true,minTriggerChars:1,storeMatchedResultsOnly:false},initialize:function(b,a){this.matchedResult=false;this.setOptions(a);b=b.replace("-auto-complete","");this.options.labelelement=typeOf(document.id(b+"-auto-complete"))==="null"?document.getElement(b+"-auto-complete"):document.id(b+"-auto-complete");this.cache={};this.selected=-1;this.mouseinsde=false;document.addEvent("keydown",function(c){this.doWatchKeys(c)}.bind(this));this.element=typeOf(document.id(b))==="null"?document.getElement(b):document.id(b);this.buildMenu();if(!this.getInputElement()){fconsole("autocomplete didn't find input element");return}this.getInputElement().setProperty("autocomplete","off");this.getInputElement().addEvent("keyup",function(c){this.search(c)}.bind(this));this.getInputElement().addEvent("blur",function(c){if(this.options.storeMatchedResultsOnly){if(!this.matchedResult){if(typeof(this.data)==="undefined"||!(this.data.length===1&&this.options.autoLoadSingleResult)){this.element.value=""}}}}.bind(this))},search:function(b){if(!this.isMinTriggerlength()){return}if(b.key==="tab"||b.key==="enter"){b.stop();this.closeMenu();return}this.matchedResult=false;var a=this.getInputElement().get("value");if(a===""){this.element.value=""}if(a!==this.searchText&&a!==""){if(this.options.storeMatchedResultsOnly===false){this.element.value=a}this.positionMenu();if(this.cache[a]){this.populateMenu(this.cache[a]);this.openMenu()}else{Fabrik.loader.start(this.getInputElement());if(this.ajax){this.closeMenu();this.ajax.cancel()}this.ajax=new Request({url:this.options.url,data:{value:a},onRequest:function(){Fabrik.loader.start(this.getInputElement())}.bind(this),onCancel:function(){Fabrik.loader.stop(this.getInputElement());this.ajax=null}.bind(this),onSuccess:function(c){Fabrik.loader.stop(this.getInputElement());this.completeAjax(c,a)}.bind(this)}).send()}}this.searchText=a},completeAjax:function(b,a){b=JSON.decode(b);this.cache[a]=b;Fabrik.loader.stop(this.getInputElement());this.populateMenu(b);this.openMenu()},buildMenu:function(){this.menu=new Element("div",{"class":this.options.menuclass,styles:{position:"absolute"}}).adopt(new Element("ul",{"class":this.options.classes.ul}));this.menu.inject(document.body);this.menu.addEvent("mouseenter",function(){this.mouseinsde=true}.bind(this));this.menu.addEvent("mouseleave",function(){this.mouseinsde=false}.bind(this))},getInputElement:function(){return this.options.labelelement?this.options.labelelement:this.element},positionMenu:function(){var a=this.getInputElement().getCoordinates();var b=this.getInputElement().getPosition();this.menu.setStyles({left:a.left,top:(a.top+a.height)-1,width:a.width})},populateMenu:function(e){e.map(function(h,g){h.text=Encoder.htmlDecode(h.text);return h});this.data=e;var b=this.getListMax();var d=this.menu.getElement("ul");d.empty();if(e.length===1&&this.options.autoLoadSingleResult){this.matchedResult=true;this.element.value=e[0].value;this.fireEvent("selection",[this,this.element.value])}for(var c=0;cthis.options.max){new Element("li").set("text","....").inject(d)}},makeSelection:function(a){if(typeOf(a)!=="null"){this.getInputElement().value=a.get("text");this.element.value=a.getProperty("data-value");this.matchedResult=true;this.closeMenu();this.fireEvent("selection",[this,this.element.value]);this.element.fireEvent("change",new Event.Mock(this.element,"change"),700);Fabrik.fireEvent("fabrik.autocomplete.selected",[this,this.element.value])}else{Fabrik.fireEvent("fabrik.autocomplete.notselected",[this,this.element.value])}},closeMenu:function(){if(this.shown){this.shown=false;this.menu.fade("out");this.selected=-1;document.removeEvent("click",function(a){this.doTestMenuClose(a)}.bind(this))}},openMenu:function(){if(!this.shown){if(this.isMinTriggerlength()){this.shown=true;this.menu.setStyle("visibility","visible").fade("in");document.addEvent("click",function(a){this.doTestMenuClose(a)}.bind(this));this.selected=0;this.highlight()}}},doTestMenuClose:function(){if(!this.mouseinsde){this.closeMenu()}},isMinTriggerlength:function(){var a=this.getInputElement().get("value");return a.length>=this.options.minTriggerChars},getListMax:function(){if(typeOf(this.data)==="null"){return 0}return this.data.length>this.options.max?this.options.max:this.data.length},doWatchKeys:function(c){var a=this.getListMax();if(!this.shown){if(c.code.toInt()===13){c.stop()}if(c.code.toInt()===40&&document.activeElement===this.getInputElement()){this.openMenu()}}else{if(!this.isMinTriggerlength()){c.stop();this.closeMenu()}else{if(c.key==="enter"||c.key==="tab"){window.fireEvent("blur")}switch(c.code){case 40:if(!this.shown){this.openMenu()}if(this.selected+1=-1){this.selected--;this.highlight()}c.stop();break;case 13:case 9:c.stop();var b=new Event.Mock(this.getSelected(),"click");this.makeSelection(b);break;case 27:c.stop();this.matchedResult=false;this.closeMenu();break}}}},getSelected:function(){var b=this.menu.getElements("li").filter(function(a,c){return c===this.selected}.bind(this));return b[0]},highlight:function(){this.matchedResult=true;this.menu.getElements("li").each(function(a,b){if(b===this.selected){a.addClass("selected")}else{a.removeClass("selected")}}.bind(this))}});var FabCddAutocomplete=new Class({Extends:FbAutocomplete,search:function(f){var d;var b=this.getInputElement().get("value");if(b===""){this.element.value=""}if(b!==this.searchText&&b!==""){var a=document.id(this.options.observerid);if(typeOf(a)!=="null"){d=a.get("value")+"."+b}else{this.parent(f);return}this.positionMenu();if(this.cache[d]){this.populateMenu(this.cache[d]);this.openMenu()}else{Fabrik.loader.start(this.getInputElement());if(this.ajax){this.closeMenu();this.ajax.cancel()}var c=document.id(this.options.observerid).get("value");if(typeOf(c)==="null"){c=Fabrik.blocks[this.options.formRef].formElements.get(this.options.observerid).get("value")}this.ajax=new Request({method:"post",url:this.options.url,data:{value:b,fabrik_cascade_ajax_update:1,v:c},onSuccess:function(g){this.completeAjax(g)}.bind(this),onError:function(g,e){console.log(g,e)},onFailure:function(e){console.log(e)}}).send()}}this.searchText=b}}); \ No newline at end of file +var FbAutocomplete=new Class({Implements:[Options,Events],options:{menuclass:"auto-complete-container",classes:{ul:"results",li:"result"},url:"index.php",max:10,onSelection:Class.empty,autoLoadSingleResult:true,minTriggerChars:1,storeMatchedResultsOnly:false},initialize:function(b,a){this.matchedResult=false;this.setOptions(a);b=b.replace("-auto-complete","");this.options.labelelement=typeOf(document.id(b+"-auto-complete"))==="null"?document.getElement(b+"-auto-complete"):document.id(b+"-auto-complete");this.cache={};this.selected=-1;this.mouseinsde=false;document.addEvent("keydown",function(c){this.doWatchKeys(c)}.bind(this));this.element=typeOf(document.id(b))==="null"?document.getElement(b):document.id(b);this.buildMenu();if(!this.getInputElement()){fconsole("autocomplete didn't find input element");return}this.getInputElement().setProperty("autocomplete","off");this.getInputElement().addEvent("keyup",function(c){this.search(c)}.bind(this));this.getInputElement().addEvent("blur",function(c){if(this.options.storeMatchedResultsOnly){if(!this.matchedResult){if(typeof(this.data)==="undefined"||!(this.data.length===1&&this.options.autoLoadSingleResult)){this.element.value=""}}}}.bind(this))},canSearch:function(a){if(!this.isMinTriggerlength()){return false}if(a.key==="tab"||a.key==="enter"){a.stop();this.closeMenu();return false}},defineSearchValue:function(){var a=this.getInputElement().get("value");if(a===""){this.element.value=""}return a},search:function(c){if(!this.canSearch(c)){return}this.matchedResult=false;var a=this.getInputElement().get("value");if(a===""){this.element.value=""}if(a!==this.searchText&&a!==""){if(this.options.storeMatchedResultsOnly===false){this.element.value=a}this.positionMenu();if(this.cache[a]){this.populateMenu(this.cache[a]);this.openMenu()}else{if(this.ajax){this.closeMenu();this.ajax.cancel()}var b={value:a};this.ajax=this.makeAjax(this.options.url,b)}}this.searchText=a},makeAjax:function(a,b){return new Request({url:a,data:b,onRequest:function(){Fabrik.loader.start(this.getInputElement())}.bind(this),onCancel:function(){Fabrik.loader.stop(this.getInputElement())}.bind(this),onSuccess:function(c){this.completeAjax(c)}.bind(this),onComplete:function(){Fabrik.loader.stop(this.getInputElement())}.bind(this),onFailure:function(){Fabrik.loader.stop(this.getInputElement())}.bind(this),onException:function(){Fabrik.loader.stop(this.getInputElement())}.bind(this)}).send()},completeAjax:function(a){Fabrik.loader.stop(this.getInputElement());a=JSON.decode(a);this.cache[v]=a;this.populateMenu(a);this.openMenu()},buildMenu:function(){this.menu=new Element("div",{"class":this.options.menuclass,styles:{position:"absolute"}}).adopt(new Element("ul",{"class":this.options.classes.ul}));this.menu.inject(document.body);this.menu.addEvent("mouseenter",function(){this.mouseinsde=true}.bind(this));this.menu.addEvent("mouseleave",function(){this.mouseinsde=false}.bind(this))},getInputElement:function(){return this.options.labelelement?this.options.labelelement:this.element},positionMenu:function(){var a=this.getInputElement().getCoordinates();var b=this.getInputElement().getPosition();this.menu.setStyles({left:a.left,top:(a.top+a.height)-1,width:a.width})},populateMenu:function(e){e.map(function(h,g){h.text=Encoder.htmlDecode(h.text);return h});this.data=e;var b=this.getListMax();var d=this.menu.getElement("ul");d.empty();if(e.length===1&&this.options.autoLoadSingleResult){this.matchedResult=true;this.element.value=e[0].value;this.fireEvent("selection",[this,this.element.value])}for(var c=0;cthis.options.max){new Element("li").set("text","....").inject(d)}},makeSelection:function(a){if(typeOf(a)!=="null"){this.getInputElement().value=a.get("text");this.element.value=a.getProperty("data-value");this.matchedResult=true;this.closeMenu();this.fireEvent("selection",[this,this.element.value]);this.element.fireEvent("change",new Event.Mock(this.element,"change"),700);Fabrik.fireEvent("fabrik.autocomplete.selected",[this,this.element.value])}else{Fabrik.fireEvent("fabrik.autocomplete.notselected",[this,this.element.value])}},closeMenu:function(){if(this.shown){this.shown=false;this.menu.fade("out");this.selected=-1;document.removeEvent("click",function(a){this.doTestMenuClose(a)}.bind(this))}},openMenu:function(){if(!this.shown){if(this.isMinTriggerlength()){this.shown=true;this.menu.setStyle("visibility","visible").fade("in");document.addEvent("click",function(a){this.doTestMenuClose(a)}.bind(this));this.selected=0;this.highlight()}}},doTestMenuClose:function(){if(!this.mouseinsde){this.closeMenu()}},isMinTriggerlength:function(){var a=this.getInputElement().get("value");return a.length>=this.options.minTriggerChars},getListMax:function(){if(typeOf(this.data)==="null"){return 0}return this.data.length>this.options.max?this.options.max:this.data.length},doWatchKeys:function(c){Fabrik.loader.stop(this.getInputElement());var a=this.getListMax();if(!this.shown){if(c.code.toInt()===13){c.stop()}if(c.code.toInt()===40&&document.activeElement===this.getInputElement()){this.openMenu()}}else{if(!this.isMinTriggerlength()){c.stop();this.closeMenu()}else{if(c.key==="enter"||c.key==="tab"){window.fireEvent("blur")}switch(c.code){case 40:if(!this.shown){this.openMenu()}if(this.selected+1=-1){this.selected--;this.highlight()}c.stop();break;case 13:case 9:c.stop();var b=new Event.Mock(this.getSelected(),"click");this.makeSelection(b);break;case 27:c.stop();this.matchedResult=false;this.closeMenu();break}}}},getSelected:function(){var b=this.menu.getElements("li").filter(function(a,c){return c===this.selected}.bind(this));return b[0]},highlight:function(){this.matchedResult=true;this.menu.getElements("li").each(function(a,b){if(b===this.selected){a.addClass("selected")}else{a.removeClass("selected")}}.bind(this))}});var FabCddAutocomplete=new Class({Extends:FbAutocomplete,search:function(g){if(!this.canSearch(g)){return}var d,b=this.defineSearchValue();if(b!==this.searchText&&b!==""){var a=document.id(this.options.observerid);if(typeOf(a)!=="null"){d=a.get("value")+"."+b}else{this.parent(g);return}this.positionMenu();if(this.cache[d]){this.populateMenu(this.cache[d]);this.openMenu()}else{if(this.ajax){this.closeMenu();this.ajax.cancel()}var c=document.id(this.options.observerid).get("value");if(typeOf(c)==="null"){c=Fabrik.blocks[this.options.formRef].elements.get(this.options.observerid).get("value")}var f={value:b,fabrik_cascade_ajax_update:1,v:c};this.ajax=this.makeAjax(this.options.url,f)}}this.searchText=b}}); \ No newline at end of file diff --git a/media/com_fabrik/js/autocomplete.js b/media/com_fabrik/js/autocomplete.js index 996309ae065..aba56349fd0 100644 --- a/media/com_fabrik/js/autocomplete.js +++ b/media/com_fabrik/js/autocomplete.js @@ -58,14 +58,38 @@ var FbAutocomplete = new Class({ } }.bind(this)); }, - - search: function (e) { + + /** + * Should the auto-complete start its ajax search + * @param e Event + * @return bool + */ + canSearch: function (e) { if (!this.isMinTriggerlength()) { - return; + return false; } if (e.key === 'tab' || e.key === 'enter') { e.stop(); this.closeMenu(); + return false; + } + }, + + /** + * Get the input text element's value and if empty set this.element.value to empty + * + * @return string input element text + */ + defineSearchValue: function () { + var v = this.getInputElement().get('value'); + if (v === '') { + this.element.value = ''; + } + return v; + }, + + search: function (e) { + if (!this.canSearch(e)) { return; } this.matchedResult = false; @@ -82,37 +106,51 @@ var FbAutocomplete = new Class({ this.populateMenu(this.cache[v]); this.openMenu(); } else { - Fabrik.loader.start(this.getInputElement()); if (this.ajax) { this.closeMenu(); this.ajax.cancel(); } - this.ajax = new Request({ - url: this.options.url, - data: { - value: v - }, - onRequest: function () { - Fabrik.loader.start(this.getInputElement()); - }.bind(this), - onCancel: function () { - Fabrik.loader.stop(this.getInputElement()); - this.ajax = null; - }.bind(this), - onSuccess: function (e) { - Fabrik.loader.stop(this.getInputElement()); - this.completeAjax(e, v); - }.bind(this) - }).send(); + + var data = {value: v}; + this.ajax = this.makeAjax(this.options.url, data); } } this.searchText = v; }, + + /** + * Build the ajax Request object and send it. + */ + makeAjax: function (url, data) { + return new Request({ + url: url, + data: data, + onRequest: function () { + Fabrik.loader.start(this.getInputElement()); + }.bind(this), + onCancel: function () { + Fabrik.loader.stop(this.getInputElement()); + //this.ajax = null; + }.bind(this), + onSuccess: function (e) { + this.completeAjax(e); + }.bind(this), + onComplete: function () { + Fabrik.loader.stop(this.getInputElement()); + }.bind(this), + onFailure: function () { + Fabrik.loader.stop(this.getInputElement()); + }.bind(this), + onException: function () { + Fabrik.loader.stop(this.getInputElement()); + }.bind(this) + }).send(); + }, - completeAjax: function (r, v) { + completeAjax: function (r) { + Fabrik.loader.stop(this.getInputElement()); r = JSON.decode(r); this.cache[v] = r; - Fabrik.loader.stop(this.getInputElement()); this.populateMenu(r); this.openMenu(); }, @@ -231,7 +269,11 @@ var FbAutocomplete = new Class({ return this.data.length > this.options.max ? this.options.max : this.data.length; }, + /** + * Observe the keydown event on the input field. Should stop the loader as we have a new search query + */ doWatchKeys: function (e) { + Fabrik.loader.stop(this.getInputElement()); var max = this.getListMax(); if (!this.shown) { if (e.code.toInt() === 13) { @@ -308,11 +350,11 @@ var FabCddAutocomplete = new Class({ Extends: FbAutocomplete, search: function (e) { - var key; - var v = this.getInputElement().get('value'); - if (v === '') { - this.element.value = ''; + if (!this.canSearch(e)) { + return; } + var key, + v = this.defineSearchValue(); if (v !== this.searchText && v !== '') { var observer = document.id(this.options.observerid); if (typeOf(observer) !== 'null') { @@ -326,38 +368,18 @@ var FabCddAutocomplete = new Class({ this.populateMenu(this.cache[key]); this.openMenu(); } else { - Fabrik.loader.start(this.getInputElement()); if (this.ajax) { this.closeMenu(); this.ajax.cancel(); } - // If you are observing a radio list then u need to get the Element js plugin value + // If you are observing a radio list then you need to get the Element js plugin value var obsValue = document.id(this.options.observerid).get('value'); if (typeOf(obsValue) === 'null') { - obsValue = Fabrik.blocks[this.options.formRef].formElements.get(this.options.observerid).get('value'); + obsValue = Fabrik.blocks[this.options.formRef].elements.get(this.options.observerid).get('value'); } - - this.ajax = new Request({ - method: 'post', - url : this.options.url, - data: { - value: v, - fabrik_cascade_ajax_update: 1, - v: obsValue - }, - - onSuccess: function (e) { - this.completeAjax(e); - }.bind(this), - - onError: function (text, error) { - console.log(text, error); - }, - onFailure: function (xhr) { - console.log(xhr); - } - }).send(); + var data = {value: v, fabrik_cascade_ajax_update: 1, v: obsValue}; + this.ajax = this.makeAjax(this.options.url, data); } } this.searchText = v;