alchemy_cms 2.3.2 → 2.4.beta2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (164) hide show
  1. data/.gitignore +1 -2
  2. data/.travis.yml +1 -5
  3. data/Gemfile +4 -4
  4. data/README.md +22 -15
  5. data/alchemy_cms.gemspec +38 -38
  6. data/app/assets/javascripts/alchemy/alchemy.base.js +2 -2
  7. data/app/assets/javascripts/alchemy/alchemy.buttons.js.coffee +31 -0
  8. data/app/assets/javascripts/alchemy/alchemy.dragndrop.js +1 -1
  9. data/app/assets/javascripts/alchemy/alchemy.elements_window.js +24 -15
  10. data/app/assets/javascripts/alchemy/alchemy.gui.js.coffee +9 -3
  11. data/app/assets/javascripts/alchemy/alchemy.jquery_loader.js +2 -2
  12. data/app/assets/javascripts/alchemy/alchemy.js +1 -0
  13. data/app/assets/javascripts/alchemy/alchemy.menubar.js +4 -12
  14. data/app/assets/javascripts/alchemy/alchemy.onload.js.coffee +32 -0
  15. data/app/assets/javascripts/alchemy/alchemy.windows.js +4 -4
  16. data/app/assets/stylesheets/alchemy/_defaults.scss +0 -1
  17. data/app/assets/stylesheets/alchemy/alchemy.css +2 -1
  18. data/app/assets/stylesheets/alchemy/base.css.scss +2 -54
  19. data/app/assets/stylesheets/alchemy/elements.css.scss +8 -5
  20. data/app/assets/stylesheets/alchemy/errors.css.scss +51 -0
  21. data/app/assets/stylesheets/alchemy/flash.css.scss +0 -2
  22. data/app/assets/stylesheets/alchemy/form_elements.css.scss +31 -75
  23. data/app/assets/stylesheets/alchemy/icons.css.scss +5 -5
  24. data/app/assets/stylesheets/alchemy/menubar.css.scss +0 -2
  25. data/app/assets/stylesheets/alchemy/sitemap.css.scss +0 -1
  26. data/app/assets/stylesheets/alchemy/tables.css.scss +3 -1
  27. data/app/controllers/alchemy/admin/base_controller.rb +19 -12
  28. data/app/controllers/alchemy/admin/elements_controller.rb +52 -24
  29. data/app/controllers/alchemy/admin/pages_controller.rb +11 -5
  30. data/app/controllers/alchemy/admin/resources_controller.rb +3 -4
  31. data/app/controllers/alchemy/admin/users_controller.rb +1 -0
  32. data/app/controllers/alchemy/base_controller.rb +34 -8
  33. data/app/controllers/alchemy/pictures_controller.rb +16 -1
  34. data/app/controllers/alchemy/user_sessions_controller.rb +6 -1
  35. data/app/helpers/alchemy/base_helper.rb +14 -0
  36. data/app/helpers/alchemy/elements_helper.rb +10 -5
  37. data/app/helpers/alchemy/pages_helper.rb +1 -2
  38. data/app/helpers/alchemy/url_helper.rb +43 -24
  39. data/app/models/alchemy/element.rb +23 -16
  40. data/app/models/alchemy/page.rb +25 -14
  41. data/app/models/alchemy/picture.rb +24 -0
  42. data/app/views/alchemy/admin/contents/create.js.erb +1 -1
  43. data/app/views/alchemy/admin/elements/_new_element_form.html.erb +1 -1
  44. data/app/views/alchemy/admin/elements/create.js.erb +11 -3
  45. data/app/views/alchemy/admin/elements/fold.js.erb +1 -1
  46. data/app/views/alchemy/admin/elements/new.html.erb +1 -1
  47. data/app/views/alchemy/admin/elements/update.js.erb +1 -1
  48. data/app/views/alchemy/admin/essence_pictures/crop.html.erb +1 -1
  49. data/app/views/alchemy/admin/languages/_form.html.erb +1 -1
  50. data/app/views/alchemy/admin/pages/_new_page_form.html.erb +1 -1
  51. data/app/views/alchemy/admin/pages/_page.html.erb +1 -1
  52. data/app/views/alchemy/admin/pages/configure.html.erb +10 -6
  53. data/app/views/alchemy/admin/pages/configure_external.html.erb +1 -1
  54. data/app/views/alchemy/admin/pages/edit.html.erb +1 -2
  55. data/app/views/alchemy/admin/pages/new.html.erb +2 -2
  56. data/app/views/alchemy/admin/pages/update.js.erb +10 -2
  57. data/app/views/alchemy/admin/partials/_sub_navigation_tab.html.erb +5 -5
  58. data/app/views/alchemy/admin/pictures/_filter_bar.html.erb +2 -1
  59. data/app/views/alchemy/admin/pictures/_picture.html.erb +2 -2
  60. data/app/views/alchemy/admin/pictures/_picture_to_assign.html.erb +2 -1
  61. data/app/views/alchemy/admin/pictures/show_in_window.html.erb +3 -2
  62. data/app/views/alchemy/admin/resources/_form.html.erb +1 -1
  63. data/app/views/alchemy/admin/users/_table.html.erb +4 -4
  64. data/app/views/alchemy/admin/users/edit.html.erb +1 -1
  65. data/app/views/alchemy/admin/users/new.html.erb +1 -1
  66. data/app/views/alchemy/base/error_notice.js.erb +1 -1
  67. data/app/views/alchemy/base/remote_errors.js.erb +2 -3
  68. data/app/views/alchemy/essences/_essence_picture_editor.html.erb +10 -7
  69. data/app/views/alchemy/essences/_essence_picture_view.html.erb +24 -21
  70. data/app/views/layouts/alchemy/admin.html.erb +9 -31
  71. data/bin/alchemy +20 -24
  72. data/config/alchemy/config.yml +6 -0
  73. data/config/alchemy/page_layouts.yml +2 -0
  74. data/config/authorization_rules.rb +1 -1
  75. data/config/locales/alchemy.de.yml +3 -0
  76. data/config/locales/alchemy.en.yml +4 -1
  77. data/db/migrate/20121026100815_alchemy_two_point_three.rb +312 -0
  78. data/lib/alchemy/mount_point.rb +9 -3
  79. data/lib/alchemy/page_layout.rb +89 -73
  80. data/lib/alchemy/version.rb +1 -1
  81. data/lib/rails/generators/alchemy/deploy_script/deploy_script_generator.rb +45 -12
  82. data/lib/rails/generators/alchemy/deploy_script/templates/deploy.rb.tt +3 -1
  83. data/lib/rails/generators/alchemy/essence/essence_generator.rb +51 -0
  84. data/lib/rails/generators/alchemy/essence/templates/editor.html.erb +18 -0
  85. data/lib/rails/generators/alchemy/essence/templates/view.html.erb +2 -0
  86. data/lib/rails/templates/alchemy.rb +1 -1
  87. data/lib/tasks/install.rake +57 -2
  88. data/spec/controllers/admin/elements_controller_spec.rb +170 -22
  89. data/spec/controllers/admin/trash_controller_spec.rb +1 -1
  90. data/spec/controllers/admin/users_controller_spec.rb +36 -0
  91. data/spec/controllers/base_controller_spec.rb +12 -1
  92. data/spec/controllers/elements_controller_spec.rb +17 -13
  93. data/spec/controllers/pictures_controller_spec.rb +4 -4
  94. data/spec/dummy/config/application.rb +1 -1
  95. data/spec/dummy/db/migrate/20121026100815_alchemy_two_point_three.rb +312 -0
  96. data/spec/dummy/db/migrate/20121026104128_create_events.rb +19 -0
  97. data/spec/dummy/db/schema.rb +1 -1
  98. data/spec/factories.rb +0 -1
  99. data/spec/helpers/base_helper_spec.rb +48 -0
  100. data/spec/helpers/elements_helper_spec.rb +14 -3
  101. data/spec/helpers/url_helper_spec.rb +8 -3
  102. data/spec/integration/picture_security_spec.rb +35 -0
  103. data/spec/integration/translation_integration_spec.rb +6 -5
  104. data/spec/models/element_spec.rb +5 -5
  105. data/spec/models/page_layout_spec.rb +10 -16
  106. data/spec/models/page_spec.rb +25 -2
  107. data/spec/models/picture_spec.rb +24 -2
  108. data/spec/routing_spec.rb +115 -115
  109. data/spec/support/alchemy/specs_helpers.rb +4 -4
  110. data/{app/assets/images/alchemy → vendor/assets/images}/Jcrop.gif +0 -0
  111. data/vendor/assets/javascripts/jquery_plugins/jquery.Jcrop.min.js +19 -243
  112. data/vendor/assets/javascripts/jquery_plugins/jquery.selectboxit.min.js +1 -0
  113. data/vendor/assets/javascripts/jquery_plugins/jquery.ui.tabspaging.js +6 -6
  114. data/vendor/assets/stylesheets/jquery.Jcrop.min.css +28 -0
  115. metadata +48 -82
  116. data/app/assets/javascripts/alchemy/alchemy.buttons.js +0 -50
  117. data/app/assets/stylesheets/alchemy/jquery.Jcrop.css.scss +0 -54
  118. data/app/helpers/alchemy/pictures_helper.rb +0 -19
  119. data/db/migrate/20100607143125_create_pages.rb +0 -34
  120. data/db/migrate/20100607144254_create_elements.rb +0 -20
  121. data/db/migrate/20100607145256_create_contents.rb +0 -18
  122. data/db/migrate/20100607145719_create_users.rb +0 -32
  123. data/db/migrate/20100607150611_create_pictures.rb +0 -16
  124. data/db/migrate/20100607150812_create_attachments.rb +0 -16
  125. data/db/migrate/20100607153647_create_folded_pages.rb +0 -13
  126. data/db/migrate/20100607161345_create_essence_texts.rb +0 -19
  127. data/db/migrate/20100607162339_create_elements_pages.rb +0 -12
  128. data/db/migrate/20100607193638_create_essence_pictures.rb +0 -23
  129. data/db/migrate/20100607193646_create_essence_richtexts.rb +0 -16
  130. data/db/migrate/20100607193653_create_essence_htmls.rb +0 -13
  131. data/db/migrate/20100609111653_create_essence_dates.rb +0 -13
  132. data/db/migrate/20100609111809_create_essence_files.rb +0 -15
  133. data/db/migrate/20100609111821_create_essence_flashes.rb +0 -16
  134. data/db/migrate/20100609111837_create_essence_videos.rb +0 -18
  135. data/db/migrate/20100616150753_create_essence_audios.rb +0 -17
  136. data/db/migrate/20100812085225_add_crop_from_and_crop_size_to_essence_pictures.rb +0 -11
  137. data/db/migrate/20100909140701_change_essence_htmls_source_column_type.rb +0 -9
  138. data/db/migrate/20101109150312_alter_pages_visible_column_default.rb +0 -9
  139. data/db/migrate/20101109151812_create_languages.rb +0 -19
  140. data/db/migrate/20101216151419_add_language_id_to_pages.rb +0 -27
  141. data/db/migrate/20101216155216_add_index_to_languages.rb +0 -9
  142. data/db/migrate/20101216173323_add_default_to_languages.rb +0 -9
  143. data/db/migrate/20101218130049_add_urlname_index_to_pages.rb +0 -9
  144. data/db/migrate/20110115123343_remove_css_class_default_from_essence_pictures.rb +0 -11
  145. data/db/migrate/20110224105120_change_pages_visible_default.rb +0 -11
  146. data/db/migrate/20110228182659_remove_default_page_layout_from_pages.rb +0 -11
  147. data/db/migrate/20110414163140_remove_display_name_from_elements.rb +0 -11
  148. data/db/migrate/20110511100516_rename_essence_texts_title_to_link_title.rb +0 -9
  149. data/db/migrate/20110529130429_create_cells.rb +0 -14
  150. data/db/migrate/20110529130500_add_cell_id_to_elements.rb +0 -11
  151. data/db/migrate/20110530102804_change_pages_page_layout_column.rb +0 -11
  152. data/db/migrate/20110707190728_add_render_size_to_essence_pictures.rb +0 -9
  153. data/db/migrate/20110711142057_change_open_link_in_new_window_to_link_target.rb +0 -19
  154. data/db/migrate/20110919110451_add_default_role_to_users.rb +0 -9
  155. data/db/migrate/20111116125112_namespace_alchemy_models.rb +0 -23
  156. data/db/migrate/20120216135355_add_country_code_to_languages.rb +0 -9
  157. data/db/migrate/20120608085509_create_alchemy_essence_selects.rb +0 -11
  158. data/db/migrate/20120611221734_create_alchemy_essence_booleans.rb +0 -11
  159. data/db/migrate/20120704181529_add_upload_hash_to_alchemy_picture.rb +0 -5
  160. data/db/migrate/20120705214247_acts_as_taggable_on_migration.rb +0 -28
  161. data/db/migrate/20120728185830_add_cached_tag_list_to_alchemy_pictures.rb +0 -5
  162. data/db/migrate/20120831135441_set_alchemy_languages_country_code_default_to_empty_string.rb +0 -9
  163. data/spec/helpers/pictures_helper_spec.rb +0 -14
  164. data/vendor/assets/javascripts/jquery_plugins/jquery.selectBoxIt.js +0 -1909
@@ -1,17 +0,0 @@
1
- class CreateEssenceAudios < ActiveRecord::Migration
2
- def self.up
3
- create_table :essence_audios do |t|
4
- t.integer :attachment_id
5
- t.integer :width, :default => 400
6
- t.integer :height, :default => 300
7
- t.boolean :show_eq, :default => true
8
- t.boolean :show_navigation, :default => true
9
- t.userstamps
10
- t.timestamps
11
- end
12
- end
13
-
14
- def self.down
15
- drop_table :essence_audios
16
- end
17
- end
@@ -1,11 +0,0 @@
1
- class AddCropFromAndCropSizeToEssencePictures < ActiveRecord::Migration
2
- def self.up
3
- add_column :essence_pictures, :crop_from, :string
4
- add_column :essence_pictures, :crop_size, :string
5
- end
6
-
7
- def self.down
8
- remove_column :essence_pictures, :crop_size
9
- remove_column :essence_pictures, :crop_from
10
- end
11
- end
@@ -1,9 +0,0 @@
1
- class ChangeEssenceHtmlsSourceColumnType < ActiveRecord::Migration
2
- def self.up
3
- change_column :essence_htmls, :source, :text
4
- end
5
-
6
- def self.down
7
- change_column :essence_htmls, :source, :string
8
- end
9
- end
@@ -1,9 +0,0 @@
1
- class AlterPagesVisibleColumnDefault < ActiveRecord::Migration
2
- def self.up
3
- change_column_default :pages, :visible, true
4
- end
5
-
6
- def self.down
7
- change_column_default :pages, :visible, false
8
- end
9
- end
@@ -1,19 +0,0 @@
1
- class CreateLanguages < ActiveRecord::Migration
2
-
3
- def self.up
4
- create_table :languages do |t|
5
- t.string :name
6
- t.string :code
7
- t.string :frontpage_name
8
- t.string :page_layout, :default => 'intro'
9
- t.boolean :public, :default => false
10
- t.timestamps
11
- t.userstamps
12
- end
13
- end
14
-
15
- def self.down
16
- drop_table :languages
17
- end
18
-
19
- end
@@ -1,27 +0,0 @@
1
- class AddLanguageIdToPages < ActiveRecord::Migration
2
- def self.up
3
- add_column :pages, :language_id, :integer
4
- rename_column :pages, :language, :language_code
5
- rename_column :pages, :language_root_for, :language_root
6
- # PostgreSQL does not support changing string columns to boolean.
7
- # We do not have existing Alchemy installations running on postgresql to support anyway,
8
- # so it's not critical to recreate the column.
9
- if ActiveRecord::Base.connection_config[:adapter] == "postgresql"
10
- remove_column :pages, :language_root
11
- add_column :pages, :language_root, :boolean
12
- else
13
- change_column :pages, :language_root, :boolean
14
- execute("UPDATE pages SET language_root = 1 WHERE language_root IS NOT NULL")
15
- end
16
- add_index :pages, :language_id
17
- end
18
-
19
- def self.down
20
- remove_index :pages, :language_id
21
- change_column :pages, :language_root, :string
22
- rename_column :pages, :language_root, :language_root_for
23
- execute("UPDATE pages SET language_root_for = 1 WHERE language_root_for IS NOT NULL")
24
- rename_column :pages, :language_code, :language
25
- remove_column :pages, :language_id
26
- end
27
- end
@@ -1,9 +0,0 @@
1
- class AddIndexToLanguages < ActiveRecord::Migration
2
- def self.up
3
- add_index :languages, :code
4
- end
5
-
6
- def self.down
7
- remove_index :languages, :code
8
- end
9
- end
@@ -1,9 +0,0 @@
1
- class AddDefaultToLanguages < ActiveRecord::Migration
2
- def self.up
3
- add_column :languages, :default, :boolean, :default => false
4
- end
5
-
6
- def self.down
7
- remove_column :languages, :default
8
- end
9
- end
@@ -1,9 +0,0 @@
1
- class AddUrlnameIndexToPages < ActiveRecord::Migration
2
- def self.up
3
- add_index :pages, :urlname
4
- end
5
-
6
- def self.down
7
- remove_index :pages, :urlname
8
- end
9
- end
@@ -1,11 +0,0 @@
1
- class RemoveCssClassDefaultFromEssencePictures < ActiveRecord::Migration
2
-
3
- def self.up
4
- change_column_default :essence_pictures, :css_class, nil
5
- end
6
-
7
- def self.down
8
- change_column_default :essence_pictures, :css_class, "no_float"
9
- end
10
-
11
- end
@@ -1,11 +0,0 @@
1
- class ChangePagesVisibleDefault < ActiveRecord::Migration
2
-
3
- def self.up
4
- change_column_default :pages, :visible, false
5
- end
6
-
7
- def self.down
8
- change_column_default :pages, :visible, true
9
- end
10
-
11
- end
@@ -1,11 +0,0 @@
1
- class RemoveDefaultPageLayoutFromPages < ActiveRecord::Migration
2
-
3
- def self.up
4
- change_column_default :pages, :page_layout, nil
5
- end
6
-
7
- def self.down
8
- change_column_default :pages, :page_layout, 'standard'
9
- end
10
-
11
- end
@@ -1,11 +0,0 @@
1
- class RemoveDisplayNameFromElements < ActiveRecord::Migration
2
-
3
- def self.up
4
- remove_column :elements, :display_name
5
- end
6
-
7
- def self.down
8
- add_column :elements, :display_name, :string
9
- end
10
-
11
- end
@@ -1,9 +0,0 @@
1
- class RenameEssenceTextsTitleToLinkTitle < ActiveRecord::Migration
2
- def self.up
3
- rename_column :essence_texts, :title, :link_title
4
- end
5
-
6
- def self.down
7
- rename_column :essence_texts, :link_title, :title
8
- end
9
- end
@@ -1,14 +0,0 @@
1
- class CreateCells < ActiveRecord::Migration
2
- def self.up
3
- create_table :cells do |t|
4
- t.integer :page_id
5
- t.string :name
6
-
7
- t.timestamps
8
- end
9
- end
10
-
11
- def self.down
12
- drop_table :cells
13
- end
14
- end
@@ -1,11 +0,0 @@
1
- class AddCellIdToElements < ActiveRecord::Migration
2
-
3
- def self.up
4
- add_column :elements, :cell_id, :integer
5
- end
6
-
7
- def self.down
8
- remove_column :elements, :cell_id
9
- end
10
-
11
- end
@@ -1,11 +0,0 @@
1
- class ChangePagesPageLayoutColumn < ActiveRecord::Migration
2
-
3
- def self.up
4
- change_column :pages, :page_layout, :string, :null => true
5
- end
6
-
7
- def self.down
8
- change_column :pages, :page_layout, :string, :null => false
9
- end
10
-
11
- end
@@ -1,9 +0,0 @@
1
- class AddRenderSizeToEssencePictures < ActiveRecord::Migration
2
- def self.up
3
- add_column :essence_pictures, :render_size, :string
4
- end
5
-
6
- def self.down
7
- remove_column :essence_pictures, :render_size
8
- end
9
- end
@@ -1,19 +0,0 @@
1
- class ChangeOpenLinkInNewWindowToLinkTarget < ActiveRecord::Migration
2
- def self.up
3
- change_column :essence_pictures, :open_link_in_new_window, :string
4
- change_column :essence_texts, :open_link_in_new_window, :string
5
- rename_column :essence_pictures, :open_link_in_new_window, :link_target
6
- rename_column :essence_texts, :open_link_in_new_window, :link_target
7
- change_column_default :essence_pictures, :link_target, nil
8
- change_column_default :essence_texts, :link_target, nil
9
- end
10
-
11
- def self.down
12
- change_column_default :essence_texts, :link_target, 0
13
- change_column_default :essence_pictures, :link_target, 0
14
- rename_column :essence_texts, :link_target, :open_link_in_new_window
15
- rename_column :essence_pictures, :link_target, :open_link_in_new_window
16
- change_column :essence_texts, :open_link_in_new_window, :boolean
17
- change_column :essence_pictures, :open_link_in_new_window, :boolean
18
- end
19
- end
@@ -1,9 +0,0 @@
1
- class AddDefaultRoleToUsers < ActiveRecord::Migration
2
- def self.up
3
- change_column_default :users, :role, "registered"
4
- end
5
-
6
- def self.down
7
- change_column_default :users, :role, nil
8
- end
9
- end
@@ -1,23 +0,0 @@
1
- class NamespaceAlchemyModels < ActiveRecord::Migration
2
- def change
3
- rename_table :attachments, :alchemy_attachments
4
- rename_table :cells, :alchemy_cells
5
- rename_table :contents, :alchemy_contents
6
- rename_table :elements, :alchemy_elements
7
- rename_table :elements_pages, :alchemy_elements_alchemy_pages
8
- rename_table :essence_audios, :alchemy_essence_audios
9
- rename_table :essence_dates, :alchemy_essence_dates
10
- rename_table :essence_files, :alchemy_essence_files
11
- rename_table :essence_flashes, :alchemy_essence_flashes
12
- rename_table :essence_htmls, :alchemy_essence_htmls
13
- rename_table :essence_pictures, :alchemy_essence_pictures
14
- rename_table :essence_richtexts, :alchemy_essence_richtexts
15
- rename_table :essence_texts, :alchemy_essence_texts
16
- rename_table :essence_videos, :alchemy_essence_videos
17
- rename_table :folded_pages, :alchemy_folded_pages
18
- rename_table :languages, :alchemy_languages
19
- rename_table :pages, :alchemy_pages
20
- rename_table :pictures, :alchemy_pictures
21
- rename_table :users, :alchemy_users
22
- end
23
- end
@@ -1,9 +0,0 @@
1
- class AddCountryCodeToLanguages < ActiveRecord::Migration
2
- def change
3
- add_column :alchemy_languages, :country_code, :string
4
- rename_column :alchemy_languages, :code, :language_code
5
- remove_index :alchemy_languages, :name => :index_languages_on_code
6
- add_index :alchemy_languages, :language_code
7
- add_index :alchemy_languages, [:language_code, :country_code]
8
- end
9
- end
@@ -1,11 +0,0 @@
1
- class CreateAlchemyEssenceSelects < ActiveRecord::Migration
2
- def change
3
- create_table :alchemy_essence_selects do |t|
4
- t.string :value
5
-
6
- t.timestamps
7
- t.userstamps
8
- end
9
- add_index :alchemy_essence_selects, :value
10
- end
11
- end
@@ -1,11 +0,0 @@
1
- class CreateAlchemyEssenceBooleans < ActiveRecord::Migration
2
- def change
3
- create_table :alchemy_essence_booleans do |t|
4
- t.boolean :value
5
-
6
- t.timestamps
7
- t.userstamps
8
- end
9
- add_index :alchemy_essence_booleans, :value
10
- end
11
- end
@@ -1,5 +0,0 @@
1
- class AddUploadHashToAlchemyPicture < ActiveRecord::Migration
2
- def change
3
- add_column :alchemy_pictures, :upload_hash, :string
4
- end
5
- end
@@ -1,28 +0,0 @@
1
- class ActsAsTaggableOnMigration < ActiveRecord::Migration
2
- def self.up
3
- create_table :tags do |t|
4
- t.string :name
5
- end
6
-
7
- create_table :taggings do |t|
8
- t.references :tag
9
-
10
- # You should make sure that the column created is
11
- # long enough to store the required class names.
12
- t.references :taggable, :polymorphic => true
13
- t.references :tagger, :polymorphic => true
14
-
15
- t.string :context
16
-
17
- t.datetime :created_at
18
- end
19
-
20
- add_index :taggings, :tag_id
21
- add_index :taggings, [:taggable_id, :taggable_type, :context]
22
- end
23
-
24
- def self.down
25
- drop_table :taggings
26
- drop_table :tags
27
- end
28
- end
@@ -1,5 +0,0 @@
1
- class AddCachedTagListToAlchemyPictures < ActiveRecord::Migration
2
- def change
3
- add_column :alchemy_pictures, :cached_tag_list, :string
4
- end
5
- end
@@ -1,9 +0,0 @@
1
- class SetAlchemyLanguagesCountryCodeDefaultToEmptyString < ActiveRecord::Migration
2
- def up
3
- change_column :alchemy_languages, :country_code, :string, :default => '', :null => false
4
- end
5
-
6
- def down
7
- change_column :alchemy_languages, :country_code, :string, :default => nil, :null => true
8
- end
9
- end
@@ -1,14 +0,0 @@
1
- require "spec_helper"
2
-
3
- describe Alchemy::PicturesHelper do
4
-
5
- describe "alchemy_picture_path" do
6
-
7
- it "should route to show_picture_path" do
8
- pic = mock_model("Picture", :urlname => 'cute-kitten', :id => 1)
9
- helper.alchemy_picture_path(pic).should == '/alchemy/pictures/1/show/cute-kitten.jpg'
10
- end
11
-
12
- end
13
-
14
- end
@@ -1,1909 +0,0 @@
1
- /* jquery Selectboxit - v0.9.0 - 2012-05-21
2
- * http://www.gregfranko.com/jQuery.selectBoxIt.js/
3
- * Copyright (c) 2012 Greg Franko; Licensed MIT */
4
-
5
- // Immediately-Invoked Function Expression (IIFE) [Ben Alman Blog Post](http://benalman.com/news/2010/11/immediately-invoked-function-expression/) that calls another IIFE that contains all of the plugin logic. I used this pattern so that anyone viewing this code would not have to scroll to the bottom of the page to view the local parameters that were passed to the main IIFE.
6
-
7
- (function (selectBoxIt) {
8
-
9
- //ECMAScript 5 Strict Mode: [John Resig Blog Post](http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/)
10
- "use strict";
11
-
12
- // Calls the second IIFE and locally passes in the global jQuery, window, and document objects
13
- selectBoxIt(jQuery, window, document);
14
-
15
- }
16
-
17
- // Locally passes in `jQuery`, the `window` object, the `document` object, and an `undefined` variable. The `jQuery`, `window` and `document` objects are passed in locally, to improve performance, since javascript first searches for a variable match within the local variables set before searching the global variables set. All of the global variables are also passed in locally to be minifier friendly. `undefined` can be passed in locally, because it is not a reserved word in JavaScript.
18
-
19
- (function ($, window, document, undefined) {
20
-
21
- // ECMAScript 5 Strict Mode: [John Resig Blog Post](http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/)
22
- "use strict";
23
-
24
- // Calling the jQueryUI Widget Factory Method
25
- $.widget("selectBox.selectBoxIt", {
26
-
27
- // Plugin version
28
-
29
- version: "0.9.0",
30
-
31
- // These options will be used as defaults
32
- options: {
33
-
34
- // **showEffect**: Accepts String: "none", "fadeIn", "show", "slideDown", or any of the jQueryUI show effects (i.e. "bounce")
35
- showEffect: "none",
36
-
37
- // **showEffectOptions**: Accepts an object literal. All of the available properties are based on the jqueryUI effect options
38
- showEffectOptions: {},
39
-
40
- // **showEffectSpeed**: Accepts Number (milliseconds) or String: "slow", "medium", or "fast"
41
- showEffectSpeed: "medium",
42
-
43
- // **hideEffect**: Accepts String: "none", "fadeOut", "hide", "slideUp", or any of the jQueryUI hide effects (i.e. "explode")
44
- hideEffect: "none",
45
-
46
- // **hideEffectOptions**: Accepts an object literal. All of the available properties are based on the jqueryUI effect options
47
- hideEffectOptions: {},
48
-
49
- // **hideEffectSpeed**: Accepts Number (milliseconds) or String: "slow", "medium", or "fast"
50
- hideEffectSpeed: "medium",
51
-
52
- // **showFirstOption**: Shows the first dropdown list option within the dropdown list options list
53
- showFirstOption: true,
54
-
55
- // **defaultText**: Overrides the text used by the dropdown list selected option to allow a user to specify custom text. Accepts a String.
56
- defaultText: "",
57
-
58
- // **defaultIcon**: Overrides the icon used by the dropdown list selected option to allow a user to specify a custom icon. Accepts a String (CSS class name(s)).
59
- defaultIcon: "",
60
-
61
- // **downArrowIcon**: Overrides the default down arrow used by the dropdown list to allow a user to specify a custom image. Accepts a String (CSS class name(s)).
62
- downArrowIcon: ""
63
-
64
- },
65
-
66
- // _Create
67
- // -------
68
- // Sets the Plugin Instance variables and
69
- // constructs the plugin. Only called once.
70
- _create: function() {
71
-
72
- // The original select box DOM element
73
- this.originalElem = this.element[0];
74
-
75
- // The original select box DOM element wrapped in a jQuery object
76
- this.selectBox = this.element;
77
-
78
- // All of the original select box options
79
- this.selectItems = this.element.find("option");
80
-
81
- // The first option in the original select box
82
- this.firstSelectItem = this.element.find("option").slice(0, 1);
83
-
84
- // The index of the currently selected dropdown list option
85
- this.currentFocus = 0;
86
-
87
- // Keeps track of which blur events will hide the dropdown list options
88
- this.blur = true;
89
-
90
- // The html document height
91
- this.documentHeight = $(document).height();
92
-
93
- // Array holding all of the original select box options text
94
- this.textArray = [];
95
-
96
- // Maintains search order in the `search` method
97
- this.currentIndex = 0;
98
-
99
- // Whether or not the dropdown list opens up or down (depending on how much room is on the page)
100
- this.flipped = false;
101
-
102
- // Creates the div elements that will become the dropdown
103
- this._createDiv();
104
-
105
- // Creates the ul element that will become the dropdown options list
106
- this._createUnorderedList();
107
-
108
- // Hides the original select box and adds the new plugin DOM elements to the page
109
- this._replaceSelectBox();
110
-
111
- // Adds event handlers to the new dropdown list
112
- this._eventHandlers();
113
-
114
- if(this.originalElem.disabled && this.disable) {
115
-
116
- // Disables the dropdown list if the original dropdown list had the `disabled` attribute
117
- this.disable();
118
-
119
- }
120
-
121
- if(this._ariaAccessibility) {
122
-
123
- // Adds ARIA accessibillity tags to the dropdown list
124
- this._ariaAccessibility();
125
-
126
- }
127
-
128
- // Adds jQueryUI classes to the dropdown list if the jqueryUI option is set to true
129
- this._addClasses();
130
-
131
- // Focus the selectbox div, if the original select tag has autofocus attribute
132
- if (this.selectBox.attr("autofocus")) {
133
-
134
- this.div.focus();
135
-
136
- }
137
-
138
- // Triggers a custom `create` event on the original dropdown list
139
- this.selectBox.trigger("create");
140
-
141
- },
142
- // _Create Div
143
- // -----------
144
- // Creates new div and span elements to replace
145
- // the original select box with a dropdown list
146
- _createDiv: function() {
147
-
148
- // Creates a span element that contains the dropdown list text value
149
- this.divText = $("<span/>", {
150
-
151
- // Dynamically sets the span `id` attribute
152
- "id": this.originalElem.id + "SelectBoxItText",
153
-
154
- "class": "selectboxit-text",
155
-
156
- // IE specific attribute to not allow the element to be selected
157
- "unselectable": "on",
158
-
159
- // Sets the span `text` to equal the original select box default value
160
- "text": this.firstSelectItem.text()
161
-
162
- }).
163
-
164
- // Sets the HTML5 data attribute on the divText `span` element
165
- attr("data-val", this.originalElem.value);
166
-
167
- // Creates a span element that contains the dropdown list text value
168
- this.divImage = $("<span/>", {
169
-
170
- // Dynamically sets the span `id` attribute
171
- "id": this.originalElem.id + "SelectBoxItDefaultIcon",
172
-
173
- "class": "selectboxit-default-icon",
174
-
175
- // IE specific attribute to not allow the element to be selected
176
- "unselectable": "on"
177
-
178
- });
179
-
180
- // Creates a div to act as the new dropdown list
181
- this.div = $("<div/>", {
182
-
183
- // Dynamically sets the div `id` attribute
184
- "id": this.originalElem.id + "SelectBoxIt",
185
-
186
- "class": "selectboxit" + (this.originalElem.className !== "" ? " " + this.originalElem.className : ""),
187
-
188
- // Sets the div `name` attribute to be the same name as the original select box
189
- "name": this.originalElem.name,
190
-
191
- // Sets the div `tabindex` attribute to 0 to allow the div to be focusable
192
- "tabindex": 0,
193
-
194
- // IE specific attribute to not allow the element to be selected
195
- "unselectable": "on"
196
-
197
- }).
198
-
199
- // Appends the default text to the inner dropdown list div element
200
- append(this.divImage).append(this.divText);
201
-
202
- // Create the div container that will hold all of the dropdown list dom elements
203
- this.divContainer = $("<div/>", {
204
-
205
- "id": this.originalElem.id + "SelectBoxItContainer",
206
-
207
- "class": "selectboxit-container"
208
- }).
209
-
210
- // Appends the inner dropdown list div element to the dropdown list container div element
211
- append(this.div);
212
-
213
- // Maintains chainability
214
- return this;
215
- },
216
-
217
- // _Create Unordered List
218
- // ----------------------
219
- // Creates an unordered list element to hold the
220
- // new dropdown list options that directly match
221
- // the values of the original select box options
222
- _createUnorderedList: function() {
223
-
224
- // Storing the context of the widget
225
- var self = this,
226
-
227
- dataDisabled,
228
-
229
- optgroupClass = "",
230
-
231
- optgroupElement = "",
232
-
233
- iconClass,
234
-
235
- // Declaring the variable that will hold all of the dropdown list option elements
236
- currentItem = "",
237
- // Creates an unordered list element
238
- createdList = $("<ul/>", {
239
-
240
- // Sets the unordered list `id` attribute
241
- "id": this.originalElem.id + "SelectBoxItOptions",
242
-
243
- "class": "selectboxit-options",
244
-
245
- //Sets the unordered list `tabindex` attribute to -1 to prevent the unordered list from being focusable
246
- "tabindex": -1
247
-
248
- });
249
-
250
- // Checks the `showFirstOption` plugin option to determine if the first dropdown list option should be shown in the options list.
251
- if (!this.options.showFirstOption) {
252
-
253
- // Excludes the first dropdown list option from the options list
254
- this.selectItems = this.selectBox.find("option").slice(1);
255
- }
256
-
257
- // Loops through the original select box options list and copies the text of each
258
- // into new list item elements of the new dropdown list
259
- this.selectItems.each(function(index) {
260
-
261
- dataDisabled = $(this).prop("disabled");
262
-
263
- iconClass = $(this).data("icon") || "";
264
-
265
- // If the current option being traversed is within an optgroup
266
-
267
- if($(this).parent().is("optgroup")) {
268
-
269
- optgroupClass = "selectboxit-optgroup-option";
270
-
271
- if($(this).index() === 0) {
272
-
273
- optgroupElement = '<div class="selectboxit-optgroup-header" data-disabled="true">' + $(this).parent().first().attr("label") + '</div>';
274
-
275
- }
276
-
277
- else {
278
-
279
- optgroupElement = "";
280
-
281
- }
282
-
283
- }
284
-
285
- // If the current option being traversed is not within an optgroup
286
-
287
- else {
288
-
289
- optgroupClass = "";
290
-
291
- }
292
-
293
- // Uses string concatenation instead of append for speed since the number of dropdown list options is unknown.
294
- currentItem += optgroupElement + '<li id="' + index + '" data-val="' + this.value + '" data-disabled="' + dataDisabled + '" class="' + optgroupClass + '"><span class="' + iconClass + '"></span>' + $(this).text() + '</li>';
295
-
296
- // Stores all of the original select box options text inside of an array
297
- // (Used later in the `searchAlgorithm` method)
298
- self.textArray[index] = $(this).text();
299
-
300
- // Checks the original select box option for the `selected` attribute
301
- if (this.selected) {
302
-
303
- //Replace the default text with the selected option
304
- self.divText.text($(this).text());
305
-
306
- //Set the currently selected option
307
- self.currentFocus = index;
308
- }
309
-
310
- });
311
-
312
- // If the `defaultText` option is being used
313
- if (self.options.defaultText) {
314
-
315
- //Overrides the current dropdown default text with the value the user specifies in the `defaultText` option
316
- self.divText.text(self.options.defaultText);
317
- }
318
-
319
- // If the `defaultText` HTML5 data attribute is being used
320
- if (self.selectBox.data("text")) {
321
-
322
- // Overrides the current dropdown default text with the value from the HTML5 `defaultText` value
323
- self.divText.text(self.selectBox.data("text"));
324
- self.options.defaultText = self.selectBox.data("text");
325
-
326
- }
327
-
328
- // Append the list item to the unordered list
329
- createdList.append(currentItem);
330
-
331
- // Stores the dropdown list options list inside of the `list` instance variable
332
- this.list = createdList;
333
-
334
- // Append the dropdown list options list to the div container element
335
- this.divContainer.append(this.list);
336
-
337
- // Stores the individual dropdown list options inside of the `listItems` instance variable
338
- this.listItems = this.list.find("li");
339
-
340
- // Set the disabled CSS class for select box options
341
- this.list.find("li[data-disabled='true']").not(".optgroupHeader").addClass("ui-state-disabled");
342
-
343
- // If the first select box option is disabled, and the user has chosen to not show the first select box option
344
- if (this.currentFocus === 0 && !this.options.showFirstOption && this.listItems.eq(0).hasClass("ui-state-disabled")) {
345
-
346
- //Sets the default value of the dropdown list to the first option that is not disabled
347
- this.currentFocus = +this.listItems.not(".ui-state-disabled").first().attr("id");
348
-
349
- }
350
-
351
- this.divImage.addClass(this.selectBox.data("icon") || this.options.defaultIcon || this.listItems.eq(this.currentFocus).find("span").attr("class"));
352
-
353
- //Maintains chainability
354
- return this;
355
- },
356
-
357
- // _Replace Select Box
358
- // -------------------
359
- // Hides the original dropdown list and inserts
360
- // the new DOM elements
361
- _replaceSelectBox: function() {
362
-
363
- // Hides the original select box
364
- this.selectBox.css("display", "none").
365
-
366
- // Adds the new dropdown list to the page directly after the hidden original select box element
367
- after(this.divContainer);
368
-
369
- // The height of the dropdown list
370
- var height = this.div.height();
371
-
372
- // The down arrow element of the dropdown list
373
- this.downArrow = $("<span/>", {
374
-
375
- // Dynamically sets the span `id` attribute of the dropdown list down arrow
376
- "id": this.originalElem.id + "SelectBoxItArrow",
377
-
378
- "class": "selectboxit-arrow",
379
-
380
- // IE specific attribute to not allow the dropdown list text to be selected
381
- "unselectable": "on"
382
-
383
- });
384
-
385
- // The down arrow container element of the dropdown list
386
- this.downArrowContainer = $("<span/>", {
387
-
388
- // Dynamically sets the span `id` attribute for the down arrow container element
389
- "id": this.originalElem.id + "SelectBoxItArrowContainer",
390
-
391
- "class": "selectboxit-arrow-container",
392
-
393
- // IE specific attribute to not allow the dropdown list text to be selected
394
- "unselectable": "on",
395
-
396
- // The dynamic CSS of the down arrow container element
397
- "style": "height:" + height + "px;"
398
-
399
- }).
400
-
401
- // Inserts the down arrow element inside of the down arrow container element
402
- append(this.downArrow);
403
-
404
- // Appends the down arrow element to the dropdown list
405
- this.div.append(this.downArrowContainer);
406
-
407
- this.divImage.css({
408
-
409
- "margin-top": height / 4
410
-
411
- });
412
-
413
- this.listItems.find("span").css({
414
-
415
- "margin-top": height / 4
416
-
417
- });
418
-
419
- // Maintains chainability
420
- return this;
421
- },
422
-
423
- // _Scroll-To-View
424
- // ---------------
425
- // Updates the dropdown list scrollTop value
426
- _scrollToView: function(type) {
427
-
428
- // The current scroll positioning of the dropdown list options list
429
- var listScrollTop = this.list.scrollTop(),
430
-
431
- // The height of the currently selected dropdown list option
432
- currentItemHeight = this.listItems.eq(this.currentFocus).height(),
433
-
434
- // The relative distance from the currently selected dropdown list option to the the top of the dropdown list options list
435
- currentTopPosition = this.listItems.eq(this.currentFocus).position().top,
436
-
437
- // The height of the dropdown list option list
438
- listHeight = this.list.height();
439
-
440
- // Scrolling logic for a text search
441
- if (type === "search") {
442
-
443
- // Increases the dropdown list options `scrollTop` if a user is searching for an option
444
- // below the currently selected option that is not visible
445
- if (listHeight - currentTopPosition < currentItemHeight) {
446
-
447
- // The selected option will be shown at the very bottom of the visible options list
448
- this.list.scrollTop(listScrollTop + (currentTopPosition - (listHeight - currentItemHeight)));
449
-
450
- }
451
-
452
- // Decreases the dropdown list options `scrollTop` if a user is searching for an option above the currently selected option that is not visible
453
- else if (currentTopPosition < -1) {
454
-
455
- this.list.scrollTop(currentTopPosition - currentItemHeight);
456
-
457
- }
458
- }
459
-
460
- // Scrolling logic for the `up` keyboard navigation
461
- else if (type === "up") {
462
-
463
- // Decreases the dropdown list option list `scrollTop` if a user is navigating to an element that is not visible
464
- if (currentTopPosition < -1) {
465
-
466
- this.list.scrollTop(listScrollTop - Math.abs(this.listItems.eq(this.currentFocus).position().top));
467
-
468
- }
469
- }
470
-
471
- // Scrolling logic for the `down` keyboard navigation
472
- else if (type === "down") {
473
-
474
- // Increases the dropdown list options `scrollTop` if a user is navigating to an element that is not fully visible
475
- if (listHeight - currentTopPosition < currentItemHeight) {
476
-
477
- // Increases the dropdown list options `scrollTop` by the height of the current option item.
478
- this.list.scrollTop((listScrollTop + (Math.abs(this.listItems.eq(this.currentFocus).position().top) - listHeight + currentItemHeight)));
479
-
480
- }
481
- }
482
-
483
- // Maintains chainability
484
- return this;
485
- },
486
-
487
- // _Callback
488
- // ---------
489
- // Call the function passed into the method
490
- _callbackSupport: function(callback) {
491
-
492
- // Checks to make sure the parameter passed in is a function
493
- if ($.isFunction(callback)) {
494
-
495
- // Calls the method passed in as a parameter and sets the current `SelectBoxIt` object that is stored in the jQuery data method as the context(allows for `this` to reference the SelectBoxIt API Methods in the callback function. The `div` DOM element that acts as the new dropdown list is also passed as the only parameter to the callback
496
- callback.call(this.element.data(this.widgetName), this.div);
497
-
498
- }
499
- },
500
-
501
- // Open
502
- // ----
503
- // Opens the dropdown list options list
504
- open: function(callback) {
505
-
506
- if(!this.list.is(":visible")) {
507
-
508
- var self = this;
509
-
510
- // Triggers a custom "open" event on the original select box
511
- this.selectBox.trigger("open");
512
-
513
- if (this._dynamicPositioning) {
514
- // Dynamically positions the dropdown list options list
515
- this._dynamicPositioning();
516
- }
517
-
518
- // Determines what jQuery effect to use when opening the dropdown list options list
519
- switch (this.options.showEffect) {
520
-
521
- // Uses `no effect`
522
- case "none":
523
-
524
- // Does not require a callback function because this animation will complete before the call to `scrollToView`
525
- this.list.show();
526
-
527
- // Updates the list `scrollTop` attribute
528
- this._scrollToView("search");
529
-
530
- break;
531
-
532
- // Uses the jQuery `show` special effect
533
- case "show":
534
-
535
- // Requires a callback function to determine when the `show` animation is complete
536
- this.list.show(this.options.showEffectSpeed, function() {
537
-
538
- // Updates the list `scrollTop` attribute
539
- self._scrollToView("search");
540
-
541
- });
542
-
543
- break;
544
-
545
- // Uses the jQuery `slideDown` special effect
546
- case "slideDown":
547
-
548
- // Requires a callback function to determine when the `slideDown` animation is complete
549
- this.list.slideDown(this.options.showEffectSpeed, function() {
550
-
551
- // Updates the list `scrollTop` attribute
552
- self._scrollToView("search");
553
-
554
- });
555
-
556
- break;
557
-
558
- // Uses the jQuery `fadeIn` special effect
559
- case "fadeIn":
560
-
561
- // Does not require a callback function because this animation will complete before the call to `scrollToView`
562
- this.list.fadeIn(this.options.showEffectSpeed);
563
-
564
- // Updates the list `scrollTop` attribute
565
- this._scrollToView("search");
566
-
567
- break;
568
-
569
- // If none of the above options were passed, then a `jqueryUI show effect` is expected
570
- default:
571
-
572
- // Allows for custom show effects via the [jQueryUI core effects](http://http://jqueryui.com/demos/show/)
573
- this.list.show(this.options.showEffect, this.options.showEffectOptions, this.options.showEffectSpeed, function() {
574
-
575
- // Updates the list `scrollTop` attribute
576
- self._scrollToView("search");
577
-
578
- });
579
-
580
- break;
581
-
582
- }
583
-
584
- }
585
-
586
- // Provide callback function support
587
- this._callbackSupport(callback);
588
-
589
- // Maintains chainability
590
- return this;
591
- },
592
-
593
- // Close
594
- // -----
595
- // Closes the dropdown list options list
596
- close: function(callback) {
597
-
598
- if(this.list.is(":visible")) {
599
-
600
- var self = this;
601
-
602
- // Triggers a custom "close" event on the original select box
603
- this.selectBox.trigger("close");
604
-
605
- // Determines what jQuery effect to use when closing the dropdown list options list
606
- switch (this.options.hideEffect) {
607
-
608
- // Uses `no effect`
609
- case "none":
610
-
611
- // Does not require a callback function because this animation will complete before the call to `scrollToView`
612
- this.list.hide();
613
-
614
- // Updates the list `scrollTop` attribute
615
- this._scrollToView("search");
616
-
617
- break;
618
-
619
- // Uses the jQuery `hide` special effect
620
- case "hide":
621
-
622
- this.list.hide(this.options.hideEffectSpeed);
623
-
624
- break;
625
-
626
- // Uses the jQuery `slideUp` special effect
627
- case "slideUp":
628
-
629
- this.list.slideUp(this.options.hideEffectSpeed);
630
-
631
- break;
632
-
633
- // Uses the jQuery `fadeOut` special effect
634
- case "fadeOut":
635
-
636
- this.list.fadeOut(this.options.hideEffectSpeed);
637
-
638
- break;
639
-
640
- // If none of the above options were passed, then a `jqueryUI hide effect` is expected
641
- default:
642
-
643
- // Allows for custom hide effects via the [jQueryUI core effects](http://http://jqueryui.com/demos/hide/)
644
- this.list.hide(this.options.hideEffect, this.options.hideEffectOptions, this.options.hideEffectSpeed, function() {
645
-
646
- //Updates the list `scrollTop` attribute
647
- self._scrollToView("search");
648
-
649
- });
650
-
651
- break;
652
- }
653
-
654
- }
655
-
656
- // Provide callback function support
657
- this._callbackSupport(callback);
658
-
659
- // Maintains chainability
660
- return this;
661
- },
662
-
663
-
664
- // _Event Handlers
665
- // ---------------
666
- // Adds event handlers to the new dropdown list
667
- _eventHandlers: function() {
668
-
669
- // LOCAL VARIABLES
670
- var self = this,
671
-
672
- upKey = 38,
673
-
674
- downKey = 40,
675
-
676
- enterKey = 13,
677
-
678
- backspaceKey = 8,
679
-
680
- tabKey = 9,
681
-
682
- spaceKey = 32,
683
-
684
- escKey = 27;
685
-
686
- // Select Box events
687
- this.div.bind({
688
-
689
- // `click` event with the `selectBoxIt` namespace
690
- "click.selectBoxIt": function() {
691
-
692
- if(!self.div.is(":focus")) {
693
-
694
- $(this).focus();
695
-
696
- }
697
-
698
- // The `click` handler logic will only be applied if the dropdown list is enabled
699
- if (!self.originalElem.disabled) {
700
-
701
- // Triggers the `click` event on the original select box
702
- self.selectBox.trigger("click");
703
-
704
- // If the dropdown list options list is visible when a user clicks on the dropdown list
705
- if (self.list.is(":visible")) {
706
-
707
- // Closes the dropdown list options list
708
- self.close();
709
- }
710
-
711
- // If the dropdown list options list is not visible when a user clicks on the dropdown list
712
- else {
713
-
714
- // Shows the dropdown list options list
715
- self.open();
716
- }
717
- }
718
- },
719
-
720
- // `mousedown` event with the `selectBoxIt` namespace
721
- "mousedown.selectBoxIt": function() {
722
-
723
- // Stores data in the jQuery `data` method to help determine if the dropdown list gains focus from a click or tabstop. The mousedown event fires before the focus event.
724
- $(this).data("mdown", true);
725
- },
726
-
727
- // `blur` event with the `selectBoxIt` namespace. Uses special blur logic to make sure the dropdown list closes correctly
728
- "blur.selectBoxIt": function() {
729
-
730
- // If `self.blur` property is true
731
- if (self.blur) {
732
-
733
- // Triggers both the `blur` and `focusout` events on the original select box.
734
- // The `focusout` event was also triggered because the event bubbles
735
- // This event has to be used when using event delegation (such as the jQuery `delegate` or `on` methods)
736
- // Popular open source projects such as Backbone.js utilize event delegation to bind events, so if you are using Backbone.js, use the `focusout` event instead of the `blur` event
737
- self.selectBox.trigger("blur").trigger("focusout");
738
-
739
- //If the dropdown options list is visible
740
- if (self.list.is(":visible")) {
741
- //Closes the dropdown list options list
742
- self.close();
743
- }
744
- }
745
- },
746
-
747
- "focus.selectBoxIt": function() {
748
-
749
- // Stores the data associated with the mousedown event inside of a local variable
750
- var mdown = $(this).data("mdown");
751
-
752
- // Removes the jQuery data associated with the mousedown event
753
- $(this).removeData('mdown');
754
-
755
- // If a mousedown event did not occur and no data was passed to the focus event (this correctly triggers the focus event), then the dropdown list gained focus from a tabstop
756
- if (!mdown) {
757
-
758
- // Triggers the `tabFocus` custom event on the original select box
759
- self.selectBox.trigger("tabFocus");
760
- }
761
-
762
- // Only trigger the `focus` event on the original select box if the dropdown list is hidden (this verifies that only the correct `focus` events are used to trigger the event on the original select box
763
- if(!self.list.is(":visible")) {
764
-
765
- //Triggers the `focus` default event on the original select box
766
- self.selectBox.trigger("focus").trigger("focusin");
767
-
768
- }
769
- },
770
-
771
- // `keydown` event with the `selectBoxIt` namespace. Catches all user keyboard navigations
772
- "keydown.selectBoxIt": function(e) {
773
-
774
- // Stores the `keycode` value in a local variable
775
- var currentKey = e.keyCode;
776
-
777
- // Performs keyboard events if the dropdown list is focused
778
- if (self.div.is(":focus")) {
779
-
780
- // Supports keyboard navigation
781
- switch (currentKey) {
782
-
783
- // If the user presses the `down key`
784
- case downKey:
785
-
786
- // Prevents the page from moving down
787
- e.preventDefault();
788
-
789
- // If the plugin options allow keyboard navigation
790
- if (self.moveDown) {
791
-
792
- //Opens the dropdown list if it's hidden
793
- if (self.list.is(":hidden")) {
794
- self.open();
795
- }
796
-
797
- // Moves the focus down to the dropdown list option directly beneath the currently selected selectbox option
798
- self.moveDown();
799
-
800
- }
801
-
802
- break;
803
-
804
- //If the user presses the `up key`
805
- case upKey:
806
-
807
- // Prevents the page from moving up
808
- e.preventDefault();
809
-
810
- // If the plugin options allow keyboard navgiation
811
- if (self.moveUp) {
812
-
813
- //Opens the dropdown list if it's hidden
814
- if (self.list.is(":hidden")) {
815
- self.open();
816
- }
817
-
818
- // Moves the focus up to the dropdown list option directly above the currently selected selectbox option
819
- self.moveUp();
820
-
821
- }
822
-
823
- break;
824
-
825
- // If the user presses the `enter key`
826
- case enterKey:
827
-
828
- // Prevents the default event from being triggered
829
- e.preventDefault();
830
-
831
- // Checks to see if the dropdown list options list is open
832
- if (self.list.is(":visible")) {
833
-
834
- // Closes the dropdown list options list
835
- self.close();
836
- }
837
-
838
- // If the first dropdown list option is not shown in the options list, and the dropdown list has not been interacted with, then update the dropdown list value when the enter key is pressed
839
- if (!self.options.showFirstOption && self.div.text() === self.firstSelectItem.text() && self.currentFocus === 0 || (self.options.showFirstOption && self.options.defaultText) || (!self.options.showFirstOption && !self.listItems.eq(0).not("[data-disabled='true']"))) {
840
-
841
- // Updates the dropdown list value
842
- self.selectBox.val(self.listItems.eq(self.currentFocus).attr("data-val")).
843
-
844
- // Triggers a `change` event on the original select box
845
- trigger("change");
846
- }
847
-
848
- // Triggers the `enter` events on the original select box
849
- self.selectBox.trigger("enter");
850
-
851
- break;
852
-
853
- // If the user presses the `tab key`
854
- case tabKey:
855
-
856
- // Triggers the custom `tabBlur` events on the original select box
857
- self.selectBox.trigger("tabBlur");
858
-
859
- break;
860
-
861
- // If the user presses the `backspace key`
862
- case backspaceKey:
863
-
864
- // Prevents the browser from navigating to the previous page in its history
865
- e.preventDefault();
866
-
867
- // Triggers the custom `backspace` event on the original select box
868
- self.selectBox.trigger("backspace");
869
-
870
- break;
871
-
872
- // If the user presses the `escape key`
873
- case escKey:
874
-
875
- // Closes the dropdown options list
876
- self.close();
877
-
878
- break;
879
-
880
- // Default is to break out of the switch statement
881
- default:
882
-
883
- break;
884
-
885
- }
886
- }
887
- },
888
-
889
- // `keypress` event with the `selectBoxIt` namespace. Catches all user keyboard text searches since you can only reliably get character codes using the `keypress` event
890
- "keypress.selectBoxIt": function(e) {
891
-
892
- // Performs a text search if the dropdown list is focused
893
- if (self.div.is(":focus")) {
894
-
895
- // Sets the current key to the `keyCode` value if `charCode` does not exist. Used for cross
896
- // browser support since IE uses `keyCode` instead of `charCode`.
897
- var currentKey = e.charCode || e.keyCode,
898
-
899
- // Converts unicode values to characters
900
- alphaNumericKey = String.fromCharCode(currentKey);
901
-
902
- // If the user presses the `space bar`
903
- if (currentKey === spaceKey) {
904
-
905
- // Prevents the browser from scrolling to the bottom of the page
906
- e.preventDefault();
907
- }
908
-
909
- // If the plugin options allow text searches
910
- if (self.search) {
911
-
912
- // Calls `search` and passes the character value of the user's text search
913
- self.search(alphaNumericKey, true, "");
914
- }
915
- }
916
- },
917
-
918
- // `mousenter` event with the `selectBoxIt` namespace .The mouseenter JavaScript event is proprietary to Internet Explorer. Because of the event's general utility, jQuery simulates this event so that it can be used regardless of browser.
919
- "mouseenter.selectBoxIt": function() {
920
-
921
- // Trigger the `mouseenter` event on the original select box
922
- self.selectBox.trigger("mouseenter");
923
- },
924
-
925
- // `mouseleave` event with the `selectBoxIt` namespace. The mouseleave JavaScript event is proprietary to Internet Explorer. Because of the event's general utility, jQuery simulates this event so that it can be used regardless of browser.
926
- "mouseleave.selectBoxIt": function() {
927
-
928
- // Trigger the `mouseleave` event on the original select box
929
- self.selectBox.trigger("mouseleave");
930
- }
931
-
932
- });
933
-
934
- // Select box options events that set the dropdown list blur logic (decides when the dropdown list gets
935
- // closed)
936
- this.list.bind({
937
-
938
- // `mouseover` event with the `selectBoxIt` namespace
939
- "mouseover.selectBoxIt": function() {
940
-
941
- // Prevents the dropdown list options list from closing
942
- self.blur = false;
943
- },
944
-
945
- // `mouseout` event with the `selectBoxIt` namespace
946
- "mouseout.selectBoxIt": function() {
947
-
948
- // Allows the dropdown list options list to close
949
- self.blur = true;
950
- },
951
-
952
- // `focusin` event with the `selectBoxIt` namespace
953
- "focusin.selectBoxIt": function() {
954
-
955
- // Prevents the default browser outline border to flicker, which results because of the `blur` event
956
- self.div.focus();
957
- }
958
-
959
- })
960
-
961
- // Select box individual options events bound with the jQuery `delegate` method. `Delegate` was used because binding individual events to each list item (since we don't know how many there will be) would decrease performance. Instead, we bind each event to the unordered list, provide the list item context, and allow the list item events to bubble up (`event bubbling`). This greatly increases page performance because we only have to bind an event to one element instead of x number of elements. Delegates the `click` event with the `selectBoxIt` namespace to the list items
962
- .delegate("li", "click.selectBoxIt", function() {
963
-
964
- if (!$(this).data("disabled")) {
965
-
966
- // Sets the original dropdown list value and triggers the `change` event on the original select box
967
- self.originalElem.value = $(this).attr("data-val");
968
-
969
- // Sets `currentFocus` to the currently focused dropdown list option.
970
- // The unary `+` operator casts the string to a number
971
- // [James Padolsey Blog Post](http://james.padolsey.com/javascript/terse-javascript-101-part-2/)
972
- self.currentFocus = +this.id;
973
-
974
- // Closes the list after selecting an option
975
- self.close();
976
-
977
- // Triggers the dropdown list `change` event if a value change occurs
978
- if (self.originalElem.value !== self.divText.attr("data-val")) {
979
-
980
- self.selectBox.trigger("change");
981
-
982
- }
983
- }
984
- })
985
-
986
- // Delegates the `focus` event with the `selectBoxIt` namespace to the list items
987
- .delegate("li", "focus.selectBoxIt", function() {
988
-
989
- if (!$(this).data("disabled")) {
990
-
991
- // Sets the original select box current value and triggers the change event
992
- self.originalElem.value = $(this).attr("data-val");
993
-
994
- // Triggers the dropdown list `change` event if a value change occurs
995
- if (self.originalElem.value !== self.divText.attr("data-val")) {
996
-
997
- self.selectBox.trigger("change");
998
-
999
- }
1000
- }
1001
- });
1002
-
1003
- // Original dropdown list events
1004
- this.selectBox.bind({
1005
-
1006
- // `change` event handler with the `selectBoxIt` namespace
1007
- "change.selectBoxIt": function() {
1008
-
1009
- // Find list item entry with value of original select
1010
- self.currentFocus = self.listItems.index($('li[data-val="' + self.originalElem.value + '"]'));
1011
-
1012
- // Sets the new dropdown list text to the value of the original dropdown list
1013
- self.divText.text(self.listItems.eq(self.currentFocus).text()).attr("data-val", self.originalElem.value);
1014
-
1015
- if(self.listItems.eq(self.currentFocus).find("span").attr("class")) {
1016
-
1017
- self.divImage.attr("class", self.listItems.eq(self.currentFocus).find("span").attr("class"));
1018
- }
1019
- },
1020
-
1021
- // `disable` event with the `selectBoxIt` namespace
1022
- "disable.selectBoxIt": function() {
1023
-
1024
- // Adds the `disabled` CSS class to the new dropdown list to visually show that it is disabled
1025
- self.div.addClass("ui-state-disabled");
1026
- },
1027
-
1028
- // `enable` event with the `selectBoxIt` namespace
1029
- "enable.selectBoxIt": function() {
1030
-
1031
- // Removes the `disabled` CSS class from the new dropdown list to visually show that it is enabled
1032
- self.div.removeClass("ui-state-disabled");
1033
- }
1034
- });
1035
-
1036
- // // Binding the original change event to the new custom one
1037
- // .on("change", function(e) {
1038
- // console.log(e)
1039
- // self.selectBoxIt.trigger("change.selectBoxIt");
1040
- // });
1041
-
1042
- // Maintains chainability
1043
- return this;
1044
- },
1045
-
1046
- // _addClasses
1047
- // ---------
1048
- // Adds SelectBoxIt CSS classes
1049
- _addClasses: function() {
1050
-
1051
- var self = this,
1052
-
1053
- focusClass = "selectboxit-focus",
1054
-
1055
- hoverClass = "selectboxit-hover";
1056
-
1057
- this.downArrow.addClass(this.selectBox.data("downarrow") || this.options.downArrowIcon || "");
1058
-
1059
- // Adds the default class to the dropdown list
1060
- this.div.addClass("selectboxit-widget");
1061
-
1062
- // Adds the default styling for the dropdown list options
1063
- this.list.addClass("selectboxit-widget selectboxit-widget-content");
1064
-
1065
- // Select box individual option events
1066
- this.listItems.bind({
1067
-
1068
- // `focus` event with the `selectBoxIt` namespace
1069
- "focus.selectBoxIt": function() {
1070
-
1071
- // Adds the focus CSS class to the currently focused dropdown list option
1072
- $(this).addClass(focusClass);
1073
-
1074
- },
1075
-
1076
- // `blur` event with the `selectBoxIt` namespace
1077
- "blur.selectBoxIt": function() {
1078
-
1079
- // Removes the focus CSS class from the previously focused dropdown list option
1080
- $(this).removeClass(focusClass);
1081
-
1082
- }
1083
-
1084
- });
1085
-
1086
- // Select box events
1087
- this.selectBox.bind({
1088
-
1089
- // `click` event with the `selectBoxIt` namespace
1090
- "open.selectBoxIt": function() {
1091
-
1092
- // Removes the jQueryUI hover class from the dropdown list and adds the jQueryUI focus class for both the dropdown list and the currently selected dropdown list option
1093
- self.div.removeClass(hoverClass).add(self.listItems.eq(self.currentFocus)).
1094
-
1095
- addClass(focusClass);
1096
- },
1097
-
1098
- "blur.selectBoxIt": function() {
1099
-
1100
- self.div.removeClass(focusClass);
1101
-
1102
- },
1103
-
1104
- // `mousenter` event with the `selectBoxIt` namespace
1105
- "mouseenter.selectBoxIt": function() {
1106
-
1107
- self.div.addClass(hoverClass);
1108
-
1109
- },
1110
-
1111
- // `mouseleave` event with the `selectBoxIt` namespace
1112
- "mouseleave.selectBoxIt": function() {
1113
-
1114
- // Removes the hover CSS class on the previously hovered dropdown list option
1115
- self.div.removeClass(hoverClass);
1116
-
1117
- }
1118
-
1119
- });
1120
-
1121
- this.listItems.bind({
1122
-
1123
- "mouseenter.selectBoxIt": function() {
1124
-
1125
- // Sets the dropdown list individual options back to the default state and sets the hover CSS class on the currently hovered option
1126
- self.listItems.removeClass(focusClass);
1127
-
1128
- $(this).addClass(hoverClass);
1129
-
1130
- },
1131
-
1132
- "mouseleave.selectBoxIt": function() {
1133
-
1134
- $(this).removeClass(hoverClass);
1135
-
1136
- }
1137
-
1138
- });
1139
-
1140
- // Maintains chainability
1141
- return this;
1142
-
1143
- }
1144
-
1145
- });
1146
-
1147
- })); // End of core module
1148
- $(function() {
1149
-
1150
- //_ARIA Accessibility
1151
- // ------------------
1152
- // Adds ARIA (Accessible Rich Internet Applications)
1153
- // Accessibility Tags to the Select Box
1154
-
1155
- $.selectBox.selectBoxIt.prototype._ariaAccessibility = function() {
1156
-
1157
- var self = this;
1158
-
1159
- //Adds `ARIA attributes` to the dropdown list
1160
- this.div.attr({
1161
-
1162
- //W3C `combobox` description: A presentation of a select; usually similar to a textbox where users can type ahead to select an option.
1163
- "role": "combobox",
1164
-
1165
- //W3C `aria-autocomplete` description: Indicates whether user input completion suggestions are provided.
1166
- "aria-autocomplete": "list",
1167
-
1168
- //W3C `aria-expanded` description: Indicates whether the element, or another grouping element it controls, is currently expanded or collapsed.
1169
- "aria-expanded": "false",
1170
-
1171
- //W3C `aria-owns` description: The value of the aria-owns attribute is a space-separated list of IDREFS that reference one or more elements in the document by ID. The reason for adding aria-owns is to expose a parent/child contextual relationship to assistive technologies that is otherwise impossible to infer from the DOM.
1172
- "aria-owns": this.list.attr("id"),
1173
-
1174
- //W3C `aria-activedescendant` description: This is used when a composite widget is responsible for managing its current active child to reduce the overhead of having all children be focusable. Examples include: multi-level lists, trees, and grids.
1175
- "aria-activedescendant": this.listItems.eq(this.currentFocus).attr("id"),
1176
-
1177
- //W3C `aria-label` description: It provides the user with a recognizable name of the object.
1178
- "aria-label": $("label[for='" + this.originalElem.id + "']").text() || "",
1179
-
1180
- //W3C `aria-live` description: Indicates that an element will be updated.
1181
- //Use the assertive value when the update needs to be communicated to the user more urgently.
1182
- "aria-live": "assertive"
1183
- }).
1184
-
1185
- //Dynamically adds `ARIA attributes` if the new dropdown list is enabled or disabled
1186
- bind({
1187
-
1188
- //Select box custom `disable` event with the `selectBoxIt` namespace
1189
- "disable.selectBoxIt" : function() {
1190
-
1191
- //W3C `aria-disabled` description: Indicates that the element is perceivable but disabled, so it is not editable or otherwise operable.
1192
- self.div.attr("aria-disabled", "true");
1193
-
1194
- },
1195
-
1196
- //Select box custom `enable` event with the `selectBoxIt` namespace
1197
- "enable.selectBoxIt" : function() {
1198
-
1199
- //W3C `aria-disabled` description: Indicates that the element is perceivable but disabled, so it is not editable or otherwise operable.
1200
- self.div.attr("aria-disabled", "false");
1201
-
1202
- }
1203
-
1204
- });
1205
-
1206
- //Adds ARIA attributes to the dropdown list options list
1207
- self.list.attr({
1208
-
1209
- //W3C `listbox` description: A widget that allows the user to select one or more items from a list of choices.
1210
- "role": "listbox",
1211
-
1212
- //Indicates that the dropdown list options list is currently hidden
1213
- "aria-hidden": "true"
1214
- });
1215
-
1216
- //Adds `ARIA attributes` to the dropdown list options
1217
- self.listItems.attr({
1218
-
1219
- //This must be set for each element when the container element role is set to `listbox`
1220
- "role": "option"
1221
- });
1222
-
1223
- //Dynamically updates the new dropdown list `aria-label` attribute after the original dropdown list value changes
1224
- self.selectBox.bind({
1225
-
1226
- //Custom `change` event with the `selectBoxIt` namespace
1227
- "change.selectBoxIt": function() {
1228
-
1229
- //Provides the user with a recognizable name of the object.
1230
- self.divText.attr("aria-label", self.originalElem.value);
1231
-
1232
- },
1233
-
1234
- //Custom `open` event with the `selectBoxIt` namespace
1235
- "open.selectBoxIt": function() {
1236
-
1237
- //Indicates that the dropdown list options list is currently visible
1238
- self.list.attr("aria-hidden", "false");
1239
-
1240
- //Indicates that the dropdown list is currently expanded
1241
- self.div.attr("aria-expanded", "true");
1242
-
1243
- },
1244
-
1245
- //Custom `close` event with the `selectBoxIt` namespace
1246
- "close.selectBoxIt": function() {
1247
-
1248
- //Indicates that the dropdown list options list is currently hidden
1249
- self.list.attr("aria-hidden", "true");
1250
-
1251
- //Indicates that the dropdown list is currently collapsed
1252
- self.div.attr("aria-expanded", "false");
1253
-
1254
- }
1255
-
1256
- });
1257
-
1258
- //Maintains chainability
1259
- return this;
1260
-
1261
- };
1262
-
1263
- });
1264
- $(function() {
1265
-
1266
- //Destroy
1267
- // ------
1268
- // Delays execution by the amount of time
1269
- // specified by the parameter
1270
-
1271
- $.selectBox.selectBoxIt.prototype.destroy = function(callback) {
1272
-
1273
- //Unbinds all of the dropdown list event handlers with the `selectBoxIt` namespace
1274
- this.div.unbind(".selectBoxIt").
1275
-
1276
- //Undelegates all of the dropdown list event handlers with the `selectBoxIt` namespace
1277
- undelegate(".selectBoxIt");
1278
-
1279
- //Remove all of the `selectBoxIt` DOM elements from the page
1280
- this.divContainer.remove();
1281
-
1282
- //Triggers the custom `destroy` event on the original select box and then shows the original dropdown list
1283
- this.selectBox.trigger("destroy").show();
1284
-
1285
- // Calls the jQueryUI Widget Factory destroy method
1286
- $.Widget.prototype.destroy.call(this);
1287
-
1288
- //Provides callback function support
1289
- this._callbackSupport(callback);
1290
-
1291
- //Maintains chainability
1292
- return this;
1293
-
1294
- };
1295
-
1296
- });
1297
- $(function() {
1298
-
1299
- //Disable
1300
- // ------
1301
- // Disables the new dropdown list
1302
-
1303
- $.selectBox.selectBoxIt.prototype.disable = function(callback) {
1304
-
1305
- if(!this.options.disabled) {
1306
-
1307
- //Makes sure the dropdown list is closed
1308
- this.close();
1309
-
1310
- //Triggers a `disable` custom event on the original select box
1311
- this.selectBox.trigger("disable")
1312
-
1313
- //Sets the `disabled` attribute on the original select box
1314
- .attr("disabled", "disabled");
1315
-
1316
- //Makes the dropdown list not focusable by removing the `tabindex` attribute
1317
- this.div.removeAttr("tabindex").css("cursor", "default");
1318
-
1319
- // Calls the jQueryUI Widget Factory disable method to make sure all options are correctly synced
1320
- $.Widget.prototype.disable.call(this);
1321
-
1322
- //Provides callback function support
1323
- this._callbackSupport(callback);
1324
-
1325
- //Maintains chainability
1326
- return this;
1327
-
1328
- }
1329
-
1330
- };
1331
-
1332
- //_Is Disabled
1333
- // -----------
1334
- // Checks the original select box for the
1335
- // disabled attribute
1336
-
1337
- $.selectBox.selectBoxIt.prototype._isDisabled = function(callback) {
1338
-
1339
- //If the original select box is disabled
1340
- if (this.originalElem.disabled) {
1341
-
1342
- //Disables the dropdown list
1343
- this.disable();
1344
- }
1345
-
1346
- //Maintains chainability
1347
- return this;
1348
-
1349
- };
1350
-
1351
- });
1352
- $(function() {
1353
-
1354
- //_Dynamic positioning
1355
- // ------------------
1356
- // Dynamically positions the dropdown list options list
1357
-
1358
- $.selectBox.selectBoxIt.prototype._dynamicPositioning = function() {
1359
-
1360
- //Returns the x and y coordinates of the dropdown list options list relative to the document
1361
- var listOffsetTop = this.div.offset().top,
1362
-
1363
- //The height of the dropdown list options list
1364
- listHeight = this.list.height(),
1365
-
1366
- //The height of the dropdown list DOM element
1367
- selectBoxHeight = this.div.height();
1368
-
1369
- //Places the dropdown list options list on top of the dropdown list if the dropdown list options list does not fit on the page when opened
1370
- if ((listOffsetTop + selectBoxHeight + listHeight >= $(window).height() + $(window).scrollTop()) && (listOffsetTop - listHeight >= 0)) {
1371
-
1372
- //If the dropdown list currently opens downward
1373
- if (!this.flipped) {
1374
-
1375
- //Sets custom CSS properties to place the dropdown list options directly above the dropdown list
1376
- this.list.css("top", (this.divContainer.position().top - this.list.height()) - 2);
1377
-
1378
- //Sets the `flipped` instance variable to false to reflect that the dropdown list opens upward
1379
- this.flipped = true;
1380
-
1381
- }
1382
-
1383
- }
1384
-
1385
- //If the dropdown list options have enough room on the page to open downward
1386
- else {
1387
-
1388
- //If the dropdown list is currently opening upward
1389
- if (this.flipped) {
1390
-
1391
- //Sets custom CSS properties to place the dropdown list options directly below the dropdown list
1392
- this.list.css("top", (this.divContainer.position().top + this.div.height()) + 2);
1393
-
1394
- //Sets the `flipped` instance variable to false to reflect that the dropdown list opens downward
1395
- this.flipped = false;
1396
-
1397
- }
1398
-
1399
- }
1400
-
1401
- };
1402
-
1403
- });
1404
- $(function() {
1405
-
1406
- //Enable
1407
- // -----
1408
- // Enables the new dropdown list
1409
-
1410
- $.selectBox.selectBoxIt.prototype.enable = function(callback) {
1411
-
1412
- if(this.options.disabled) {
1413
-
1414
- //Triggers a `enable` custom event on the original select box
1415
- this.selectBox.trigger("enable")
1416
-
1417
- //Removes the `disabled` attribute from the original dropdown list
1418
- .removeAttr("disabled");
1419
-
1420
- //Make the dropdown list focusable
1421
- this.div.attr("tabindex", 0).css("cursor", "pointer");
1422
-
1423
- $.Widget.prototype.enable.call(this);
1424
-
1425
- //Provide callback function support
1426
- this._callbackSupport(callback);
1427
-
1428
- }
1429
-
1430
- //Maintains chainability
1431
- return this;
1432
-
1433
- };
1434
-
1435
- });
1436
- $(function() {
1437
-
1438
- //Move Down
1439
- // --------
1440
- // Handles the down keyboard navigation logic
1441
-
1442
- $.selectBox.selectBoxIt.prototype.moveDown = function(callback) {
1443
-
1444
- //Increments `currentFocus`, which represents the currently focused list item `id` attribute.
1445
- this.currentFocus += 1;
1446
-
1447
- //Determines whether the dropdown option the user is trying to go to is currently disabled
1448
- var disabled = this.listItems.eq(this.currentFocus).data("disabled"),
1449
-
1450
- hasNextEnabled = this.listItems.eq(this.currentFocus).nextAll("li").not("[data-disabled='true']").first().length;
1451
-
1452
- //If the user has reached the top of the list
1453
- if (this.currentFocus === this.listItems.length) {
1454
-
1455
- //Does not allow the user to continue to go up the list
1456
- this.currentFocus -= 1;
1457
-
1458
- }
1459
-
1460
- //If the option the user is trying to go to is disabled, but there is another enabled option
1461
- else if (disabled && hasNextEnabled) {
1462
-
1463
- //Blur the previously selected option
1464
- this.listItems.eq(this.currentFocus - 1).blur();
1465
-
1466
- //Call the `moveDown` method again
1467
- this.moveDown();
1468
-
1469
- //Exit the method
1470
- return;
1471
-
1472
- }
1473
-
1474
- //If the option the user is trying to go to is disabled, but there is not another enabled option
1475
- else if (disabled && !hasNextEnabled) {
1476
-
1477
- this.currentFocus -= 1;
1478
-
1479
- }
1480
-
1481
- //If the user has not reached the bottom of the unordered list
1482
- else {
1483
-
1484
- //Blurs the previously focused list item
1485
- //The jQuery `end()` method allows you to continue chaining while also using a different selector
1486
- this.listItems.eq(this.currentFocus - 1).blur().end().
1487
-
1488
- //Focuses the currently focused list item
1489
- eq(this.currentFocus).focus();
1490
-
1491
- //Calls `scrollToView` to make sure the `scrollTop` is correctly updated. The `down` user action
1492
- this._scrollToView("down");
1493
-
1494
- //Triggers the custom `moveDown` event on the original select box
1495
- this.selectBox.trigger("moveDown");
1496
-
1497
- }
1498
-
1499
- //Provide callback function support
1500
- this._callbackSupport(callback);
1501
-
1502
- //Maintains chainability
1503
- return this;
1504
- };
1505
-
1506
- //Move Up
1507
- // ------
1508
- // Handles the up keyboard navigation logic
1509
- $.selectBox.selectBoxIt.prototype.moveUp = function(callback) {
1510
-
1511
- //Increments `currentFocus`, which represents the currently focused list item `id` attribute.
1512
- this.currentFocus -= 1;
1513
-
1514
- //Determines whether the dropdown option the user is trying to go to is currently disabled
1515
- var disabled = this.listItems.eq(this.currentFocus).data("disabled"),
1516
-
1517
- hasPreviousEnabled = this.listItems.eq(this.currentFocus).prevAll("li").not("[data-disabled='true']").first().length;
1518
-
1519
- //If the user has reached the top of the list
1520
- if (this.currentFocus === -1) {
1521
-
1522
- //Does not allow the user to continue to go up the list
1523
- this.currentFocus += 1;
1524
- }
1525
-
1526
- //If the option the user is trying to go to is disabled and the user is not trying to go up after the user has reached the top of the list
1527
- else if (disabled && hasPreviousEnabled) {
1528
-
1529
- //Blur the previously selected option
1530
- this.listItems.eq(this.currentFocus + 1).blur();
1531
-
1532
- //Call the `moveUp` method again
1533
- this.moveUp();
1534
-
1535
- //Exit the method
1536
- return;
1537
- }
1538
-
1539
- else if (disabled && !hasPreviousEnabled) {
1540
-
1541
- this.currentFocus += 1;
1542
-
1543
- }
1544
-
1545
- //If the user has not reached the top of the unordered list
1546
- else {
1547
-
1548
- //Blurs the previously focused list item
1549
- //The jQuery `end()` method allows you to continue chaining while also using a different selector
1550
- this.listItems.eq(this.currentFocus + 1).blur().end().
1551
-
1552
- //Focuses the currently focused list item
1553
- eq(this.currentFocus).focus();
1554
-
1555
- //Calls `scrollToView` to make sure the `scrollTop` is correctly updated. The `down` user action
1556
- this._scrollToView("up");
1557
-
1558
- //Triggers the custom `moveDown` event on the original select box
1559
- this.selectBox.trigger("moveUp");
1560
-
1561
- }
1562
-
1563
- //Provide callback function support
1564
- this._callbackSupport(callback);
1565
-
1566
- //Maintains chainability
1567
- return this;
1568
- };
1569
-
1570
- });
1571
- $(function() {
1572
-
1573
- // _Set Current Search Option
1574
- // -------------------------
1575
- // Sets the currently selected dropdown list search option
1576
-
1577
- $.selectBox.selectBoxIt.prototype._setCurrentSearchOption = function(currentOption) {
1578
-
1579
- // Does not change the current option if `showFirstOption` is false and the matched search item is the hidden first option.
1580
- // Otherwise, the current option value is updated
1581
- if (!(currentOption === 0 && !this.options.showFirstOption) && this.listItems.eq(currentOption).data("disabled") !== true) {
1582
-
1583
- //Updates the default dropdown list text
1584
- this.divText.text(this.textArray[currentOption]);
1585
-
1586
- //Calls the `blur` event of the currently selected dropdown list option
1587
- this.listItems.eq(this.currentFocus).blur();
1588
-
1589
- //Sets `currentIndex` to the currently selected dropdown list option
1590
- this.currentIndex = currentOption;
1591
-
1592
- //Sets `currentFocus` to the currently selected dropdown list option
1593
- this.currentFocus = currentOption;
1594
-
1595
- //Focuses the currently selected dropdown list option
1596
- this.listItems.eq(this.currentFocus).focus();
1597
-
1598
- //Updates the scrollTop so that the currently selected dropdown list option is visible to the user
1599
- this._scrollToView("search");
1600
-
1601
- //Triggers the custom `search` event on the original select box
1602
- this.selectBox.trigger("search");
1603
-
1604
- }
1605
-
1606
- //Maintains chainability
1607
- return this;
1608
-
1609
- };
1610
-
1611
- // _Search Algorithm
1612
- // -----------------
1613
- // Uses regular expressions to find text matches
1614
- $.selectBox.selectBoxIt.prototype._searchAlgorithm = function(currentIndex, alphaNumeric) {
1615
-
1616
- // Boolean to determine if a pattern match exists
1617
- var matchExists = false,
1618
-
1619
- //Iteration variable used in the outermost for loop
1620
- x,
1621
-
1622
- //Iteration variable used in the nested for loop
1623
- y,
1624
-
1625
- //Variable used to cache the length of the text array (Small enhancement to speed up traversing)
1626
- arrayLength;
1627
-
1628
- //Loops through the text array to find a pattern match
1629
- for (x = currentIndex, arrayLength = this.textArray.length; x < arrayLength; x += 1) {
1630
-
1631
- //Nested for loop to help search for a pattern match with the currently traversed array item
1632
- for (y = 0; y < arrayLength; y += 1) {
1633
-
1634
- //Searches for a match
1635
- if (this.textArray[y].search(alphaNumeric) !== -1) {
1636
-
1637
- //`matchExists` is set to true if there is a match
1638
- matchExists = true;
1639
-
1640
- //Exits the nested for loop
1641
- y = arrayLength;
1642
-
1643
- }
1644
-
1645
- } //End nested for loop
1646
-
1647
- //If a match does not exist
1648
- if (!matchExists) {
1649
-
1650
- //Sets the current text to the last entered character
1651
- this.currentText = this.currentText.charAt(this.currentText.length - 1).
1652
-
1653
- //Escapes the regular expression to make sure special characters are seen as literal characters instead of special commands
1654
- replace(/[|()\[{.+*?$\\]/g, "\\$0");
1655
-
1656
- //Resets the regular expression with the new value of `self.currentText`
1657
- alphaNumeric = new RegExp(this.currentText, "gi");
1658
-
1659
- }
1660
-
1661
- //Searches based on the first letter of the dropdown list options text if the currentText < 2 characters
1662
- if (this.currentText.length < 2) {
1663
-
1664
- //If there is a match based on the first character
1665
- if ((this.textArray[x].charAt(0).search(alphaNumeric) !== -1)) {
1666
-
1667
- //Sets properties of that dropdown list option to make it the currently selected option
1668
- this._setCurrentSearchOption(x);
1669
-
1670
- //Increments the current index by one
1671
- this.currentIndex += 1;
1672
-
1673
- //Exits the search
1674
- return false;
1675
-
1676
- }
1677
- }
1678
-
1679
- // If `self.currentText` > 1 character
1680
- else {
1681
-
1682
- // If there is a match based on the entire string
1683
- if ((this.textArray[x].search(alphaNumeric) !== -1)) {
1684
-
1685
- // Sets properties of that dropdown list option to make it the currently selected option
1686
- this._setCurrentSearchOption(x);
1687
-
1688
- // Exits the search
1689
- return false;
1690
- }
1691
- }
1692
-
1693
- // If the current text search is an exact match
1694
- if (this.textArray[x].toLowerCase() === this.currentText.toLowerCase()) {
1695
-
1696
- // Sets properties of that dropdown list option to make it the currently selected option
1697
- this._setCurrentSearchOption(x);
1698
-
1699
- // Resets the current text search to a blank string to start fresh again
1700
- this.currentText = "";
1701
-
1702
- // Exits the search
1703
- return false;
1704
-
1705
- }
1706
- }
1707
-
1708
- //Returns true if there is not a match at all
1709
- return true;
1710
- };
1711
-
1712
- // Search
1713
- // ------
1714
- // Calls searchAlgorithm()
1715
- $.selectBox.selectBoxIt.prototype.search = function(alphaNumericKey, rememberPreviousSearch, callback) {
1716
-
1717
- // If the search method is being called internally by the plugin, and not externally as a method by a user
1718
- if (rememberPreviousSearch) {
1719
-
1720
- // Continued search with history from past searches. Properly escapes the regular expression
1721
- this.currentText += alphaNumericKey.replace(/[|()\[{.+*?$\\]/g, "\\$0");
1722
-
1723
- }
1724
-
1725
- else {
1726
-
1727
- // Brand new search. Properly escapes the regular expression
1728
- this.currentText = alphaNumericKey.replace(/[|()\[{.+*?$\\]/g, "\\$0");
1729
-
1730
- }
1731
-
1732
- // Wraps the current user text search in a regular expression that is case insensitive and searches globally
1733
- var alphaNumeric = new RegExp(this.currentText, "gi"),
1734
-
1735
- // Calls `searchAlgorithm` which searches an array that contains all of the dropdown list option values.
1736
- notFound = this._searchAlgorithm(this.currentIndex, alphaNumeric);
1737
-
1738
- // Searches the list again if a match is not found. This is needed, because the first search started at the array indece of the currently selected dropdown list option, and does not search the options before the current array indece.
1739
- // If there are many similar dropdown list options, starting the search at the indece of the currently selected dropdown list option is needed to properly traverse the text array.
1740
- if (notFound) {
1741
-
1742
- // Searches the dropdown list values starting from the beginning of the text array
1743
- this._searchAlgorithm(0, alphaNumeric);
1744
-
1745
- }
1746
-
1747
- // Provide callback function support
1748
- this._callbackSupport(callback);
1749
-
1750
- // Maintains chainability
1751
- return this;
1752
-
1753
- };
1754
-
1755
- });
1756
- $(function() {
1757
-
1758
- //Set Option
1759
- // ----------
1760
- // Accepts an string key, a value, and a callback function to replace a single
1761
- // property of the plugin options object
1762
-
1763
- $.selectBox.selectBoxIt.prototype.setOption = function(key, value, callback) {
1764
-
1765
- //If a user sets the `showFirstOption` to false
1766
- if (key === "showFirstOption" && !value) {
1767
-
1768
- //Hides the first option in the dropdown list
1769
- this.listItems.eq(0).hide();
1770
-
1771
- }
1772
-
1773
- //If a user sets the `showFirstOption` to true
1774
- else if (key === "showFirstOption" && value) {
1775
-
1776
- //Shows the first option in the dropdown list
1777
- this.listItems.eq(0).show();
1778
-
1779
- }
1780
-
1781
- else if(key === "defaultIcon" && value) {
1782
-
1783
- this.divImage.attr("class", value);
1784
-
1785
- }
1786
-
1787
- else if(key === "downArrowIcon" && value) {
1788
-
1789
- this.downArrow.attr("class", value);
1790
-
1791
- }
1792
-
1793
- //If a user sets the defaultText option
1794
- else if (key === "defaultText") {
1795
-
1796
- //Sets the new dropdown list default text
1797
- this.divText.text(value);
1798
-
1799
- }
1800
-
1801
- $.Widget.prototype._setOption.apply(this, arguments);
1802
-
1803
- //Provides callback function support
1804
- this._callbackSupport(callback);
1805
-
1806
- //Maintains chainability
1807
- return this;
1808
- };
1809
-
1810
- });
1811
- $(function() {
1812
-
1813
- //Set Options
1814
- // ----------
1815
- // Accepts an object to replace plugin options
1816
- // properties of the plugin options object
1817
-
1818
- $.selectBox.selectBoxIt.prototype.setOptions = function(newOptions, callback) {
1819
-
1820
- $.Widget.prototype._setOptions.apply(this, arguments);
1821
-
1822
- //If the `showFirstOption` option is true
1823
- if (this.options.showFirstOption) {
1824
-
1825
- //Shows the first option in the dropdown list
1826
- this.listItems.eq(0).show();
1827
-
1828
- }
1829
-
1830
- //If the `showFirstOption` option is false
1831
- else {
1832
-
1833
- //Hides the first option in the dropdown list
1834
- this.listItems.eq(0).hide();
1835
-
1836
- }
1837
-
1838
- if(this.options.defaultIcon) {
1839
-
1840
- this.divImage.attr("class", this.options.defaultIcon);
1841
-
1842
- }
1843
-
1844
- if(this.options.downArrowIcon) {
1845
-
1846
- this.downArrow.attr("class", this.options.downArrowIcon);
1847
-
1848
- }
1849
-
1850
- //If the defaultText option is set, make sure the dropdown list default text reflects this value
1851
- if (this.options.defaultText) {
1852
-
1853
- this.divText.text(this.options.defaultText);
1854
-
1855
- }
1856
-
1857
- //Provide callback function support
1858
- this._callbackSupport(callback);
1859
-
1860
- return this;
1861
-
1862
- };
1863
-
1864
- });
1865
- $(function() {
1866
-
1867
- //Wait
1868
- // ---
1869
- // Delays execution by the amount of time
1870
- // specified by the parameter
1871
-
1872
- $.selectBox.selectBoxIt.prototype.wait = function(time, callback) {
1873
-
1874
- var self = this,
1875
-
1876
- //The timeout variable stores a Deferred Object, which will be resolved after the time specified in the parameter
1877
- timeout = this.returnTimeout(time);
1878
-
1879
- //Once the Deferred object is resolved, call the callback function
1880
- timeout.then(function() {
1881
-
1882
- //Provide callback function support
1883
- self._callbackSupport(callback);
1884
-
1885
- });
1886
-
1887
- //Maintains chainability
1888
- return this;
1889
-
1890
- };
1891
-
1892
- //Return timeout
1893
- // -------------
1894
- // Returns a Deferred Object after the time
1895
- // specified by the parameter
1896
-
1897
- $.selectBox.selectBoxIt.prototype.returnTimeout = function(time) {
1898
-
1899
- //Returns a Deferred Object
1900
- return $.Deferred(function(dfd) {
1901
-
1902
- //Call the JavaScript `setTimeout function and resolve the Deferred Object
1903
- setTimeout(dfd.resolve, time);
1904
-
1905
- });
1906
-
1907
- };
1908
-
1909
- });