1/* 2 3Uniform v1.8.0+f 4Copyright © 2009 Josh Pyles / Pixelmatrix Design LLC 5http://pixelmatrixdesign.com 6 7Requires jQuery 1.3 or newer 8 9Much thanks to Thomas Reynolds and Buck Wilson for their help and advice on 10this. 11 12Disabling text selection is made possible by Mathias Bynens 13<http://mathiasbynens.be/> and his noSelect plugin. 14<http://github.com/mathiasbynens/noSelect-jQuery-Plugin>. 15 16Also, thanks to David Kaneda and Eugene Bond for their contributions to the 17plugin. 18 19This version (+f) is from fidian's forked repository until the changes can 20get merged upstream. See https://github.com/fidian/uniform 21 22License: 23MIT License - http://www.opensource.org/licenses/mit-license.php 24 25Enjoy! 26 27*/ 28/*global jQuery, window, document*/ 29 30(function ($, undef) { 31 "use strict"; 32 33 $.uniform = { 34 // Default options that can be overridden globally or when uniformed 35 // globally: $.uniform.defaults.fileButtonHtml = "Pick A File"; 36 // on uniform: $('input').uniform({fileButtonHtml: "Pick a File"}); 37 defaults: { 38 activeClass: "active", 39 autoHide: true, 40 buttonClass: "button", 41 checkboxClass: "checker", 42 checkedClass: "checked", 43 disabledClass: "disabled", 44 fileButtonClass: "action", 45 fileButtonHtml: "Choose File", 46 fileClass: "uploader", 47 fileDefaultHtml: "No file selected", 48 filenameClass: "filename", 49 focusClass: "focus", 50 hoverClass: "hover", 51 idPrefix: "uniform", 52 radioClass: "radio", 53 resetDefaultHtml: "Reset", 54 resetSelector: false, // We'll use our own function when you don't specify one 55 selectAutoWidth: false, 56 selectClass: "selector", 57 submitDefaultHtml: "Submit", // Only text allowed 58 useID: true 59 }, 60 61 // All uniformed elements - DOM objects 62 elements: [] 63 }; 64 65 // Change text into HTML 66 function htmlify(text) { 67 if (!text) { 68 return ""; 69 } 70 return $('<span />').text(text).html(); 71 } 72 73 // For backwards compatibility with older jQuery libraries 74 // Also adds our namespace in one consistent location and shrinks the 75 // resulting minified code 76 function bindMany($el, events) { 77 var name, namespaced; 78 79 for (name in events) { 80 if (events.hasOwnProperty(name)) { 81 namespaced = name.replace(/ |$/g, ".uniform"); 82 $el.bind(name, events[name]); 83 } 84 } 85 } 86 87 // Test if the element is a multiselect 88 function isMultiselect($el) { 89 var elSize; 90 91 if ($el[0].multiple) { 92 return true; 93 } 94 95 elSize = $el.attr("size"); 96 97 if (elSize === undef || elSize <= 1) { 98 return false; 99 } 100 101 return true; 102 } 103 104 // Update the filename tag based on $el's value 105 function setFilename($el, $filenameTag, options) { 106 var filename = $el.val(); 107 108 if (filename === "") { 109 filename = options.fileDefaultHtml; 110 } else { 111 filename = filename.split(/[\/\\]+/); 112 filename = filename[(filename.length - 1)]; 113 } 114 115 $filenameTag.text(filename); 116 } 117 118 function classClearStandard($el, options) { 119 $el.removeClass(options.hoverClass + " " + options.focusClass + " " + options.activeClass); 120 } 121 122 function classToggle($el, className, enabled) { 123 if (enabled) { 124 $el.addClass(className); 125 } else { 126 $el.removeClass(className); 127 } 128 } 129 130 function classToggleChecked($tag, $el, options) { 131 var isChecked = $el.is(":checked"); 132 133 if ($el.prop) { 134 // jQuery 1.6+ 135 $el.prop("checked", isChecked); 136 } else { 137 // jQuery 1.5 and below 138 if (isChecked) { 139 $el.attr("checked", "checked"); 140 } else { 141 $el.removeAttr("checked"); 142 } 143 } 144 145 classToggle($tag, options.checkedClass, isChecked); 146 } 147 148 function classToggleDisabled($tag, $el, options) { 149 classToggle($tag, options.disabledClass, $el.is(":disabled")); 150 } 151 152 function divSpanWrap($el, $container, method) { 153 switch (method) { 154 case "after": 155 $el.after($container); 156 return $el.next(); 157 case "before": 158 $el.before($container); 159 return $el.prev(); 160 case "wrap": 161 $el.wrap($container); 162 return $el.parent(); 163 } 164 return null; 165 } 166 function divSpan($el, options, divSpanConfig) { 167 var $div, $span; 168 169 if (!divSpanConfig) { 170 divSpanConfig = {}; 171 } 172 173 divSpanConfig = $.extend({ 174 bind: {}, 175 css: null, 176 divClass: null, 177 divWrap: "wrap", 178 spanClass: null, 179 spanHtml: null, 180 spanWrap: "wrap" 181 }, divSpanConfig); 182
183 $div = $('<div />'); 184 $span = $('<span />'); 185 186 if (options.autoHide && !($el.is(':visible'))) { 187 $div.hide(); 188 } 189 190 if (divSpanConfig.divClass) { 191 $div.addClass(divSpanConfig.divClass); 192 } 193 194 if (divSpanConfig.spanClass) { 195 $span.addClass(divSpanConfig.spanClass); 196 } 197 198 if (options.useID && $el.attr('id')) { 199 $div.attr('id', options.idPrefix + '-' + $el.attr('id')); 200 } 201 202 if (divSpanConfig.spanHtml) { 203 $span.html(divSpanConfig.spanHtml); 204 } 205 206 $div = divSpanWrap($el, $div, divSpanConfig.divWrap); 207 $span = divSpanWrap($el, $span, divSpanConfig.spanWrap); 208 209 if (divSpanConfig.css) { 210 $el.css(divSpanConfig.css); 211 } 212 213 classToggleDisabled($div, $el, options); 214 215 return { 216 div: $div, 217 span: $span 218 }; 219 } 220 221 var allowStyling = true, 222 uniformHandlers = [ 223 { 224 // Buttons 225 match: function ($el) { 226 return $el.is("button, :submit, :reset, a, input[type='button']"); 227 }, 228 apply: function ($el, options) { 229 var $div, spanHtml, ds; 230 231 spanHtml = options.submitDefaultHtml; 232 233 if ($el.is(":reset")) { 234 spanHtml = options.resetDefaultHtml; 235 } 236 237 if ($el.is("a, button")) { 238 spanHtml = $el.html() || spanHtml; 239 } else if ($el.is(":submit, :reset, input[type=button]")) { 240 spanHtml = htmlify($el.attr("value")) || spanHtml; 241 } 242 243 ds = divSpan($el, options, { 244 css: { display: "none" }, 245 divClass: options.buttonClass, 246 spanHtml: spanHtml 247 }); 248 $div = ds.div; 249 250 bindMany($div, { 251 "mouseenter": function () { 252 $div.addClass(options.hoverClass); 253 }, 254 "mouseleave": function () { 255 $div.removeClass(options.hoverClass); 256 $div.removeClass(options.activeClass); 257 }, 258 "mousedown touchbegin": function () { 259 $div.addClass(options.activeClass); 260 }, 261 "mouseup touchend": function () { 262 $div.removeClass(options.activeClass); 263 }, 264 "click touchend": function (e) { 265 var ev; 266 267 if ($(e.target).is("span, div")) { 268 if ($el[0].dispatchEvent) { 269 ev = document.createEvent("MouseEvents"); 270 ev.initEvent("click", true, true); 271 $el[0].dispatchEvent(ev); 272 } else { 273 $el.click(); 274 } 275 } 276 } 277 }); 278 bindMany($el, { 279 "focus": function () { 280 $div.addClass(options.focusClass); 281 }, 282 "blur": function () { 283 $div.removeClass(options.focusClass); 284 } 285 }); 286 $.uniform.noSelect($div); 287 return { 288 remove: function () { 289 return $el.unwrap().unwrap(); 290 }, 291 update: function () { 292 classClearStandard($div, options); 293 classToggleDisabled($div, $el, options); 294 } 295 }; 296 } 297 }, 298 { 299 // Checkboxes 300 match: function ($el) { 301 return $el.is(":checkbox"); 302 }, 303 apply: function ($el, options) { 304 var ds, $div, $span; 305 306 ds = divSpan($el, options, { 307 css: { opacity: 0 }, 308 divClass: options.checkboxClass 309 }); 310 $div = ds.div; 311 $span = ds.span; 312 313 // Add focus classes, toggling, active, etc. 314 bindMany($el, { 315 "focus": function () { 316 $div.addClass(options.focusClass); 317 }, 318 "blur": function () { 319 $div.removeClass(options.focusClass); 320 }, 321 "click touchend": function () { 322 classToggleChecked($span, $el, options); 323 }, 324 "mousedown touchbegin": function () { 325 $div.addClass(options.activeClass); 326 }, 327 "mouseup touchend": function () { 328 $div.removeClass(options.activeClass); 329 }, 330 "mouseenter": function () { 331 $div.addClass(options.hoverClass); 332 }, 333 "mouseleave": function () { 334 $div.removeClass(options.hoverClass); 335 $div.removeClass(options.activeClass); 336 } 337 }); 338 339 classToggleChecked($span, $el, options); 340 return { 341 remove: function () { 342 return $el.unwrap().unwrap(); 343 }, 344 update: function () { 345 classClearStandard($div, options); 346 $span.removeClass(options.checkedClass); 347 classToggleChecked($span, $el, options); 348 classToggleDisabled($div, options); 349 } 350 }; 351 } 352 }, 353 { 354 // File selection / uploads 355 match: function ($el) { 356 return $el.is(":file"); 357 }, 358 apply: function ($el, options) { 359 var ds, $div, $filename, $button; 360 361 // The "span" is the button 362 ds = divSpan($el, options, { 363 css: { opacity: 0 }, 364 divClass: options.fileClass, 365 spanClass: options.fileButtonClass, 366 spanHtml: options.fileButtonHtml, 367 spanWrap: "after" 368 }); 369 $div = ds.div; 370 $button = ds.span; 371 $filename = $("<span />").html(options.fileDefaultHtml); 372 $filename.addClass(options.filenameClass); 373 $filename = divSpanWrap($el, $filename, "after"); 374 375 // Set the size 376 if (!$el.attr("size")) { 377 $el.attr("size", $div.width() / 10); 378 } 379 380 // Actions 381 function filenameUpdate() { 382 setFilename($el, $filename, options); 383 } 384 385 // Account for input saved across refreshes 386 filenameUpdate(); 387 388 bindMany($el, { 389 "focus": function () { 390 $div.addClass(options.focusClass); 391 }, 392 "blur": function () { 393 $div.removeClass(options.focusClass); 394 }, 395 "mousedown": function () { 396 if (!$el.is(":disabled")) { 397 $div.addClass(options.activeClass); 398 } 399 }, 400 "mouseup": function () { 401 $div.removeClass(options.activeClass); 402 }, 403 "mouseenter": function () { 404 $div.addClass(options.hoverClass); 405 }, 406 "mouseleave": function () { 407 $div.removeClass(options.hoverClass); 408 $div.removeClass(options.activeClass); 409 } 410 }); 411 412 // IE7 doesn't fire onChange until blur or second fire. 413 if ($.browser.msie) { 414 // IE considers browser chrome blocking I/O, so it 415 // suspends tiemouts until after the file has been selected. 416 bindMany($el, { 417 "click": function () { 418 $el.trigger("change"); 419 setTimeout(filenameUpdate, 0); 420 } 421 }); 422 } else { 423 // All other browsers behave properly 424 bindMany($el, { 425 "change": filenameUpdate 426 }); 427 } 428 429 $.uniform.noSelect($filename); 430 $.uniform.noSelect($button); 431 return { 432 remove: function () { 433 // Remove sibling spans 434 $el.siblings("span").remove(); 435 // Unwrap parent div 436 $el.unwrap(); 437 return $el; 438 }, 439 update: function () { 440 classClearStandard($div, options); 441 setFilename($el, $filename, options); 442 classToggleDisabled($div, $el, options); 443 } 444 }; 445 } 446 }, 447 {
448 // Input fields (text) 449 match: function ($el) { 450 if ($el.is("input")) { 451 var t = $el.attr("type").toLowerCase(), 452 allowed = " color date datetime datetime-local email month number password search tel text time url week "; 453 return allowed.indexOf(" " + t + " ") >= 0; 454 } 455 return false; 456 }, 457 apply: function ($el) { 458 var elType = $el.attr("type"); 459 $el.addClass(elType); 460 return { 461 remove: function () { 462 $el.removeClass(elType); 463 }, 464 update: function () { 465 } 466 }; 467 } 468 }, 469 { 470 // Radio buttons 471 match: function ($el) { 472 return $el.is(":radio"); 473 }, 474 apply: function ($el, options) { 475 var ds, $div, $span; 476 477 ds = divSpan($el, options, { 478 css: { opacity: 0 }, 479 divClass: options.radioClass 480 }); 481 $div = ds.div; 482 $span = ds.span; 483 484 // Add classes for focus, hanlde active, checked 485 bindMany($el, { 486 "focus": function () { 487 $div.addClass(options.focusClass); 488 }, 489 "blur": function () { 490 $div.removeClass(options.focusClass); 491 }, 492 "click touchend": function () { 493 // Untoggle the rest of the radios 494 var radioClass = options.radioClass.split(" ")[0], 495 otherRadioSpans = "." + radioClass + " span." + options.checkedClass + ":has([name='" + $el.attr("name") + "'])"; 496 $(otherRadioSpans).each(function () { 497 var $spanTag = $(this), 498 $el = $spanTag.find(":radio"); 499 classToggleChecked($spanTag, $el, options); 500 }); 501 502 // Toggle me 503 classToggleChecked($span, $el, options); 504 }, 505 "mousedown touchend": function () { 506 if (!$el.is(":disabled")) { 507 $div.addClass(options.activeClass); 508 } 509 }, 510 "mouseup touchbegin": function () { 511 $div.removeClass(options.activeClass); 512 }, 513 "mouseenter touchend": function () { 514 $div.addClass(options.hoverClass); 515 }, 516 "mouseleave": function () { 517 $div.removeClass(options.hoverClass); 518 $div.removeClass(options.activeClass); 519 } 520 }); 521 522 classToggleChecked($span, $el, options); 523 return { 524 remove: function () { 525 // Unwrap from span and div 526 return $el.unwrap().unwrap(); 527 }, 528 update: function () { 529 classClearStandard($div, options); 530 classToggleChecked($span, $el, options); 531 classToggleDisabled($div, $el, options); 532 } 533 }; 534 } 535 }, 536 { 537 // Select lists, but do not style multiselects 538 match: function ($el) { 539 var elSize; 540 541 if ($el.is("select") && !isMultiselect($el)) { 542 return true; 543 } 544 545 return false; 546 }, 547 apply: function ($el, options) { 548 var ds, $div, $span, origElemWidth, px; 549 550 origElemWidth = $el.width(); 551 ds = divSpan($el, options, { 552 css: { 553 opacity: 0, 554 // The next two need some review 555 left: "2px", 556 width: (origElemWidth + 32) + "px" 557 }, 558 divClass: options.selectClass, 559 spanHtml: ($el.find(":selected:first") || $el.find("option:first")).html(), 560 spanWrap: "before" 561 }); 562 $div = ds.div; 563 $span = ds.span; 564 565 if (options.selectAutoWidth) { 566 // This needs some critical review 567 $div.width($("<div />").width() - $("<span />").width() + origElemWidth + 25); 568 px = parseInt($div.css("paddingLeft"), 10); 569 $span.width(origElemWidth - px - 15); 570 $el.width(origElemWidth + px); 571 $el.css("min-width", origElemWidth + px + "px"); 572 $div.width(origElemWidth + px); 573 } else { 574 // Set the width of select behavior 575 px = $el.width(); 576 $div.width(175); 577 $span.width(150); 578 } 579 580 bindMany($el, { 581 "change": function () { 582 $span.html($el.find(":selected").html()); 583 $div.removeClass(options.activeClass); 584 }, 585 "focus": function () { 586 $div.addClass(options.focusClass); 587 }, 588 "blur": function () { 589 $div.removeClass(options.focusClass); 590 $div.removeClass(options.activeClass); 591 }, 592 "mousedown touchbegin": function () { 593 $div.addClass(options.activeClass); 594 }, 595 "mouseup touchend": function () { 596 $div.removeClass(options.activeClass); 597 }, 598 "click touchend": function () { 599 // IE7 and IE8 may not update the value right 600 // until click - issue #238 601 var selHtml = $el.find(":selected").html(); 602 603 if ($span.html() !== selHtml) { 604 // Change was detected 605 // Fire the change event on the select tag 606 $el.trigger('change'); 607 } 608 }, 609 "mouseenter": function () { 610 $div.addClass(options.hoverClass); 611 }, 612 "mouseleave": function () { 613 $div.removeClass(options.hoverClass); 614 $div.removeClass(options.activeClass); 615 }, 616 "keyup": function () { 617 $span.html($el.find(":selected").html()); 618 } 619 }); 620 621 $.uniform.noSelect($span); 622 623 return { 624 remove: function () { 625 // Remove sibling span 626 $el.siblings("span").remove(); 627 // Unwrap parent div 628 $el.unwrap(); 629 return $el; 630 }, 631 update: function () { 632 classClearStandard($div, options); 633 634 // Reset current selected text 635 $span.html($el.find(":selected").html()); 636 637 classToggleDisabled($div, $el, options); 638 } 639 }; 640 } 641 }, 642 { 643 // Select lists - multiselect lists only 644 match: function ($el) { 645 var elSize; 646
647 if ($el.is("select") && isMultiselect($el)) { 648 return true; 649 } 650 651 return false; 652 }, 653 apply: function ($el) { 654 $el.addClass("uniform-multiselect"); 655 return { 656 remove: function () { 657 $el.removeClass("uniform-multiselect"); 658 }, 659 update: function () { 660 } 661 }; 662 } 663 }, 664 { 665 // Textareas 666 match: function ($el) { 667 return $el.is("textarea"); 668 }, 669 apply: function ($el) { 670 $el.addClass("uniform"); 671 return { 672 remove: function () { 673 $el.removeClass("uniform"); 674 }, 675 update: function () { 676 } 677 }; 678 } 679 } 680 ]; 681 682 // IE6 can't be styled - can't set opacity on select 683 if ($.browser.msie && $.browser.version < 7) { 684 allowStyling = false; 685 } 686 687 688 $.fn.uniform = function (options) { 689 var el = this; 690 options = $.extend({}, $.uniform.defaults, options); 691 692 // Code for specifying a reset button 693 if (options.resetSelector !== false) { 694 $(options.resetSelector).mouseup(function () { 695 window.setTimeout(function () { 696 $.uniform.update(el); 697 }, 10); 698 }); 699 } 700 701 return this.each(function () { 702 var $el = $(this), 703 i, 704 handler, 705 callbacks; 706 707 // Avoid uniforming elements already uniformed - just update 708 if ($el.data("uniformed")) { 709 $.uniform.update($el); 710 } 711 712 // Avoid uniforming browsers that don't work right 713 if ($el.data("uniformed") || !allowStyling) { 714 return; 715 } 716 717 for (i = 0; i < uniformHandlers.length; i = i + 1) { 718 handler = uniformHandlers[i]; 719 720 if (handler.match($el, options)) { 721 callbacks = handler.apply($el, options); 722 723 // Mark the element as uniformed and save options 724 $el.data("uniformed", callbacks); 725 726 // Store element in our global array 727 $.uniform.elements.push($el.get(0)); 728 return; 729 } 730 } 731 }); 732 }; 733 734 $.uniform.restore = function (elem) { 735 if (elem === undef) { 736 elem = $.uniform.elements; 737 } 738 739 var $elem = $(elem); 740 741 $elem.each(function () { 742 var $el = $(this), 743 index, 744 elementData; 745 746 elementData = $el.data("uniformed"); 747 748 // Skip elements that are not uniformed 749 if (!elementData) { 750 return; 751 } 752 753 elementData.remove(); 754 755 // Unbind events 756 $el.unbind(".uniform"); 757 758 // Remove item from list of uniformed elements 759 index = $.inArray(this, $.uniform.elements); 760 761 if (index >= 0) { 762 $.uniform.elements.splice(index, 1); 763 } 764 765 $el.removeData("uniformed"); 766 }); 767 }; 768 769 //noSelect v1.0 770 $.uniform.noSelect = function (elem) { 771 var f = function () { 772 return false; 773 }; 774 775 $(elem).each(function () { 776 this.onselectstart = this.ondragstart = f; // Webkit & IE 777 // .mousedown() for Webkit and Opera 778 // .css for Firefox 779 $(this).mousedown(f).css({ 780 MozUserSelect: "none" 781 }); 782 }); 783 }; 784 785 $.uniform.update = function (elem) { 786 if (elem === undef) { 787 elem = $.uniform.elements; 788 } 789 790 var $elem = $(elem); 791 792 $elem.each(function () { 793 var $el = $(this), 794 elementData; 795 796 elementData = $el.data("uniformed"); 797 798 // Skip elements that are not uniformed 799 if (!elementData) { 800 return; 801 } 802 803 elementData.update($el, elementData.options); 804 }); 805 }; 806}(jQuery));
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.