ui_alchemy-rails 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (186) hide show
  1. data/LICENSE +20 -0
  2. data/README.md +6 -0
  3. data/Rakefile +21 -0
  4. data/app/assets/fonts/alchemy/LiberationSans-Bold-webfont.eot +0 -0
  5. data/app/assets/fonts/alchemy/LiberationSans-Bold-webfont.svg +154 -0
  6. data/app/assets/fonts/alchemy/LiberationSans-Bold-webfont.ttf +0 -0
  7. data/app/assets/fonts/alchemy/LiberationSans-Bold-webfont.woff +0 -0
  8. data/app/assets/fonts/alchemy/LiberationSans-BoldItalic-webfont.eot +0 -0
  9. data/app/assets/fonts/alchemy/LiberationSans-BoldItalic-webfont.svg +154 -0
  10. data/app/assets/fonts/alchemy/LiberationSans-BoldItalic-webfont.ttf +0 -0
  11. data/app/assets/fonts/alchemy/LiberationSans-BoldItalic-webfont.woff +0 -0
  12. data/app/assets/fonts/alchemy/LiberationSans-Italic-webfont.eot +0 -0
  13. data/app/assets/fonts/alchemy/LiberationSans-Italic-webfont.svg +154 -0
  14. data/app/assets/fonts/alchemy/LiberationSans-Italic-webfont.ttf +0 -0
  15. data/app/assets/fonts/alchemy/LiberationSans-Italic-webfont.woff +0 -0
  16. data/app/assets/fonts/alchemy/LiberationSans-Regular-webfont.eot +0 -0
  17. data/app/assets/fonts/alchemy/LiberationSans-Regular-webfont.svg +154 -0
  18. data/app/assets/fonts/alchemy/LiberationSans-Regular-webfont.ttf +0 -0
  19. data/app/assets/fonts/alchemy/LiberationSans-Regular-webfont.woff +0 -0
  20. data/app/assets/fonts/alchemy/Red Hat Liberation License.txt +78 -0
  21. data/app/assets/fonts/alchemy/overpass_bold-web.eot +0 -0
  22. data/app/assets/fonts/alchemy/overpass_bold-web.svg +470 -0
  23. data/app/assets/fonts/alchemy/overpass_bold-web.ttf +0 -0
  24. data/app/assets/fonts/alchemy/overpass_bold-web.woff +0 -0
  25. data/app/assets/fonts/alchemy/overpass_regular-web.eot +0 -0
  26. data/app/assets/fonts/alchemy/overpass_regular-web.svg +470 -0
  27. data/app/assets/fonts/alchemy/overpass_regular-web.ttf +0 -0
  28. data/app/assets/fonts/alchemy/overpass_regular-web.woff +0 -0
  29. data/app/assets/images/alchemy/icons/action-icons.png +0 -0
  30. data/app/assets/images/alchemy/icons/arrow_icon.png +0 -0
  31. data/app/assets/images/alchemy/icons/chosen-sprite.png +0 -0
  32. data/app/assets/images/alchemy/icons/error_icon.png +0 -0
  33. data/app/assets/images/alchemy/icons/objects.png +0 -0
  34. data/app/assets/images/alchemy/icons/spinner.gif +0 -0
  35. data/app/assets/images/alchemy/icons/spinner_head.gif +0 -0
  36. data/app/assets/images/alchemy/icons/success_icon.png +0 -0
  37. data/app/assets/images/alchemy/icons/warning_icon.png +0 -0
  38. data/app/assets/javascripts/alchemy/flash_messages.js +12 -0
  39. data/app/assets/javascripts/alchemy/forms.js +25 -0
  40. data/app/assets/javascripts/alchemy/i18n.js +36 -0
  41. data/app/assets/javascripts/alchemy/login.js +130 -0
  42. data/app/assets/javascripts/alchemy/password.js +99 -0
  43. data/app/assets/stylesheets/alchemy/components/_chosen.scss +423 -0
  44. data/app/assets/stylesheets/alchemy/components/_content.scss +58 -0
  45. data/app/assets/stylesheets/alchemy/components/_helpers.scss +38 -0
  46. data/app/assets/stylesheets/alchemy/components/_media.scss +49 -0
  47. data/app/assets/stylesheets/alchemy/components/_media_object.scss +22 -0
  48. data/app/assets/stylesheets/alchemy/components/_normalize.scss +396 -0
  49. data/app/assets/stylesheets/alchemy/components/_shared.scss +18 -0
  50. data/app/assets/stylesheets/alchemy/components/buttons/_buttons.scss +278 -0
  51. data/app/assets/stylesheets/alchemy/components/buttons/_buttons_vars.scss +11 -0
  52. data/app/assets/stylesheets/alchemy/components/flash_messages/_flash_messages.scss +93 -0
  53. data/app/assets/stylesheets/alchemy/components/flash_messages/_flash_messages_vars.scss +3 -0
  54. data/app/assets/stylesheets/alchemy/components/fonts/_liberation.scss +44 -0
  55. data/app/assets/stylesheets/alchemy/components/fonts/_overpass.scss +24 -0
  56. data/app/assets/stylesheets/alchemy/components/footer/_footer.scss +53 -0
  57. data/app/assets/stylesheets/alchemy/components/footer/_footer_vars.scss +4 -0
  58. data/app/assets/stylesheets/alchemy/components/forms/_forms.scss +552 -0
  59. data/app/assets/stylesheets/alchemy/components/forms/_forms_ie.scss +45 -0
  60. data/app/assets/stylesheets/alchemy/components/forms/_forms_mixins.scss +18 -0
  61. data/app/assets/stylesheets/alchemy/components/forms/_forms_responsive.scss +167 -0
  62. data/app/assets/stylesheets/alchemy/components/forms/_forms_vars.scss +25 -0
  63. data/app/assets/stylesheets/alchemy/components/header/_header.scss +216 -0
  64. data/app/assets/stylesheets/alchemy/components/header/_header_vars.scss +11 -0
  65. data/app/assets/stylesheets/alchemy/components/login/_login.scss +173 -0
  66. data/app/assets/stylesheets/alchemy/components/login/_login_mixins.scss +7 -0
  67. data/app/assets/stylesheets/alchemy/components/login/_login_vars.scss +19 -0
  68. data/app/assets/stylesheets/alchemy/components/sprites/_sprites.scss +110 -0
  69. data/app/assets/stylesheets/alchemy/components/sprites/_sprites_mixins.scss +9 -0
  70. data/app/assets/stylesheets/alchemy/components/text/_text.scss +30 -0
  71. data/app/assets/stylesheets/alchemy/components/text/_text_vars.scss +1 -0
  72. data/app/assets/stylesheets/alchemy/composites/content_elements.scss +6 -0
  73. data/app/assets/stylesheets/alchemy/composites/login.scss +9 -0
  74. data/app/assets/stylesheets/alchemy/composites/shell.scss +4 -0
  75. data/app/assets/stylesheets/alchemy/partials/_base.scss +8 -0
  76. data/app/assets/stylesheets/alchemy/partials/_colors.scss +99 -0
  77. data/app/assets/stylesheets/alchemy/partials/_mixins.scss +24 -0
  78. data/app/assets/stylesheets/alchemy/partials/_vars.scss +31 -0
  79. data/app/helpers/ui_alchemy/gettext_translations.rb +28 -0
  80. data/app/helpers/ui_alchemy/layout_helper.rb +35 -0
  81. data/app/helpers/ui_alchemy/rails_translations.rb +21 -0
  82. data/app/helpers/ui_alchemy/translation_helper.rb +19 -0
  83. data/app/views/alchemy/layouts/_change_password_layout.html.haml +20 -0
  84. data/app/views/alchemy/layouts/_common_i18n.haml +4 -0
  85. data/app/views/alchemy/layouts/_header_layout.haml +13 -0
  86. data/app/views/alchemy/layouts/_login_layout.html.haml +58 -0
  87. data/app/views/alchemy/layouts/_user_session_layout.haml +17 -0
  88. data/app/views/alchemy/layouts/base.html.haml +20 -0
  89. data/app/views/alchemy/layouts/shell_layout.haml +10 -0
  90. data/lib/ui_alchemy/rails/engine.rb +6 -0
  91. data/lib/ui_alchemy/rails/version.rb +5 -0
  92. data/lib/ui_alchemy-rails.rb +2 -0
  93. data/vendor/assets/javascripts/alchemy/handlebars.js +2201 -0
  94. data/vendor/assets/javascripts/alchemy/html5shiv.js +298 -0
  95. data/vendor/assets/javascripts/alchemy/jquery/jquery-1.6.2.js +8981 -0
  96. data/vendor/assets/javascripts/alchemy/jquery/plugins/chosen.jquery.js +1003 -0
  97. data/vendor/assets/javascripts/alchemy/jquery/plugins/flot-0.7/excanvas.js +1427 -0
  98. data/vendor/assets/javascripts/alchemy/jquery/plugins/flot-0.7/excanvas.min.js +1 -0
  99. data/vendor/assets/javascripts/alchemy/jquery/plugins/flot-0.7/jquery.colorhelpers.js +179 -0
  100. data/vendor/assets/javascripts/alchemy/jquery/plugins/flot-0.7/jquery.colorhelpers.min.js +1 -0
  101. data/vendor/assets/javascripts/alchemy/jquery/plugins/flot-0.7/jquery.flot.crosshair.js +167 -0
  102. data/vendor/assets/javascripts/alchemy/jquery/plugins/flot-0.7/jquery.flot.crosshair.min.js +1 -0
  103. data/vendor/assets/javascripts/alchemy/jquery/plugins/flot-0.7/jquery.flot.fillbetween.js +183 -0
  104. data/vendor/assets/javascripts/alchemy/jquery/plugins/flot-0.7/jquery.flot.fillbetween.min.js +1 -0
  105. data/vendor/assets/javascripts/alchemy/jquery/plugins/flot-0.7/jquery.flot.image.js +238 -0
  106. data/vendor/assets/javascripts/alchemy/jquery/plugins/flot-0.7/jquery.flot.image.min.js +1 -0
  107. data/vendor/assets/javascripts/alchemy/jquery/plugins/flot-0.7/jquery.flot.js +2599 -0
  108. data/vendor/assets/javascripts/alchemy/jquery/plugins/flot-0.7/jquery.flot.min.js +6 -0
  109. data/vendor/assets/javascripts/alchemy/jquery/plugins/flot-0.7/jquery.flot.navigate.js +336 -0
  110. data/vendor/assets/javascripts/alchemy/jquery/plugins/flot-0.7/jquery.flot.navigate.min.js +1 -0
  111. data/vendor/assets/javascripts/alchemy/jquery/plugins/flot-0.7/jquery.flot.pie.js +750 -0
  112. data/vendor/assets/javascripts/alchemy/jquery/plugins/flot-0.7/jquery.flot.pie.min.js +1 -0
  113. data/vendor/assets/javascripts/alchemy/jquery/plugins/flot-0.7/jquery.flot.resize.js +60 -0
  114. data/vendor/assets/javascripts/alchemy/jquery/plugins/flot-0.7/jquery.flot.resize.min.js +1 -0
  115. data/vendor/assets/javascripts/alchemy/jquery/plugins/flot-0.7/jquery.flot.selection.js +344 -0
  116. data/vendor/assets/javascripts/alchemy/jquery/plugins/flot-0.7/jquery.flot.selection.min.js +1 -0
  117. data/vendor/assets/javascripts/alchemy/jquery/plugins/flot-0.7/jquery.flot.stack.js +184 -0
  118. data/vendor/assets/javascripts/alchemy/jquery/plugins/flot-0.7/jquery.flot.stack.min.js +1 -0
  119. data/vendor/assets/javascripts/alchemy/jquery/plugins/flot-0.7/jquery.flot.symbol.js +70 -0
  120. data/vendor/assets/javascripts/alchemy/jquery/plugins/flot-0.7/jquery.flot.symbol.min.js +1 -0
  121. data/vendor/assets/javascripts/alchemy/jquery/plugins/flot-0.7/jquery.flot.threshold.js +103 -0
  122. data/vendor/assets/javascripts/alchemy/jquery/plugins/flot-0.7/jquery.flot.threshold.min.js +1 -0
  123. data/vendor/assets/javascripts/alchemy/jquery/plugins/jquery-svg/blank.svg +3 -0
  124. data/vendor/assets/javascripts/alchemy/jquery/plugins/jquery-svg/custom_test.js +67 -0
  125. data/vendor/assets/javascripts/alchemy/jquery/plugins/jquery-svg/jquery.svg.css +9 -0
  126. data/vendor/assets/javascripts/alchemy/jquery/plugins/jquery-svg/jquery.svg.js +1101 -0
  127. data/vendor/assets/javascripts/alchemy/jquery/plugins/jquery-svg/jquery.svg.min.js +7 -0
  128. data/vendor/assets/javascripts/alchemy/jquery/plugins/jquery-svg/jquery.svg.pack.js +7 -0
  129. data/vendor/assets/javascripts/alchemy/jquery/plugins/jquery-svg/jquery.svgfilter.js +396 -0
  130. data/vendor/assets/javascripts/alchemy/jquery/plugins/jquery-svg/jquery.svgfilter.min.js +7 -0
  131. data/vendor/assets/javascripts/alchemy/jquery/plugins/jquery-svg/jquery.svgfilter.pack.js +7 -0
  132. data/vendor/assets/javascripts/alchemy/jquery/plugins/jquery-svg/jquery.svggraph.js +1337 -0
  133. data/vendor/assets/javascripts/alchemy/jquery/plugins/jquery-svg/jquery.svggraph.min.js +7 -0
  134. data/vendor/assets/javascripts/alchemy/jquery/plugins/jquery-svg/jquery.svggraph.pack.js +7 -0
  135. data/vendor/assets/javascripts/alchemy/jquery/plugins/jquery-svg/lion.svg +161 -0
  136. data/vendor/assets/javascripts/alchemy/jquery/plugins/jquery-svg/test.js +714 -0
  137. data/vendor/assets/javascripts/alchemy/jquery/plugins/jquery.ajaxfileupload.js +205 -0
  138. data/vendor/assets/javascripts/alchemy/jquery/plugins/jquery.ba-bbq.js +1137 -0
  139. data/vendor/assets/javascripts/alchemy/jquery/plugins/jquery.ba-resize.js +246 -0
  140. data/vendor/assets/javascripts/alchemy/jquery/plugins/jquery.cookie.js +92 -0
  141. data/vendor/assets/javascripts/alchemy/jquery/plugins/jquery.easing.1.3.js +205 -0
  142. data/vendor/assets/javascripts/alchemy/jquery/plugins/jquery.fancyqueries.js +106 -0
  143. data/vendor/assets/javascripts/alchemy/jquery/plugins/jquery.flash.js +288 -0
  144. data/vendor/assets/javascripts/alchemy/jquery/plugins/jquery.form.js +964 -0
  145. data/vendor/assets/javascripts/alchemy/jquery/plugins/jquery.hoverIntent.js +106 -0
  146. data/vendor/assets/javascripts/alchemy/jquery/plugins/jquery.jeditable.ajaxupload.js +62 -0
  147. data/vendor/assets/javascripts/alchemy/jquery/plugins/jquery.jeditable.js +556 -0
  148. data/vendor/assets/javascripts/alchemy/jquery/plugins/jquery.jnotify.js +210 -0
  149. data/vendor/assets/javascripts/alchemy/jquery/plugins/jquery.jscrollpane.js +1390 -0
  150. data/vendor/assets/javascripts/alchemy/jquery/plugins/jquery.jscrollpane.min.js +11 -0
  151. data/vendor/assets/javascripts/alchemy/jquery/plugins/jquery.linkHover.js +89 -0
  152. data/vendor/assets/javascripts/alchemy/jquery/plugins/jquery.loadmask.min.js +10 -0
  153. data/vendor/assets/javascripts/alchemy/jquery/plugins/jquery.mousewheel.js +78 -0
  154. data/vendor/assets/javascripts/alchemy/jquery/plugins/jquery.multiselect.filter.js +176 -0
  155. data/vendor/assets/javascripts/alchemy/jquery/plugins/jquery.multiselect.js +668 -0
  156. data/vendor/assets/javascripts/alchemy/jquery/plugins/jquery.pack.js +11 -0
  157. data/vendor/assets/javascripts/alchemy/jquery/plugins/jquery.periodicalupdater.js +175 -0
  158. data/vendor/assets/javascripts/alchemy/jquery/plugins/jquery.sortElements.js +75 -0
  159. data/vendor/assets/javascripts/alchemy/jquery/plugins/jquery.sparkline.min.js +94 -0
  160. data/vendor/assets/javascripts/alchemy/jquery/plugins/jquery.text-overflow.js +60 -0
  161. data/vendor/assets/javascripts/alchemy/jquery/plugins/jquery.timepickr.js +214 -0
  162. data/vendor/assets/javascripts/alchemy/jquery/plugins/jquery.timers.js +142 -0
  163. data/vendor/assets/javascripts/alchemy/jquery/plugins/jquery.tipsy.js +358 -0
  164. data/vendor/assets/javascripts/alchemy/jquery/plugins/jquery.treeTable.js +226 -0
  165. data/vendor/assets/javascripts/alchemy/jquery/plugins/jquery.trunk8.js +203 -0
  166. data/vendor/assets/javascripts/alchemy/jquery/plugins/jquery.ui.multiselect.js +338 -0
  167. data/vendor/assets/javascripts/alchemy/jquery/plugins/jquery.ui.totop.js +58 -0
  168. data/vendor/assets/javascripts/alchemy/jquery/plugins/jquery.uitablefilter.js +95 -0
  169. data/vendor/assets/javascripts/alchemy/jquery/plugins/ui.spinner.js +683 -0
  170. data/vendor/assets/javascripts/alchemy/jquery-ui-1.8.11.custom/css/custom-theme/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  171. data/vendor/assets/javascripts/alchemy/jquery-ui-1.8.11.custom/css/custom-theme/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  172. data/vendor/assets/javascripts/alchemy/jquery-ui-1.8.11.custom/css/custom-theme/images/ui-bg_highlight-hard_75_dadada_1x100.png +0 -0
  173. data/vendor/assets/javascripts/alchemy/jquery-ui-1.8.11.custom/css/custom-theme/images/ui-bg_highlight-hard_75_e6e6e6_1x100.png +0 -0
  174. data/vendor/assets/javascripts/alchemy/jquery-ui-1.8.11.custom/css/custom-theme/images/ui-bg_highlight-hard_95_ffffff_1x100.png +0 -0
  175. data/vendor/assets/javascripts/alchemy/jquery-ui-1.8.11.custom/css/custom-theme/images/ui-bg_highlight-soft_80_e0e0e0_1x100.png +0 -0
  176. data/vendor/assets/javascripts/alchemy/jquery-ui-1.8.11.custom/css/custom-theme/images/ui-bg_inset-hard_65_ffffff_1x100.png +0 -0
  177. data/vendor/assets/javascripts/alchemy/jquery-ui-1.8.11.custom/css/custom-theme/images/ui-bg_inset-soft_95_fef1ec_1x100.png +0 -0
  178. data/vendor/assets/javascripts/alchemy/jquery-ui-1.8.11.custom/css/custom-theme/images/ui-icons_8f8f8f_256x240.png +0 -0
  179. data/vendor/assets/javascripts/alchemy/jquery-ui-1.8.11.custom/css/custom-theme/images/ui-icons_97baed_256x240.png +0 -0
  180. data/vendor/assets/javascripts/alchemy/jquery-ui-1.8.11.custom/css/custom-theme/images/ui-icons_cd0a0a_256x240.png +0 -0
  181. data/vendor/assets/javascripts/alchemy/jquery-ui-1.8.11.custom/css/custom-theme/jquery-ui-1.8.11.custom.css +573 -0
  182. data/vendor/assets/javascripts/alchemy/jquery-ui-1.8.11.custom/js/jquery-1.5.1.min.js +16 -0
  183. data/vendor/assets/javascripts/alchemy/jquery-ui-1.8.11.custom/js/jquery-ui-1.8.11.custom.min.js +783 -0
  184. data/vendor/assets/javascripts/alchemy/rails.js +331 -0
  185. data/vendor/assets/javascripts/alchemy/underscore-1.3.1.js +999 -0
  186. metadata +252 -0
@@ -0,0 +1,668 @@
1
+ /* jshint forin:true, noarg:true, noempty:true, eqeqeq:true, boss:true, undef:true, curly:true, browser:true, jquery:true */
2
+ /*
3
+ * jQuery MultiSelect UI Widget 1.12
4
+ * Copyright (c) 2011 Eric Hynds
5
+ *
6
+ * http://www.erichynds.com/jquery/jquery-ui-multiselect-widget/
7
+ *
8
+ * Depends:
9
+ * - jQuery 1.4.2+
10
+ * - jQuery UI 1.8 widget factory
11
+ *
12
+ * Optional:
13
+ * - jQuery UI effects
14
+ * - jQuery UI position utility
15
+ *
16
+ * Dual licensed under the MIT and GPL licenses:
17
+ * http://www.opensource.org/licenses/mit-license.php
18
+ * http://www.gnu.org/licenses/gpl.html
19
+ *
20
+ */
21
+ (function($, undefined){
22
+
23
+ var multiselectID = 0;
24
+
25
+ $.widget("ech.multiselect", {
26
+
27
+ // default options
28
+ options: {
29
+ header: true,
30
+ height: 175,
31
+ minWidth: 225,
32
+ classes: '',
33
+ checkAllText: 'Check all',
34
+ uncheckAllText: 'Uncheck all',
35
+ noneSelectedText: 'Select options',
36
+ selectedText: '# selected',
37
+ selectedList: 0,
38
+ show: '',
39
+ hide: '',
40
+ autoOpen: false,
41
+ multiple: true,
42
+ position: {}
43
+ },
44
+
45
+ _create: function(){
46
+ var el = this.element.hide(),
47
+ o = this.options;
48
+
49
+ this.speed = $.fx.speeds._default; // default speed for effects
50
+ this._isOpen = false; // assume no
51
+
52
+ var
53
+ button = (this.button = $('<button type="button"><span class="ui-icon ui-icon-triangle-2-n-s"></span></button>'))
54
+ .addClass('ui-multiselect ui-widget ui-state-default ui-corner-all')
55
+ .addClass( o.classes )
56
+ .attr({ 'title':el.attr('title'), 'aria-haspopup':true, 'tabIndex':el.attr('tabIndex') })
57
+ .insertAfter( el ),
58
+
59
+ buttonlabel = (this.buttonlabel = $('<span />'))
60
+ .html( o.noneSelectedText )
61
+ .appendTo( button ),
62
+
63
+ menu = (this.menu = $('<div />'))
64
+ .addClass('ui-multiselect-menu ui-widget ui-widget-content ui-corner-all')
65
+ .addClass( o.classes )
66
+ .appendTo( document.body ),
67
+
68
+ header = (this.header = $('<div />'))
69
+ .addClass('ui-widget-header ui-corner-all ui-multiselect-header ui-helper-clearfix')
70
+ .appendTo( menu ),
71
+
72
+ headerLinkContainer = (this.headerLinkContainer = $('<ul />'))
73
+ .addClass('ui-helper-reset')
74
+ .html(function(){
75
+ if( o.header === true ){
76
+ return '<li><a class="ui-multiselect-all" href="#"><span class="ui-icon ui-icon-check"></span><span>' + o.checkAllText + '</span></a></li><li><a class="ui-multiselect-none" href="#"><span class="ui-icon ui-icon-closethick"></span><span>' + o.uncheckAllText + '</span></a></li>';
77
+ } else if(typeof o.header === "string"){
78
+ return '<li>' + o.header + '</li>';
79
+ } else {
80
+ return '';
81
+ }
82
+ })
83
+ .append('<li class="ui-multiselect-close"><a href="#" class="ui-multiselect-close"><span class="ui-icon ui-icon-circle-close"></span></a></li>')
84
+ .appendTo( header ),
85
+
86
+ checkboxContainer = (this.checkboxContainer = $('<ul />'))
87
+ .addClass('ui-multiselect-checkboxes ui-helper-reset')
88
+ .appendTo( menu );
89
+
90
+ // perform event bindings
91
+ this._bindEvents();
92
+
93
+ // build menu
94
+ this.refresh( true );
95
+
96
+ // some addl. logic for single selects
97
+ if( !o.multiple ){
98
+ menu.addClass('ui-multiselect-single');
99
+ }
100
+ },
101
+
102
+ _init: function(){
103
+ if( this.options.header === false ){
104
+ this.header.hide();
105
+ }
106
+ if( !this.options.multiple ){
107
+ this.headerLinkContainer.find('.ui-multiselect-all, .ui-multiselect-none').hide();
108
+ }
109
+ if( this.options.autoOpen ){
110
+ this.open();
111
+ }
112
+ if( this.element.is(':disabled') ){
113
+ this.disable();
114
+ }
115
+ },
116
+
117
+ refresh: function( init ){
118
+ var el = this.element,
119
+ o = this.options,
120
+ menu = this.menu,
121
+ checkboxContainer = this.checkboxContainer,
122
+ optgroups = [],
123
+ html = [],
124
+ id = el.attr('id') || multiselectID++; // unique ID for the label & option tags
125
+
126
+ // build items
127
+ el.find('option').each(function( i ){
128
+ var $this = $(this),
129
+ parent = this.parentNode,
130
+ title = this.innerHTML,
131
+ description = this.title,
132
+ value = this.value,
133
+ inputID = this.id || 'ui-multiselect-' + id + '-option-' + i,
134
+ isDisabled = this.disabled,
135
+ isSelected = this.selected,
136
+ labelClasses = ['ui-corner-all'],
137
+ optLabel;
138
+
139
+ // is this an optgroup?
140
+ if( parent.tagName.toLowerCase() === 'optgroup' ){
141
+ optLabel = parent.getAttribute('label');
142
+
143
+ // has this optgroup been added already?
144
+ if( $.inArray(optLabel, optgroups) === -1 ){
145
+ html.push('<li class="ui-multiselect-optgroup-label"><a href="#">' + optLabel + '</a></li>');
146
+ optgroups.push( optLabel );
147
+ }
148
+ }
149
+
150
+ if( isDisabled ){
151
+ labelClasses.push('ui-state-disabled');
152
+ }
153
+
154
+ // browsers automatically select the first option
155
+ // by default with single selects
156
+ if( isSelected && !o.multiple ){
157
+ labelClasses.push('ui-state-active');
158
+ }
159
+
160
+ html.push('<li class="' + (isDisabled ? 'ui-multiselect-disabled' : '') + '">');
161
+
162
+ // create the label
163
+ html.push('<label for="' + inputID + '" title="' + description + '" class="' + labelClasses.join(' ') + '">');
164
+ html.push('<input id="' + inputID + '" name="multiselect_' + id + '" type="' + (o.multiple ? "checkbox" : "radio") + '" value="' + value + '" title="' + title + '"');
165
+
166
+ // pre-selected?
167
+ if( isSelected ){
168
+ html.push(' checked="checked"');
169
+ html.push(' aria-selected="true"');
170
+ }
171
+
172
+ // disabled?
173
+ if( isDisabled ){
174
+ html.push(' disabled="disabled"');
175
+ html.push(' aria-disabled="true"');
176
+ }
177
+
178
+ // add the title and close everything off
179
+ html.push(' /><span>' + title + '</span></label></li>');
180
+ });
181
+
182
+ // insert into the DOM
183
+ checkboxContainer.html( html.join('') );
184
+
185
+ // cache some moar useful elements
186
+ this.labels = menu.find('label');
187
+
188
+ // set widths
189
+ this._setButtonWidth();
190
+ this._setMenuWidth();
191
+
192
+ // remember default value
193
+ this.button[0].defaultValue = this.update();
194
+
195
+ // broadcast refresh event; useful for widgets
196
+ if( !init ){
197
+ this._trigger('refresh');
198
+ }
199
+ },
200
+
201
+ // updates the button text. call refresh() to rebuild
202
+ update: function(){
203
+ var o = this.options,
204
+ $inputs = this.labels.find('input'),
205
+ $checked = $inputs.filter('[checked]'),
206
+ numChecked = $checked.length,
207
+ value;
208
+
209
+ if( numChecked === 0 ){
210
+ value = o.noneSelectedText;
211
+ } else {
212
+ if($.isFunction( o.selectedText )){
213
+ value = o.selectedText.call(this, numChecked, $inputs.length, $checked.get());
214
+ } else if( /\d/.test(o.selectedList) && o.selectedList > 0 && numChecked <= o.selectedList){
215
+ value = $checked.map(function(){ return $(this).next().text(); }).get().join(', ');
216
+ } else {
217
+ value = o.selectedText.replace('#', numChecked).replace('#', $inputs.length);
218
+ }
219
+ }
220
+
221
+ this.buttonlabel.html( value );
222
+ return value;
223
+ },
224
+
225
+ // binds events
226
+ _bindEvents: function(){
227
+ var self = this, button = this.button;
228
+
229
+ function clickHandler(){
230
+ self[ self._isOpen ? 'close' : 'open' ]();
231
+ return false;
232
+ }
233
+
234
+ // webkit doesn't like it when you click on the span :(
235
+ button
236
+ .find('span')
237
+ .bind('click.multiselect', clickHandler);
238
+
239
+ // button events
240
+ button.bind({
241
+ click: clickHandler,
242
+ keypress: function( e ){
243
+ switch(e.which){
244
+ case 27: // esc
245
+ case 38: // up
246
+ case 37: // left
247
+ self.close();
248
+ break;
249
+ case 39: // right
250
+ case 40: // down
251
+ self.open();
252
+ break;
253
+ }
254
+ },
255
+ mouseenter: function(){
256
+ if( !button.hasClass('ui-state-disabled') ){
257
+ $(this).addClass('ui-state-hover');
258
+ }
259
+ },
260
+ mouseleave: function(){
261
+ $(this).removeClass('ui-state-hover');
262
+ },
263
+ focus: function(){
264
+ if( !button.hasClass('ui-state-disabled') ){
265
+ $(this).addClass('ui-state-focus');
266
+ }
267
+ },
268
+ blur: function(){
269
+ $(this).removeClass('ui-state-focus');
270
+ }
271
+ });
272
+
273
+ // header links
274
+ this.header
275
+ .delegate('a', 'click.multiselect', function( e ){
276
+ // close link
277
+ if( $(this).hasClass('ui-multiselect-close') ){
278
+ self.close();
279
+
280
+ // check all / uncheck all
281
+ } else {
282
+ self[ $(this).hasClass('ui-multiselect-all') ? 'checkAll' : 'uncheckAll' ]();
283
+ }
284
+
285
+ e.preventDefault();
286
+ });
287
+
288
+ // optgroup label toggle support
289
+ this.menu
290
+ .delegate('li.ui-multiselect-optgroup-label a', 'click.multiselect', function( e ){
291
+ e.preventDefault();
292
+
293
+ var $this = $(this),
294
+ $inputs = $this.parent().nextUntil('li.ui-multiselect-optgroup-label').find('input:visible:not(:disabled)'),
295
+ nodes = $inputs.get(),
296
+ label = $this.parent().text();
297
+
298
+ // trigger event and bail if the return is false
299
+ if( self._trigger('beforeoptgrouptoggle', e, { inputs:nodes, label:label }) === false ){
300
+ return;
301
+ }
302
+
303
+ // toggle inputs
304
+ self._toggleChecked(
305
+ $inputs.filter('[checked]').length !== $inputs.length,
306
+ $inputs
307
+ );
308
+
309
+ self._trigger('optgrouptoggle', e, {
310
+ inputs: nodes,
311
+ label: label,
312
+ checked: nodes[0].checked
313
+ });
314
+ })
315
+ .delegate('label', 'mouseenter.multiselect', function(){
316
+ if( !$(this).hasClass('ui-state-disabled') ){
317
+ self.labels.removeClass('ui-state-hover');
318
+ $(this).addClass('ui-state-hover').find('input').focus();
319
+ }
320
+ })
321
+ .delegate('label', 'keydown.multiselect', function( e ){
322
+ e.preventDefault();
323
+
324
+ switch(e.which){
325
+ case 9: // tab
326
+ case 27: // esc
327
+ self.close();
328
+ break;
329
+ case 38: // up
330
+ case 40: // down
331
+ case 37: // left
332
+ case 39: // right
333
+ self._traverse(e.which, this);
334
+ break;
335
+ case 13: // enter
336
+ $(this).find('input')[0].click();
337
+ break;
338
+ }
339
+ })
340
+ .delegate('input[type="checkbox"], input[type="radio"]', 'click.multiselect', function( e ){
341
+ var $this = $(this),
342
+ val = this.value,
343
+ checked = this.checked,
344
+ tags = self.element.find('option');
345
+
346
+ // bail if this input is disabled or the event is cancelled
347
+ if( this.disabled || self._trigger('click', e, { value: val, text: this.title, checked: checked }) === false ){
348
+ e.preventDefault();
349
+ return;
350
+ }
351
+
352
+ // make sure the input has focus. otherwise, the esc key
353
+ // won't close the menu after clicking an item.
354
+ $this.focus();
355
+
356
+ // toggle aria state
357
+ $this.attr('aria-selected', checked);
358
+
359
+ // change state on the original option tags
360
+ tags.each(function(){
361
+ if( this.value === val ){
362
+ this.selected = checked;
363
+ } else if( !self.options.multiple ){
364
+ this.selected = false;
365
+ }
366
+ });
367
+
368
+ // some additional single select-specific logic
369
+ if( !self.options.multiple ){
370
+ self.labels.removeClass('ui-state-active');
371
+ $this.closest('label').toggleClass('ui-state-active', checked );
372
+
373
+ // close menu
374
+ self.close();
375
+ }
376
+
377
+ // fire change on the select box
378
+ self.element.trigger("change");
379
+
380
+ // setTimeout is to fix multiselect issue #14 and #47. caused by jQuery issue #3827
381
+ // http://bugs.jquery.com/ticket/3827
382
+ setTimeout($.proxy(self.update, self), 10);
383
+ });
384
+
385
+ // close each widget when clicking on any other element/anywhere else on the page
386
+ $(document).bind('mousedown.multiselect', function( e ){
387
+ if(self._isOpen && !$.contains(self.menu[0], e.target) && !$.contains(self.button[0], e.target) && e.target !== self.button[0]){
388
+ self.close();
389
+ }
390
+ });
391
+
392
+ // deal with form resets. the problem here is that buttons aren't
393
+ // restored to their defaultValue prop on form reset, and the reset
394
+ // handler fires before the form is actually reset. delaying it a bit
395
+ // gives the form inputs time to clear.
396
+ $(this.element[0].form).bind('reset.multiselect', function(){
397
+ setTimeout($.proxy(self.refresh, self), 10);
398
+ });
399
+ },
400
+
401
+ // set button width
402
+ _setButtonWidth: function(){
403
+ var width = this.element.outerWidth(),
404
+ o = this.options;
405
+
406
+ if( /\d/.test(o.minWidth) && width < o.minWidth){
407
+ width = o.minWidth;
408
+ }
409
+
410
+ // set widths
411
+ this.button.width( width );
412
+ },
413
+
414
+ // set menu width
415
+ _setMenuWidth: function(){
416
+ var m = this.menu,
417
+ width = this.button.outerWidth()-
418
+ parseInt(m.css('padding-left'),10)-
419
+ parseInt(m.css('padding-right'),10)-
420
+ parseInt(m.css('border-right-width'),10)-
421
+ parseInt(m.css('border-left-width'),10);
422
+
423
+ m.width( width || this.button.outerWidth() );
424
+ },
425
+
426
+ // move up or down within the menu
427
+ _traverse: function( which, start ){
428
+ var $start = $(start),
429
+ moveToLast = which === 38 || which === 37,
430
+
431
+ // select the first li that isn't an optgroup label / disabled
432
+ $next = $start.parent()[moveToLast ? 'prevAll' : 'nextAll']('li:not(.ui-multiselect-disabled, .ui-multiselect-optgroup-label)')[ moveToLast ? 'last' : 'first']();
433
+
434
+ // if at the first/last element
435
+ if( !$next.length ){
436
+ var $container = this.menu.find('ul').last();
437
+
438
+ // move to the first/last
439
+ this.menu.find('label')[ moveToLast ? 'last' : 'first' ]().trigger('mouseover');
440
+
441
+ // set scroll position
442
+ $container.scrollTop( moveToLast ? $container.height() : 0 );
443
+
444
+ } else {
445
+ $next.find('label').trigger('mouseover');
446
+ }
447
+ },
448
+
449
+ // This is an internal function to toggle the checked property and
450
+ // other related attributes of a checkbox.
451
+ //
452
+ // The context of this function should be a checkbox; do not proxy it.
453
+ _toggleState: function( prop, flag ){
454
+ return function(){
455
+ if( !this.disabled ) {
456
+ this[ prop ] = flag;
457
+ }
458
+
459
+ if( flag ){
460
+ this.setAttribute('aria-selected', true);
461
+ } else {
462
+ this.removeAttribute('aria-selected');
463
+ }
464
+ };
465
+ },
466
+
467
+ _toggleChecked: function( flag, group ){
468
+ var $inputs = (group && group.length) ?
469
+ group :
470
+ this.labels.find('input'),
471
+
472
+ self = this;
473
+
474
+ // toggle state on inputs
475
+ $inputs.each(this._toggleState('checked', flag));
476
+
477
+ // give the first input focus
478
+ $inputs.eq(0).focus();
479
+
480
+ // update button text
481
+ this.update();
482
+
483
+ // gather an array of the values that actually changed
484
+ var values = $inputs.map(function(){
485
+ return this.value;
486
+ }).get();
487
+
488
+ // toggle state on original option tags
489
+ this.element
490
+ .find('option')
491
+ .each(function(){
492
+ if( !this.disabled && $.inArray(this.value, values) > -1 ){
493
+ self._toggleState('selected', flag).call( this );
494
+ }
495
+ });
496
+
497
+ // trigger the change event on the select
498
+ if( $inputs.length ) {
499
+ this.element.trigger("change");
500
+ }
501
+ },
502
+
503
+ _toggleDisabled: function( flag ){
504
+ this.button
505
+ .attr({ 'disabled':flag, 'aria-disabled':flag })[ flag ? 'addClass' : 'removeClass' ]('ui-state-disabled');
506
+
507
+ this.menu
508
+ .find('input')
509
+ .attr({ 'disabled':flag, 'aria-disabled':flag })
510
+ .parent()[ flag ? 'addClass' : 'removeClass' ]('ui-state-disabled');
511
+
512
+ this.element
513
+ .attr({ 'disabled':flag, 'aria-disabled':flag });
514
+ },
515
+
516
+ // open the menu
517
+ open: function( e ){
518
+ var self = this,
519
+ button = this.button,
520
+ menu = this.menu,
521
+ speed = this.speed,
522
+ o = this.options;
523
+
524
+ // bail if the multiselectopen event returns false, this widget is disabled, or is already open
525
+ if( this._trigger('beforeopen') === false || button.hasClass('ui-state-disabled') || this._isOpen ){
526
+ return;
527
+ }
528
+
529
+ var $container = menu.find('ul').last(),
530
+ effect = o.show,
531
+ pos = button.offset();
532
+
533
+ // figure out opening effects/speeds
534
+ if( $.isArray(o.show) ){
535
+ effect = o.show[0];
536
+ speed = o.show[1] || self.speed;
537
+ }
538
+
539
+ // set the scroll of the checkbox container
540
+ $container.scrollTop(0).height(o.height);
541
+
542
+ // position and show menu
543
+ if( $.ui.position && !$.isEmptyObject(o.position) ){
544
+ o.position.of = o.position.of || button;
545
+
546
+ menu
547
+ .show()
548
+ .position( o.position )
549
+ .hide()
550
+ .show( effect, speed );
551
+
552
+ // if position utility is not available...
553
+ } else {
554
+ menu.css({
555
+ top: pos.top + button.outerHeight(),
556
+ left: pos.left
557
+ }).show( effect, speed );
558
+ }
559
+
560
+ // select the first option
561
+ // triggering both mouseover and mouseover because 1.4.2+ has a bug where triggering mouseover
562
+ // will actually trigger mouseenter. the mouseenter trigger is there for when it's eventually fixed
563
+ this.labels.eq(0).trigger('mouseover').trigger('mouseenter').find('input').trigger('focus');
564
+
565
+ button.addClass('ui-state-active');
566
+ this._isOpen = true;
567
+ this._trigger('open');
568
+ },
569
+
570
+ // close the menu
571
+ close: function(){
572
+ if(this._trigger('beforeclose') === false){
573
+ return;
574
+ }
575
+
576
+ var o = this.options, effect = o.hide, speed = this.speed;
577
+
578
+ // figure out opening effects/speeds
579
+ if( $.isArray(o.hide) ){
580
+ effect = o.hide[0];
581
+ speed = o.hide[1] || this.speed;
582
+ }
583
+
584
+ this.menu.hide(effect, speed);
585
+ this.button.removeClass('ui-state-active').trigger('blur').trigger('mouseleave');
586
+ this._isOpen = false;
587
+ this._trigger('close');
588
+ },
589
+
590
+ enable: function(){
591
+ this._toggleDisabled(false);
592
+ },
593
+
594
+ disable: function(){
595
+ this._toggleDisabled(true);
596
+ },
597
+
598
+ checkAll: function( e ){
599
+ this._toggleChecked(true);
600
+ this._trigger('checkAll');
601
+ },
602
+
603
+ uncheckAll: function(){
604
+ this._toggleChecked(false);
605
+ this._trigger('uncheckAll');
606
+ },
607
+
608
+ getChecked: function(){
609
+ return this.menu.find('input').filter('[checked]');
610
+ },
611
+
612
+ destroy: function(){
613
+ // remove classes + data
614
+ $.Widget.prototype.destroy.call( this );
615
+
616
+ this.button.remove();
617
+ this.menu.remove();
618
+ this.element.show();
619
+
620
+ return this;
621
+ },
622
+
623
+ isOpen: function(){
624
+ return this._isOpen;
625
+ },
626
+
627
+ widget: function(){
628
+ return this.menu;
629
+ },
630
+
631
+ // react to option changes after initialization
632
+ _setOption: function( key, value ){
633
+ var menu = this.menu;
634
+
635
+ switch(key){
636
+ case 'header':
637
+ menu.find('div.ui-multiselect-header')[ value ? 'show' : 'hide' ]();
638
+ break;
639
+ case 'checkAllText':
640
+ menu.find('a.ui-multiselect-all span').eq(-1).text(value);
641
+ break;
642
+ case 'uncheckAllText':
643
+ menu.find('a.ui-multiselect-none span').eq(-1).text(value);
644
+ break;
645
+ case 'height':
646
+ menu.find('ul').last().height( parseInt(value,10) );
647
+ break;
648
+ case 'minWidth':
649
+ this.options[ key ] = parseInt(value,10);
650
+ this._setButtonWidth();
651
+ this._setMenuWidth();
652
+ break;
653
+ case 'selectedText':
654
+ case 'selectedList':
655
+ case 'noneSelectedText':
656
+ this.options[key] = value; // these all needs to update immediately for the update() call
657
+ this.update();
658
+ break;
659
+ case 'classes':
660
+ menu.add(this.button).removeClass(this.options.classes).addClass(value);
661
+ break;
662
+ }
663
+
664
+ $.Widget.prototype._setOption.apply( this, arguments );
665
+ }
666
+ });
667
+
668
+ })(jQuery);