af.selectbox.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. /**
  2. * @copyright: 2011 Intel
  3. * @description: This script will replace all drop downs with friendly select controls. Users can still interact
  4. * with the old drop down box as normal with javascript, and this will be reflected
  5. */
  6. (function($) {
  7. function updateOption(prop, oldValue, newValue) {
  8. if (newValue === true) {
  9. if (!this.getAttribute("multiple"))
  10. $.selectBox.updateMaskValue(this.parentNode.id, this.text, this.value);
  11. this.parentNode.value = this.value;
  12. }
  13. return newValue;
  14. }
  15. function updateIndex(prop, oldValue, newValue) {
  16. if (this.options[newValue]) {
  17. if (!this.getAttribute("multiple"))
  18. $.selectBox.updateMaskValue(this.linker, this.options[newValue].value, this.options[newValue].text);
  19. this.value = this.options[newValue].value;
  20. }
  21. return newValue;
  22. }
  23. function destroy(e) {
  24. var el = e.target;
  25. $(el.linker).remove();
  26. delete el.linker;
  27. e.stopPropagation();
  28. }
  29. $['selectBox'] = {
  30. scroller: null,
  31. currLinker: null,
  32. getOldSelects: function(elID) {
  33. if (!$.os.android || $.os.androidICS) return;
  34. if (!$.fn['scroller']) {
  35. alert("This library requires af.scroller");
  36. return;
  37. }
  38. var container = elID && document.getElementById(elID) ? document.getElementById(elID) : document;
  39. if (!container) {
  40. alert("Could not find container element for af.selectBox " + elID);
  41. return;
  42. }
  43. var sels = container.getElementsByTagName("select");
  44. var that = this;
  45. for (var i = 0; i < sels.length; i++) {
  46. var el = sels[i];
  47. el.style.display = "none";
  48. var fixer = $.create("div", {
  49. className: "afFakeSelect"
  50. });
  51. fixer.get(0).linker = sels[i];
  52. el.linker = fixer.get(0);
  53. fixer.insertAfter(sels[i]);
  54. el.watch("selectedIndex", updateIndex);
  55. for (var j = 0; j < el.options.length; j++) {
  56. var currInd = j;
  57. el.options[j].watch("selected", updateOption);
  58. if (el.options[j].selected)
  59. fixer.html(el.options[j].text);
  60. }
  61. $(el).one("destroy", destroy);
  62. }
  63. that.createHtml();
  64. },
  65. updateDropdown: function(el) {
  66. if (!el) return;
  67. for (var j = 0; j < el.options.length; j++) {
  68. if (el.options[j].selected) el.linker.innerHTML = el.options[j].text;
  69. }
  70. el = null;
  71. },
  72. initDropDown: function(el) {
  73. var that = this;
  74. if (el.disabled) return;
  75. if (!el || !el.options || el.options.length === 0) return;
  76. var htmlTemplate = "";
  77. var foundInd = 0;
  78. var $scr = $("#afSelectBoxfix");
  79. $scr.html("<ul></ul>");
  80. var $list = $scr.find("ul");
  81. for (var j = 0; j < el.options.length; j++) {
  82. var currInd = j;
  83. el.options[j].watch("selected", updateOption);
  84. var checked = (el.options[j].selected) ? "selected" : "";
  85. if (checked) foundInd = j + 1;
  86. var row = $.create("li", {
  87. html: el.options[j].text,
  88. className: checked
  89. });
  90. row.data("ind", j);
  91. $list.append(row);
  92. }
  93. $("#afModalMask").show();
  94. try {
  95. if (foundInd > 0 && el.getAttribute("multiple") != "multiple") {
  96. var scrollToPos = 0;
  97. var scrollThreshold = numOnly($list.find("li").computedStyle("height"));
  98. var theHeight = numOnly($("#afSelectBoxContainer").computedStyle("height"));
  99. if (foundInd * scrollThreshold >= theHeight) scrollToPos = (foundInd - 1) * -scrollThreshold;
  100. this.scroller.scrollTo({
  101. x: 0,
  102. y: scrollToPos
  103. });
  104. }
  105. } catch (e) {
  106. console.log("error init dropdown" + e);
  107. }
  108. var selClose = $("#afSelectClose").css("display") == "block" ? numOnly($("#afSelectClose").height()) : 0;
  109. $("#afSelectWrapper").height((numOnly($("#afSelectBoxContainer").height()) - selClose) + "px");
  110. },
  111. updateMaskValue: function(linker, value, val2) {
  112. $(linker).html(val2);
  113. },
  114. setDropDownValue: function(el, value) {
  115. if (!el) return;
  116. var $el = $(el);
  117. value = parseInt(value, 10);
  118. if (!el.getAttribute("multiple")) {
  119. el.selectedIndex = value;
  120. $el.find("option").prop("selected", false);
  121. $el.find("option:nth-child(" + (value + 1) + ")").prop("selected", true);
  122. this.scroller.scrollTo({
  123. x: 0,
  124. y: 0
  125. });
  126. this.hideDropDown();
  127. } else {
  128. //multi select
  129. // var myEl = $el.find("option:nth-child(" + (value + 1) + ")").get(0);
  130. var myList = $("#afSelectBoxfix li:nth-child(" + (value + 1) + ")");
  131. if (myList.hasClass("selected")) {
  132. myList.removeClass("selected");
  133. // myEl.selected = false;
  134. } else {
  135. myList.addClass("selected");
  136. // myEl.selected = true;
  137. }
  138. }
  139. $(el).trigger("change");
  140. el = null;
  141. },
  142. hideDropDown: function() {
  143. $("#afModalMask").hide();
  144. $("#afSelectBoxfix").html("");
  145. },
  146. createHtml: function() {
  147. var that = this;
  148. if (document.getElementById("afSelectBoxfix")) {
  149. return;
  150. }
  151. $(document).ready(function() {
  152. $(document).on("click", ".afFakeSelect", function(e) {
  153. if (this.linker.disabled)
  154. return;
  155. that.currLinker = this;
  156. if (this.linker.getAttribute("multiple") == "multiple")
  157. $("#afSelectClose").show();
  158. else
  159. $("#afSelectClose").hide();
  160. that.initDropDown(this.linker);
  161. });
  162. var container = $.create("div", {
  163. id: "afSelectBoxContainer"
  164. });
  165. var modalDiv = $.create("div", {
  166. id: "afSelectBoxfix"
  167. });
  168. var modalWrapper = $.create("div", {
  169. id: "afSelectWrapper"
  170. });
  171. modalWrapper.css("position", "relative");
  172. modalWrapper.append(modalDiv);
  173. var closeDiv = $.create("div", {
  174. id: "afSelectClose",
  175. html: "<a id='afSelectDone'>Done</a> <a id='afSelectCancel'>Cancel</a>"
  176. });
  177. var modalMask = $.create("div", {
  178. id:"afModalMask"
  179. });
  180. var $afui = $("#afui");
  181. container.prepend(closeDiv).append(modalWrapper);
  182. modalMask.append(container);
  183. if ($afui.length > 0) $afui.append(modalMask);
  184. else document.body.appendChild(modalMask.get(0));
  185. that.scroller = $.query("#afSelectBoxfix").scroller({
  186. scroller: false,
  187. verticalScroll: true,
  188. vScrollCSS: "jqselectscrollBarV"
  189. });
  190. $("#afModalMask").on("click",function(e){
  191. var $e=$(e.target);
  192. if($e.closest("#afSelectBoxContainer").length===0)
  193. that.hideDropDown();
  194. })
  195. $("#afSelectBoxfix").on("click", "li", function(e) {
  196. var $el = $(e.target);
  197. that.setDropDownValue(that.currLinker.linker, $el.data("ind"));
  198. });
  199. $("#afSelectBoxContainer").on("click", "a", function(e) {
  200. if (e.target.id == "afSelectCancel")
  201. return that.hideDropDown();
  202. var $sel = $(that.currLinker.linker);
  203. $sel.find("option").prop("selected", false);
  204. $("#afSelectBoxfix li").each(function(el) {
  205. var $el = $(this);
  206. if ($el.hasClass("selected")) {
  207. var ind = parseInt($el.data("ind"), 10);
  208. $sel.find("option:nth-child(" + (ind + 1) + ")").prop("selected", true);
  209. that.currLinker.innerHTML = $el.html();
  210. }
  211. });
  212. that.hideDropDown();
  213. e.stopPropagation();
  214. e.preventDefault();
  215. return false;
  216. });
  217. });
  218. }
  219. };
  220. //The following is based off Eli Grey's shim
  221. //https://gist.github.com/384583
  222. //We use HTMLElement to not cause problems with other objects
  223. if (!HTMLElement.prototype.watch) {
  224. HTMLElement.prototype.watch = function(prop, handler) {
  225. var oldval = this[prop],
  226. newval = oldval,
  227. getter = function() {
  228. return newval;
  229. },
  230. setter = function(val) {
  231. oldval = newval;
  232. newval = handler.call(this, prop, oldval, val);
  233. return newval;
  234. };
  235. if (delete this[prop]) { // can't watch constants
  236. if (HTMLElement.defineProperty) { // ECMAScript 5
  237. HTMLElement.defineProperty(this, prop, {
  238. get: getter,
  239. set: setter,
  240. enumerable: false,
  241. configurable: true
  242. });
  243. } else if (HTMLElement.prototype.__defineGetter__ && HTMLElement.prototype.__defineSetter__) { // legacy
  244. HTMLElement.prototype.__defineGetter__.call(this, prop, getter);
  245. HTMLElement.prototype.__defineSetter__.call(this, prop, setter);
  246. }
  247. }
  248. };
  249. }
  250. if (!HTMLElement.prototype.unwatch) {
  251. HTMLElement.prototype.unwatch = function(prop) {
  252. var val = this[prop];
  253. delete this[prop]; // remove accessors
  254. this[prop] = val;
  255. };
  256. }
  257. })(af);