1 2WS.Namespace.Create('NovAxis.Select', (function () 3{ 4 /** 5 @class Select 6 @namespace NovAxis 7 @constructor 8 @param {jQuery} [select] A jQuery object containing a select html element. 9 @param {Array<String>} [classes] Array of class names to apply to the control. 10 @param {Integer} [width] The width of the control. Automatic if omitted. 11 @param {Integer} [height] The height of the control. Automatic if omitted. 12 @param {Integer} [maxHeight] The maximum height of the selection menu. Automatic if omitted. 13 **/ 14 var Class = function (select, classes, width, height, maxHeight) 15 { 16 if (!select || select.length == 0) throw "Select control cannot be null."; 17 18 /** 19 Fired when the value is changed. 20 21 @event change 22 **/ 23 WS.EventObject.call(this, ['change', 'action']); 24 25 var elements = CreateControl(select); 26 this.element = elements.eq(0); 27 this.list = elements.eq(1); 28 this.listContent = this.list.find('.naSelectListContent'); 29 this.listBottom = this.list.find('.naSelectListBottom'); 30 if (width) this.element.css("width", width + "px"); 31 if (height) this.element.css("height", height + "px"); 32 if (classes && classes.length >
32 0) elements.addClass(classes.join(" ")); 33 this.maxHeight = maxHeight || 500; 34 35 var me = this; 36 this.scrollBar = null; 37 38 this.select = select; 39 this._internal = {}; 40 this._internal.value = null; 41 this._internal.text = null; 42 this._internal.initialized = false; 43 this._internal.disabled = false; 44 45 value = this.select.find("option[selected]").attr("value") || null; 46 if (value == null) value = this.list.find(".naSelectOption").eq(0).attr("data") || null; 47 if (value != null) SelectValue.call(this, value); 48 49 this.data = this.select.find("option[selected]").data(); 50 51 AddEventHandler.apply(this); 52 53 this.select.after(this.element); 54 this.select.detach(); 55 $("body").append(this.list); 56 }; 57 58 WS.Exts.Inherits(Class, WS.EventObject); 59 60 // Private Method(s) 61 var CreateControl = function (select) 62 { 63 var Html = []; 64 Html.push("<div class=\"naSelect\">"); 65 Html.push("<div class=\"naSelectBody\">"); 66 Html.push("<div class=\"naSelectValue\"></div>") 67 Html.push("<div class=\"naSelectOpen\"></div>") 68 Html.push("</div>"); 69 Html.push("</div>"); 70 71 Html.push("<div class=\"naSelectList\">"); 72 Html.push("<div class=\"naSelectListContent\">"); 73 74 select.find("option").each(function () { 75 var option = $(this); 76 var disabled = false; 77 var actionName = option.data("optionaction"); 78 if (typeof actionName === "string" && actionName !== "") 79 { 80 Html.push(CreateActionOption(option.text(), actionName, option.attr("style"), option.data(), disabled)); 81 } else { 82 if (typeof option.attr("disabled") !== typeof undefined && option.attr("disabled") !== false) disabled = true; 83 Html.push(CreateOption(option.text(), option.attr("value"), option.attr("style"), option.data(), disabled)); 84 } 85 }); 86 87 Html.push("</div>"); 88 Html.push("<div class=\"naSelectListBottom\"></div>"); 89 Html.push("</div>"); 90 91 return $(Html.join("")); 92 }; 93 94 var CreateOption = function (text, value, style, data, disabled) 95 { 96 if (typeof disabled == "undefined" || disabled == "") disabled = false; 97 98 value = value || ""; 99 style = GetStyleString(style); 100 101 var dataAttr = GetDataAttributes(data); 102 return "<div class=\"naSelectOption " + (disabled ? "optionDisabled" : "") + "\"" + style + " data=\"" + value + "\"" + dataAttr + ">" + text + "</div>"; 103 104 }; 105 106 var CreateActionOption = function(text, actionName, style, data, disabled) 107 { 108 if (typeof disabled == "undefined" || disabled == "") disabled = false; 109 if (typeof actionName !== "string" || actionName.length === 0) 110 throw new Error("Action option must have a name."); 111 112 data = data || {}; 113 data.optionaction = actionName; 114 115 style = GetStyleString(style); 116 117 return "<div class=\"naSelectActionOption" + (disabled ? " optionDisabled" : "") + "\"" + style + GetDataAttributes(data) + ">" + text + "</div>"; 118 }; 119 120 var CreateSeparator = function (text, style, data) 121 { 122 style = GetStyleString(style); 123 124 var data_add = ""; 125 for (var key in data) { 126 data_add += " data-" + key + "=\"" + data[key] + "\""; 127 } 128 return ( 129 "<div class=\"naSelectSeparator\"" + style + data_add + ">" + 130 "<div class=\"naSelectSeparatorText\">" + text + "</div>" + 131 "</div>" 132 ); 133 }; 134 135 var GetDataAttributes = function (data) { 136 data = (typeof data === 'object') ? data : {}; 137 var dataStr = ""; 138 for (var key in data) { 139 dataStr += " data-" + key + "=\"" + data[key] + "\""; 140 } 141 return dataStr; 142 }; 143 144 var GetStyleString = function(style) 145 { 146 return style ? " style=\"" + style + "\"" : ""; 147 }; 148 149 var ShowList = function () 150 { 151 if (!this.scrollBar) this.scrollBar = WS.ScrollBar.init(this.listContent.get(0)); 152 153 var offset = this.element.offset(); 154 var width = (getComputedStyle ? parseFloat(getComputedStyle(this.element[0]).width) : this.element.width()); 155 var height = (getComputedStyle ? parseFloat(getComputedStyle(this.element[0]).height) : this.element.height()); 156 this.list.css({ left: offset.left + "px", top: (offset.top + height) + "px", "min-width": width + "px", maxHeight: Math.min(this.maxHeight, $(window).height() - (offset.top - $(window).scrollTop()) - height - 20) + "px" }).addClass("naSelectActive"); 157 this.scrollBar.scrollTo(0); 158 this.element.addClass("naSelectActive"); 159 var _me = this; 160 161 //add keydown listener 162 $(window).bind('keydown', function (event) 163 { 164 event.stopPropagation(); 165 event.preventDefault(); 166 switch (event.keyCode) 167 { 168 case 13: 169 170 _me.list.find('.hover').click(); 171 break; 172 173 case 38: 174 175 var element = _me.list.find('.hover'); 176 SelectByArrow.call(_me, element, true); 177 break; 178 179 case 40: 180 181 var element = _me.list.find('.hover'); 182 SelectByArrow.call(_me, element); 183 break; 184 185 default: 186 187 SearchValue.call(_me, String.fromCharCode(event.keyCode));
188 break; 189 } 190 }); 191 }; 192 193 var HideList = function () 194 { 195 this.list.removeClass("naSelectActive").removeAttr("style"); 196 197 //unselect hover on close 198 this.list.find('.hover').removeClass('hover'); 199 this.element.removeClass("naSelectActive"); 200 201 //remove keydown listener 202 $(window).unbind('keydown'); 203 }; 204 205 /* 206 Remove the hover class on cursor move in list to avoid double highlight element 207 */ 208 var BindListMouseMove = function () { 209 this.list.off("mousemove").on('mousemove', function () { 210 $(this).find('.hover').removeClass('hover'); 211 }); 212 }; 213 214 /* 215 Handle navigation in list by arrow key 216 element : starting html object element 217 isUp : true if the up arrow is selected 218 */ 219 var SelectByArrow = function (element, isUp) 220 { 221 if (element.length == 0) element = this.list.find('.naSelectOption').eq(0).addClass('hover'); 222 var newElement = element[isUp ? "prev" : "next"](".naSelectOption"); 223 if (newElement.length > 0) 224 { 225 element.removeClass("hover"); 226 newElement.addClass("hover"); 227 MoveList.call(this, newElement, isUp); 228 BindListMouseMove.call(this); 229 } 230 }; 231 232 /* 233 Position list handler. If list height is smaller than the container, the position stay the same 234 element - selected option in list 235 isUp - true if up arrow is press 236 */ 237 var MoveList = function (element, isUp) 238 { 239 var position = element.position().top; 240 if (isUp) 241 { 242 if (position < 0) this.scrollBar.scrollTo(Math.round(this.listContent.scrollTop() + position)); 243 } 244 245 else 246 { 247 var listHeight = this.listContent.height(); 248 var elementHeight = element.innerHeight(); 249 if (position > listHeight - elementHeight) this.scrollBar.scrollTo(Math.round(this.listContent.scrollTop() + position - listHeight + elementHeight)); 250 } 251 }; 252 253 /* 254 Look for the first option starting by the selected key 255 value - the selected character 256 **/ 257 var SearchValue = function (value) 258 { 259 var option = this.list.find('.naSelectOption'); 260 var options = []; 261 for (var i = 0; i < option.length; i++) 262 { 263 if (option.eq(i).html().toLowerCase().indexOf(value.toLowerCase()) === 0) options.push(option.eq(i)); 264 } 265 266 var selectedIndex = -1; 267 for (var i = 0; i < options.length && selectedIndex == -1; i++) 268 { 269 if (options[i].hasClass("hover")) selectedIndex = i; 270 } 271 272 if (++selectedIndex == options.length) selectedIndex = 0; 273 274 //scroll list to value and hightlight the right option 275 if (options.length > 0) 276 { 277 this.listContent.find('.hover').removeClass('hover'); 278 this.scrollBar.scrollTo(Math.round(this.listContent.scrollTop() + options[selectedIndex].position().top - (this.listContent.height() / 2))); 279 options[selectedIndex].addClass('hover'); 280 BindListMouseMove.call(this); 281 } 282 }; 283 284 var SelectValue = function (value) 285 { 286 if (value != this._internal.value) 287 { 288 var option = this.list.find('.naSelectOption[data="' + value + '"]'); 289 if (option.length > 0) 290 { 291 this._internal.value = value; 292 this._internal.text = option.eq(0).text(); 293 this.list.find(".naSelectOption").removeClass("naSelectOptionSelected"); 294 option.eq(0).addClass("naSelectOptionSelected"); 295 this.element.find(".naSelectValue").removeClass("optionDisabled").text(option.eq(0).text()); 296 if (option.eq(0).hasClass("optionDisabled")) this.element.find(".naSelectValue").addClass("optionDisabled"); 297 if (this._internal.initialized) this.RaiseEvent("change", value, option.eq(0).text()); 298 this._internal.initialized = true; 299 } 300 } 301 }; 302 303 var SelectAction = function(actionName) 304 { 305 if (typeof actionName === "string" && this._internal.initialized) 306 { 307 this.RaiseEvent("action", actionName); 308 } 309 }; 310 311 var AddEventHandler = function () 312 { 313 var me = this; 314 me._internal.events = {}; 315 316 me._internal.events.clickHandler = function (event) 317 { 318 var target = $(this); 319 if (target.hasClass("naSelectOption")) SelectValue.call(me, target.attr("data")); 320 if (target.hasClass("naSelectActionOption")) SelectAction.call(me, target.data("optionaction")); 321 322 if (event.type == "click" || !$.contains(me.list[0], event.target)) 323 { 324 HideList.call(me); 325 $(document).off("mousedown", me._internal.events.clickHandler); 326 event.stopPropagation(); 327 } 328 }; 329 330 this.element.find(".naSelectBody").on("click", function (event) { 331 if (!me._internal.disabled) 332 { 333 ShowList.call(me); 334 $(document).on("mousedown", me._internal.events.clickHandler); 335 event.stopPropagation(); 336 } 337 }); 338 this.list.find(".naSelectOption, .naSelectActionOption").on("click", me._internal.events.clickHandler); 339 }; 340 341 // Public Method(s) 342 (function (Methods) 343 { 344 /** 345 Add an option. 346 347 @method Add 348 **/ 349 Methods.Add = function (text, value) 350 { 351 var option = $(CreateOption(text, value)); 352 353 option.on("click", this._internal.events.clickHandler); 354 355 this.listContent.append(option); 356 if (this._internal.value == null) SelectValue.call(this, value); 357 }; 358 359 /** 360 Add an action option. 361 362 @method AddAction 363 **/ 364 Methods.AddAction = function (text, actionName, fixed) 365 { 366 var actionOption = $(CreateActionOption(text, actionName)); 367 368 actionOption.on("click", this._internal.events.clickHandler); 369 370 if (fixed) { 371 this.listBottom.append(actionOption); 372 } else { 373 this.listContent.append(actionOption); 374 } 375 }; 376 377 /** 378 Add a separator. 379 380 @method AddSeparator 381 **/ 382 Methods.AddSeparator = function(text) 383 { 384 var separator = $(CreateSeparator(text)); 385 this.listContent.append(separator); 386 return separator; 387 }; 388 389 /** 390 Remove an option. 391 392 @method Remove 393 **/ 394 Methods.Remove = function (value) 395 { 396 this.list.find('.naSelectOption[data="' + value + '"]').remove(); 397 if (value == this._internal.value) 398 { 399 if (this.list.find(".naSelectOption").length > 0) 400 SelectValue.call(this, this.list.find(".naSelectOption").eq(0).attr("data")); 401 else 402 this.Clear(); 403 } 404 }; 405 406 /** 407 Get the options list 408 409 @method GetOptions 410 **/ 411 Methods.GetOptions = function () 412 { 413 var Options = []; 414 for (var i = 0; i< this.list.find(".naSelectOption").length; i++) 415 { 416 Options.push(this.list.find(".naSelectOption").eq(i).attr("data")); 417 } 418 419 return Options; 420 }; 421 422 /** 423 Get the data 424 425 @method GetDataByValue 426 **/ 427 Methods.GetDataByValue = function (value) { 428 return this.list.find(".naSelectOption[data=" + value + "]").data(); 429 }; 430 431 /** 432 Clear all option. 433 434 @method Clear 435 **/ 436 Methods.Clear = function () { 437 this.list.find('.naSelectOption, .naSelectSeparator, .naSelectActionOption').remove(); 438 this._internal.value = null; 439 this._internal.text = null; 440 this._internal.initialized = false; 441 }; 442 443 /** 444 Get the selected value. 445 446 @method GetValue 447 **/ 448 Methods.GetValue = function () 449 { 450 return this._internal.value; 451 }; 452 453 /** 454 Set the selected value. 455 456 @method SetValue 457 **/ 458 Methods.SetValue = function (value) 459 { 460 this._internal.initialized = false; 461 SelectValue.call(this, value); 462 this._internal.initialized = true; 463 }; 464 465 /** 466 Set invalid style. 467 468 @method SetInvalid 469 **/ 470 Methods.SetInvalid = function () { 471 var SelectorBox = this.element.find(".naSelectBody"); 472 SelectorBox.addClass("naSelectInvalid"); 473 SelectorBox.off("mouseenter").on("mouseenter", function () { SelectorBox.removeClass("naSelectInvalid") }); 474 }; 475 476 /** 477 Remove invalid style. 478 479 @method RemoveInvalid 480 **/ 481 Methods.RemoveInvalid = function () { 482 var SelectorBox = this.element.find(".naSelectBody"); 483 SelectorBox.removeClass("naSelectInvalid"); 484 SelectorBox.off("mouseenter"); 485 }; 486 487 /** 488 Get the selected text. 489 490 @method GetText 491 **/ 492 Methods.GetText = function () 493 { 494 return this._internal.text; 495 }; 496 497 /** 498 Disable the control. 499 500 @method Disable 501 **/ 502 Methods.Disable = function () 503 { 504 this.element.addClass("naSelectDisabled"); 505 this._internal.disabled = true; 506 }; 507 508 /** 509 Enable the control. 510 511 @method Enable 512 **/ 513 Methods.Enable = function () 514 { 515 this.element.removeClass("naSelectDisabled"); 516 this._internal.disabled = false; 517 }; 518 519 /** 520 Rebind the control. 521 522 @method Rebind 523 **/ 524 Methods.Rebind = function (select) { 525 this.Clear(); 526 var me = this; 527 select.find("option").each(function () { me.Add($(this).text(), $(this).attr("value")) }); 528 529 value = select.find("option[selected]").attr("value") || null; 530 if (value != null) SelectValue.call(this, value); 531 }; 532 533 /** 534 Destroy the control. 535 536 @method Destroy 537 **/ 538 Methods.Destroy = function () 539 { 540 this.element.after(this.select); 541 this.element.remove(); 542 this.list.remove(); 543 this.element = null; 544 this.select = null; 545 this._internal = null; 546 }; 547 548 })(Class.prototype); 549 550 return Class; 551})());
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.