/** * @copyright: 2011 Intel * @description: This script will replace all drop downs with friendly select controls. Users can still interact * with the old drop down box as normal with javascript, and this will be reflected */ (function($) { function updateOption(prop, oldValue, newValue) { if (newValue === true) { if (!this.getAttribute("multiple")) $.selectBox.updateMaskValue(this.parentNode.id, this.text, this.value); this.parentNode.value = this.value; } return newValue; } function updateIndex(prop, oldValue, newValue) { if (this.options[newValue]) { if (!this.getAttribute("multiple")) $.selectBox.updateMaskValue(this.linker, this.options[newValue].value, this.options[newValue].text); this.value = this.options[newValue].value; } return newValue; } function destroy(e) { var el = e.target; $(el.linker).remove(); delete el.linker; e.stopPropagation(); } $['selectBox'] = { scroller: null, currLinker: null, getOldSelects: function(elID) { if (!$.os.android || $.os.androidICS) return; if (!$.fn['scroller']) { alert("This library requires af.scroller"); return; } var container = elID && document.getElementById(elID) ? document.getElementById(elID) : document; if (!container) { alert("Could not find container element for af.selectBox " + elID); return; } var sels = container.getElementsByTagName("select"); var that = this; for (var i = 0; i < sels.length; i++) { var el = sels[i]; el.style.display = "none"; var fixer = $.create("div", { className: "afFakeSelect" }); fixer.get(0).linker = sels[i]; el.linker = fixer.get(0); fixer.insertAfter(sels[i]); el.watch("selectedIndex", updateIndex); for (var j = 0; j < el.options.length; j++) { var currInd = j; el.options[j].watch("selected", updateOption); if (el.options[j].selected) fixer.html(el.options[j].text); } $(el).one("destroy", destroy); } that.createHtml(); }, updateDropdown: function(el) { if (!el) return; for (var j = 0; j < el.options.length; j++) { if (el.options[j].selected) el.linker.innerHTML = el.options[j].text; } el = null; }, initDropDown: function(el) { var that = this; if (el.disabled) return; if (!el || !el.options || el.options.length === 0) return; var htmlTemplate = ""; var foundInd = 0; var $scr = $("#afSelectBoxfix"); $scr.html(""); var $list = $scr.find("ul"); for (var j = 0; j < el.options.length; j++) { var currInd = j; el.options[j].watch("selected", updateOption); var checked = (el.options[j].selected) ? "selected" : ""; if (checked) foundInd = j + 1; var row = $.create("li", { html: el.options[j].text, className: checked }); row.data("ind", j); $list.append(row); } $("#afModalMask").show(); try { if (foundInd > 0 && el.getAttribute("multiple") != "multiple") { var scrollToPos = 0; var scrollThreshold = numOnly($list.find("li").computedStyle("height")); var theHeight = numOnly($("#afSelectBoxContainer").computedStyle("height")); if (foundInd * scrollThreshold >= theHeight) scrollToPos = (foundInd - 1) * -scrollThreshold; this.scroller.scrollTo({ x: 0, y: scrollToPos }); } } catch (e) { console.log("error init dropdown" + e); } var selClose = $("#afSelectClose").css("display") == "block" ? numOnly($("#afSelectClose").height()) : 0; $("#afSelectWrapper").height((numOnly($("#afSelectBoxContainer").height()) - selClose) + "px"); }, updateMaskValue: function(linker, value, val2) { $(linker).html(val2); }, setDropDownValue: function(el, value) { if (!el) return; var $el = $(el); value = parseInt(value, 10); if (!el.getAttribute("multiple")) { el.selectedIndex = value; $el.find("option").prop("selected", false); $el.find("option:nth-child(" + (value + 1) + ")").prop("selected", true); this.scroller.scrollTo({ x: 0, y: 0 }); this.hideDropDown(); } else { //multi select // var myEl = $el.find("option:nth-child(" + (value + 1) + ")").get(0); var myList = $("#afSelectBoxfix li:nth-child(" + (value + 1) + ")"); if (myList.hasClass("selected")) { myList.removeClass("selected"); // myEl.selected = false; } else { myList.addClass("selected"); // myEl.selected = true; } } $(el).trigger("change"); el = null; }, hideDropDown: function() { $("#afModalMask").hide(); $("#afSelectBoxfix").html(""); }, createHtml: function() { var that = this; if (document.getElementById("afSelectBoxfix")) { return; } $(document).ready(function() { $(document).on("click", ".afFakeSelect", function(e) { if (this.linker.disabled) return; that.currLinker = this; if (this.linker.getAttribute("multiple") == "multiple") $("#afSelectClose").show(); else $("#afSelectClose").hide(); that.initDropDown(this.linker); }); var container = $.create("div", { id: "afSelectBoxContainer" }); var modalDiv = $.create("div", { id: "afSelectBoxfix" }); var modalWrapper = $.create("div", { id: "afSelectWrapper" }); modalWrapper.css("position", "relative"); modalWrapper.append(modalDiv); var closeDiv = $.create("div", { id: "afSelectClose", html: "Done Cancel" }); var modalMask = $.create("div", { id:"afModalMask" }); var $afui = $("#afui"); container.prepend(closeDiv).append(modalWrapper); modalMask.append(container); if ($afui.length > 0) $afui.append(modalMask); else document.body.appendChild(modalMask.get(0)); that.scroller = $.query("#afSelectBoxfix").scroller({ scroller: false, verticalScroll: true, vScrollCSS: "jqselectscrollBarV" }); $("#afModalMask").on("click",function(e){ var $e=$(e.target); if($e.closest("#afSelectBoxContainer").length===0) that.hideDropDown(); }) $("#afSelectBoxfix").on("click", "li", function(e) { var $el = $(e.target); that.setDropDownValue(that.currLinker.linker, $el.data("ind")); }); $("#afSelectBoxContainer").on("click", "a", function(e) { if (e.target.id == "afSelectCancel") return that.hideDropDown(); var $sel = $(that.currLinker.linker); $sel.find("option").prop("selected", false); $("#afSelectBoxfix li").each(function(el) { var $el = $(this); if ($el.hasClass("selected")) { var ind = parseInt($el.data("ind"), 10); $sel.find("option:nth-child(" + (ind + 1) + ")").prop("selected", true); that.currLinker.innerHTML = $el.html(); } }); that.hideDropDown(); e.stopPropagation(); e.preventDefault(); return false; }); }); } }; //The following is based off Eli Grey's shim //https://gist.github.com/384583 //We use HTMLElement to not cause problems with other objects if (!HTMLElement.prototype.watch) { HTMLElement.prototype.watch = function(prop, handler) { var oldval = this[prop], newval = oldval, getter = function() { return newval; }, setter = function(val) { oldval = newval; newval = handler.call(this, prop, oldval, val); return newval; }; if (delete this[prop]) { // can't watch constants if (HTMLElement.defineProperty) { // ECMAScript 5 HTMLElement.defineProperty(this, prop, { get: getter, set: setter, enumerable: false, configurable: true }); } else if (HTMLElement.prototype.__defineGetter__ && HTMLElement.prototype.__defineSetter__) { // legacy HTMLElement.prototype.__defineGetter__.call(this, prop, getter); HTMLElement.prototype.__defineSetter__.call(this, prop, setter); } } }; } if (!HTMLElement.prototype.unwatch) { HTMLElement.prototype.unwatch = function(prop) { var val = this[prop]; delete this[prop]; // remove accessors this[prop] = val; }; } })(af);