fae-railsz 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +5 -0
- data/Rakefile +37 -0
- data/app/assets/fonts/fae/icons.eot +0 -0
- data/app/assets/fonts/fae/icons.svg +56 -0
- data/app/assets/fonts/fae/icons.ttf +0 -0
- data/app/assets/fonts/fae/icons.woff +0 -0
- data/app/assets/fonts/fae/lato-bold-webfont.eot +0 -0
- data/app/assets/fonts/fae/lato-bold-webfont.svg +4551 -0
- data/app/assets/fonts/fae/lato-bold-webfont.ttf +0 -0
- data/app/assets/fonts/fae/lato-bold-webfont.woff +0 -0
- data/app/assets/fonts/fae/lato-light-webfont.eot +0 -0
- data/app/assets/fonts/fae/lato-light-webfont.svg +4241 -0
- data/app/assets/fonts/fae/lato-light-webfont.ttf +0 -0
- data/app/assets/fonts/fae/lato-light-webfont.woff +0 -0
- data/app/assets/fonts/fae/lato-regular-webfont.eot +0 -0
- data/app/assets/fonts/fae/lato-regular-webfont.svg +4241 -0
- data/app/assets/fonts/fae/lato-regular-webfont.ttf +0 -0
- data/app/assets/fonts/fae/lato-regular-webfont.woff +0 -0
- data/app/assets/fonts/fae/selection.json +1334 -0
- data/app/assets/images/fae/error_bg.jpg +0 -0
- data/app/assets/images/fae/error_sad_face.png +0 -0
- data/app/assets/images/fae/icons/alert.svg +9 -0
- data/app/assets/images/fae/icons/arrow_down.svg +8 -0
- data/app/assets/images/fae/icons/arrow_left.svg +9 -0
- data/app/assets/images/fae/icons/arrow_right.svg +9 -0
- data/app/assets/images/fae/icons/arrow_stacked.svg +8 -0
- data/app/assets/images/fae/icons/arrow_up.svg +8 -0
- data/app/assets/images/fae/icons/calendar.svg +17 -0
- data/app/assets/images/fae/icons/check.svg +7 -0
- data/app/assets/images/fae/icons/checkmark.svg +8 -0
- data/app/assets/images/fae/icons/chevron_down.svg +7 -0
- data/app/assets/images/fae/icons/chevron_left.svg +10 -0
- data/app/assets/images/fae/icons/chevron_right.svg +10 -0
- data/app/assets/images/fae/icons/chevron_up.svg +7 -0
- data/app/assets/images/fae/icons/delete.svg +8 -0
- data/app/assets/images/fae/icons/delete_x.svg +8 -0
- data/app/assets/images/fae/icons/edit.svg +11 -0
- data/app/assets/images/fae/icons/handle.svg +13 -0
- data/app/assets/images/fae/icons/home.svg +10 -0
- data/app/assets/images/fae/icons/logout.svg +12 -0
- data/app/assets/images/fae/icons/magnifying_glass.svg +10 -0
- data/app/assets/images/fae/icons/menu.svg +11 -0
- data/app/assets/images/fae/icons/offlink.svg +25 -0
- data/app/assets/images/fae/icons/plus.svg +8 -0
- data/app/assets/images/fae/icons/pulldown.svg +11 -0
- data/app/assets/images/fae/icons/search.svg +11 -0
- data/app/assets/images/fae/icons/settings.svg +12 -0
- data/app/assets/images/fae/icons/sort.svg +11 -0
- data/app/assets/images/fae/icons/support.svg +15 -0
- data/app/assets/images/fae/icons/trash.svg +10 -0
- data/app/assets/images/fae/icons/trumbowyg.svg +1 -0
- data/app/assets/images/fae/icons/user.svg +13 -0
- data/app/assets/images/fae/icons/users.svg +19 -0
- data/app/assets/images/fae/icons/zoom.svg +12 -0
- data/app/assets/images/fae/tutorial_model_location.png +0 -0
- data/app/assets/images/fae/youtube_helper.jpg +0 -0
- data/app/assets/javascripts/fae/_modals.js +60 -0
- data/app/assets/javascripts/fae/_tables.js +403 -0
- data/app/assets/javascripts/fae/admin.js.erb +11 -0
- data/app/assets/javascripts/fae/application.js +63 -0
- data/app/assets/javascripts/fae/fae_init.js +8 -0
- data/app/assets/javascripts/fae/form/_ajax.js +380 -0
- data/app/assets/javascripts/fae/form/_cancel.js +38 -0
- data/app/assets/javascripts/fae/form/_filtering.js +276 -0
- data/app/assets/javascripts/fae/form/_form.js +60 -0
- data/app/assets/javascripts/fae/form/_slugger.js.erb +100 -0
- data/app/assets/javascripts/fae/form/_validator.js +459 -0
- data/app/assets/javascripts/fae/form/fae_chosen.js +44 -0
- data/app/assets/javascripts/fae/form/fileinputer.js +178 -0
- data/app/assets/javascripts/fae/form/hinter.js +111 -0
- data/app/assets/javascripts/fae/form/inputs/_checkbox.js +27 -0
- data/app/assets/javascripts/fae/form/inputs/_color.js +42 -0
- data/app/assets/javascripts/fae/form/inputs/_dates.js +78 -0
- data/app/assets/javascripts/fae/form/inputs/_select.js +162 -0
- data/app/assets/javascripts/fae/form/inputs/_text.js +118 -0
- data/app/assets/javascripts/fae/navigation/_global_search.js +184 -0
- data/app/assets/javascripts/fae/navigation/_language.js +89 -0
- data/app/assets/javascripts/fae/navigation/_navigation.js +206 -0
- data/app/assets/javascripts/fae/navigation/_subnav_highlighter.js +81 -0
- data/app/assets/javascripts/fae/navigation/sticky.js +186 -0
- data/app/assets/javascripts/fae/vendor/chosen.jquery.min.js +2 -0
- data/app/assets/javascripts/fae/vendor/frob_core_helpers.js +587 -0
- data/app/assets/javascripts/fae/vendor/fryr.js +437 -0
- data/app/assets/javascripts/fae/vendor/jqColorPicker.min.js +4 -0
- data/app/assets/javascripts/fae/vendor/jquery.daterangepicker.js +1292 -0
- data/app/assets/javascripts/fae/vendor/jquery.multi-select.js +534 -0
- data/app/assets/javascripts/fae/vendor/jquery.simplemodal.1.4.4.js +719 -0
- data/app/assets/javascripts/fae/vendor/jquery.tablesorter.js +1901 -0
- data/app/assets/javascripts/fae/vendor/js.cookie.js +139 -0
- data/app/assets/javascripts/fae/vendor/moment.min.js +7 -0
- data/app/assets/javascripts/fae/vendor/simplemde.min.js +13 -0
- data/app/assets/javascripts/fae/vendor/touch_punch.js +11 -0
- data/app/assets/javascripts/fae/vendor/trumbowyg.js.erb +4 -0
- data/app/assets/javascripts/fae/vendor/trumbowyg/plugins/upload/trumbowyg.upload.js +223 -0
- data/app/assets/javascripts/fae/vendor/trumbowyg/trumbowyg.js +1603 -0
- data/app/assets/stylesheets/fae/application.css +8 -0
- data/app/assets/stylesheets/fae/base.scss +82 -0
- data/app/assets/stylesheets/fae/globals/_fonts.scss +43 -0
- data/app/assets/stylesheets/fae/globals/_icons.scss +15 -0
- data/app/assets/stylesheets/fae/globals/_plugins.scss +51 -0
- data/app/assets/stylesheets/fae/globals/_tags.scss +68 -0
- data/app/assets/stylesheets/fae/globals/imports/_extends.scss +53 -0
- data/app/assets/stylesheets/fae/globals/imports/_mixins.scss +58 -0
- data/app/assets/stylesheets/fae/globals/imports/_variables.scss +165 -0
- data/app/assets/stylesheets/fae/globals/imports/finescss/_fine.scss +7 -0
- data/app/assets/stylesheets/fae/globals/imports/finescss/_fine_functions.scss +88 -0
- data/app/assets/stylesheets/fae/globals/imports/finescss/_fine_mixins.scss +280 -0
- data/app/assets/stylesheets/fae/globals/imports/finescss/_fine_variables.scss +30 -0
- data/app/assets/stylesheets/fae/globals/layout/_base.scss +48 -0
- data/app/assets/stylesheets/fae/globals/layout/_breadcrumbs.scss +45 -0
- data/app/assets/stylesheets/fae/globals/layout/_content-header.scss +99 -0
- data/app/assets/stylesheets/fae/globals/legacy/_pre-1.3.scss +659 -0
- data/app/assets/stylesheets/fae/globals/navigation/_base.scss +22 -0
- data/app/assets/stylesheets/fae/globals/navigation/_footer.scss +50 -0
- data/app/assets/stylesheets/fae/globals/navigation/_header.scss +149 -0
- data/app/assets/stylesheets/fae/globals/navigation/_mobilenav.scss +149 -0
- data/app/assets/stylesheets/fae/globals/navigation/_search.scss +76 -0
- data/app/assets/stylesheets/fae/globals/navigation/_sidenav.scss +142 -0
- data/app/assets/stylesheets/fae/globals/navigation/_utility.scss +95 -0
- data/app/assets/stylesheets/fae/modules/_alerts.scss +50 -0
- data/app/assets/stylesheets/fae/modules/_buttons.scss +62 -0
- data/app/assets/stylesheets/fae/modules/_modal.scss +78 -0
- data/app/assets/stylesheets/fae/modules/_toggles.scss +48 -0
- data/app/assets/stylesheets/fae/modules/forms/_asset-actions.scss +83 -0
- data/app/assets/stylesheets/fae/modules/forms/_base.scss +100 -0
- data/app/assets/stylesheets/fae/modules/forms/_checkbox.scss +87 -0
- data/app/assets/stylesheets/fae/modules/forms/_colorpicker.scss +57 -0
- data/app/assets/stylesheets/fae/modules/forms/_date.scss +335 -0
- data/app/assets/stylesheets/fae/modules/forms/_hints.scss +40 -0
- data/app/assets/stylesheets/fae/modules/forms/_label.scss +57 -0
- data/app/assets/stylesheets/fae/modules/forms/_radio.scss +69 -0
- data/app/assets/stylesheets/fae/modules/forms/_select.scss +317 -0
- data/app/assets/stylesheets/fae/modules/forms/_simple-mde.scss +29 -0
- data/app/assets/stylesheets/fae/modules/forms/_text.scss +62 -0
- data/app/assets/stylesheets/fae/modules/forms/_textarea.scss +16 -0
- data/app/assets/stylesheets/fae/modules/forms/_validation.scss +63 -0
- data/app/assets/stylesheets/fae/modules/tables/_actions.scss +41 -0
- data/app/assets/stylesheets/fae/modules/tables/_base.scss +63 -0
- data/app/assets/stylesheets/fae/modules/tables/_collapsible.scss +76 -0
- data/app/assets/stylesheets/fae/modules/tables/_filters.scss +61 -0
- data/app/assets/stylesheets/fae/modules/tables/_image.scss +21 -0
- data/app/assets/stylesheets/fae/modules/tables/_pagination.scss +34 -0
- data/app/assets/stylesheets/fae/modules/tables/_sorting.scss +58 -0
- data/app/assets/stylesheets/fae/modules/tables/_sticky.scss +9 -0
- data/app/assets/stylesheets/fae/modules/tables/_tooltips.scss +24 -0
- data/app/assets/stylesheets/fae/pages/_error.scss +35 -0
- data/app/assets/stylesheets/fae/pages/_help.scss +28 -0
- data/app/assets/stylesheets/fae/pages/_home.scss +18 -0
- data/app/assets/stylesheets/fae/pages/_login.scss +137 -0
- data/app/assets/stylesheets/fae/vendor/chosen.css +377 -0
- data/app/assets/stylesheets/fae/vendor/daterangepicker.css +227 -0
- data/app/assets/stylesheets/fae/vendor/reset.css +48 -0
- data/app/assets/stylesheets/fae/vendor/simplemde.min.css +7 -0
- data/app/assets/stylesheets/fae/vendor/trumbowyg.css +584 -0
- data/app/controllers/concerns/fae/application_controller_concern.rb +1 -0
- data/app/controllers/concerns/fae/asset_cloner.rb +46 -0
- data/app/controllers/concerns/fae/cloneable.rb +136 -0
- data/app/controllers/fae/application_controller.rb +123 -0
- data/app/controllers/fae/base_controller.rb +117 -0
- data/app/controllers/fae/files_controller.rb +26 -0
- data/app/controllers/fae/images_controller.rb +37 -0
- data/app/controllers/fae/nested_base_controller.rb +100 -0
- data/app/controllers/fae/options_controller.rb +29 -0
- data/app/controllers/fae/pages_controller.rb +44 -0
- data/app/controllers/fae/setup_controller.rb +54 -0
- data/app/controllers/fae/static_pages_controller.rb +54 -0
- data/app/controllers/fae/users_controller.rb +71 -0
- data/app/controllers/fae/utilities_controller.rb +61 -0
- data/app/helpers/fae/application_helper.rb +114 -0
- data/app/helpers/fae/fae_helper.rb +6 -0
- data/app/helpers/fae/form_helper.rb +240 -0
- data/app/helpers/fae/nested_form_helper.rb +39 -0
- data/app/helpers/fae/view_helper.rb +175 -0
- data/app/inputs/date_range_input.rb +17 -0
- data/app/inputs/radio_collection_input.rb +17 -0
- data/app/inputs/symbol_input.rb +5 -0
- data/app/models/concerns/fae/assets_validatable.rb +12 -0
- data/app/models/concerns/fae/authorization_concern.rb +12 -0
- data/app/models/concerns/fae/base_model_concern.rb +105 -0
- data/app/models/concerns/fae/change_concern.rb +1 -0
- data/app/models/concerns/fae/file_concern.rb +1 -0
- data/app/models/concerns/fae/image_concern.rb +1 -0
- data/app/models/concerns/fae/navigation_concern.rb +10 -0
- data/app/models/concerns/fae/option_concern.rb +1 -0
- data/app/models/concerns/fae/page_validatable.rb +26 -0
- data/app/models/concerns/fae/paper_trailer.rb +8 -0
- data/app/models/concerns/fae/role_concern.rb +1 -0
- data/app/models/concerns/fae/sortable.rb +51 -0
- data/app/models/concerns/fae/static_page_concern.rb +1 -0
- data/app/models/concerns/fae/text_area_concern.rb +1 -0
- data/app/models/concerns/fae/text_field_concern.rb +1 -0
- data/app/models/concerns/fae/trackable.rb +124 -0
- data/app/models/concerns/fae/user_concern.rb +7 -0
- data/app/models/fae/authorization.rb +8 -0
- data/app/models/fae/change.rb +53 -0
- data/app/models/fae/file.rb +24 -0
- data/app/models/fae/image.rb +33 -0
- data/app/models/fae/navigation.rb +132 -0
- data/app/models/fae/option.rb +38 -0
- data/app/models/fae/role.rb +18 -0
- data/app/models/fae/static_page.rb +109 -0
- data/app/models/fae/text_area.rb +14 -0
- data/app/models/fae/text_field.rb +14 -0
- data/app/models/fae/user.rb +67 -0
- data/app/uploaders/fae/file_uploader.rb +26 -0
- data/app/uploaders/fae/image_uploader.rb +28 -0
- data/app/validators/fae/cross_model_uniqueness_validator.rb +14 -0
- data/app/views/devise/confirmations/new.html.slim +13 -0
- data/app/views/devise/mailer/confirmation_instructions.html.slim +3 -0
- data/app/views/devise/mailer/reset_password_instructions.html.slim +5 -0
- data/app/views/devise/mailer/unlock_instructions.html.slim +4 -0
- data/app/views/devise/passwords/edit.html.slim +10 -0
- data/app/views/devise/passwords/new.html.slim +10 -0
- data/app/views/devise/registrations/edit.html.slim +22 -0
- data/app/views/devise/registrations/new.html.slim +15 -0
- data/app/views/devise/sessions/new.html.slim +7 -0
- data/app/views/devise/shared/_links.slim +25 -0
- data/app/views/devise/unlocks/new.html.slim +13 -0
- data/app/views/fae/application/_breadcrumb.html.slim +19 -0
- data/app/views/fae/application/_content_form.html.slim +55 -0
- data/app/views/fae/application/_credit.slim +6 -0
- data/app/views/fae/application/_file_uploader.html.slim +36 -0
- data/app/views/fae/application/_flash_messages.slim +2 -0
- data/app/views/fae/application/_global_search_results.html.slim +37 -0
- data/app/views/fae/application/_header.slim +50 -0
- data/app/views/fae/application/_markdown_helper.slim +41 -0
- data/app/views/fae/application/_mobilenav.slim +66 -0
- data/app/views/fae/application/_sidenav.slim +23 -0
- data/app/views/fae/application/_user_log.html.slim +36 -0
- data/app/views/fae/images/_image_uploader.html.slim +66 -0
- data/app/views/fae/options/_form.html.slim +16 -0
- data/app/views/fae/options/edit.html.slim +1 -0
- data/app/views/fae/pages/activity_log.html.slim +32 -0
- data/app/views/fae/pages/disabled_environment.html.slim +4 -0
- data/app/views/fae/pages/error404.html.slim +7 -0
- data/app/views/fae/pages/help.html.slim +35 -0
- data/app/views/fae/pages/home.html.slim +36 -0
- data/app/views/fae/setup/first_user.html.slim +11 -0
- data/app/views/fae/shared/_errors.slim +4 -0
- data/app/views/fae/shared/_form_header.html.slim +40 -0
- data/app/views/fae/shared/_index_header.html.slim +26 -0
- data/app/views/fae/shared/_nested_table.html.slim +49 -0
- data/app/views/fae/shared/_recent_changes.html.slim +22 -0
- data/app/views/fae/shared/_shared_nested_table.html.slim +46 -0
- data/app/views/fae/static_pages/index.html.slim +13 -0
- data/app/views/fae/users/_form.html.slim +19 -0
- data/app/views/fae/users/edit.html.slim +1 -0
- data/app/views/fae/users/index.html.slim +23 -0
- data/app/views/fae/users/new.html.slim +1 -0
- data/app/views/fae/users/settings.html.slim +1 -0
- data/app/views/kaminari/fae/_gap.html.slim +8 -0
- data/app/views/kaminari/fae/_next_page.html.slim +9 -0
- data/app/views/kaminari/fae/_page.html.slim +15 -0
- data/app/views/kaminari/fae/_paginator.html.slim +15 -0
- data/app/views/kaminari/fae/_prev_page.html.slim +9 -0
- data/app/views/layouts/devise.html.slim +29 -0
- data/app/views/layouts/fae/application.html.slim +23 -0
- data/app/views/layouts/fae/error.html.slim +11 -0
- data/config/deploy.rb +73 -0
- data/config/deploy/dev.rb +19 -0
- data/config/deploy/prod.rb +19 -0
- data/config/deploy/stage.rb +19 -0
- data/config/initializers/assets.rb +1 -0
- data/config/initializers/carrierwave.rb +3 -0
- data/config/initializers/devise.rb +258 -0
- data/config/initializers/devise_monkeypatch.rb +11 -0
- data/config/initializers/fae_judge.rb +3 -0
- data/config/initializers/inflections.rb +16 -0
- data/config/initializers/kaminari_config.rb +10 -0
- data/config/initializers/simple_form.rb +147 -0
- data/config/initializers/time_formats.rb +3 -0
- data/config/locales/devise.en.yml +59 -0
- data/config/locales/devise.zh-CN.yml +59 -0
- data/config/locales/fae.en.yml +10 -0
- data/config/locales/fae.zh-CN.yml +10 -0
- data/config/locales/simple_form.en.yml +26 -0
- data/config/locales/simple_form.zh-CN.yml +26 -0
- data/config/routes.rb +46 -0
- data/db/migrate/20140809222030_add_user_table.rb +49 -0
- data/db/migrate/20140822224029_create_fae_roles.rb +10 -0
- data/db/migrate/20141008180718_create_fae_images_table.rb +19 -0
- data/db/migrate/20141017194616_create_fae_options.rb +16 -0
- data/db/migrate/20141021181327_create_fae_files.rb +17 -0
- data/db/migrate/20141021183047_create_fae_text_areas.rb +16 -0
- data/db/migrate/20141021184311_create_fae_pages.rb +13 -0
- data/db/migrate/20141105214814_create_fae_text_fields.rb +15 -0
- data/db/migrate/20150930224821_create_fae_changes.rb +17 -0
- data/lib/fae-rails.rb +6 -0
- data/lib/fae/concerns/models/base.rb +8 -0
- data/lib/fae/engine.rb +37 -0
- data/lib/fae/options.rb +35 -0
- data/lib/fae/validation_helper_collection.rb +76 -0
- data/lib/fae/version.rb +3 -0
- data/lib/file_size_validator.rb +71 -0
- data/lib/generators/fae/base_generator.rb +156 -0
- data/lib/generators/fae/controller_generator.rb +13 -0
- data/lib/generators/fae/install_generator.rb +61 -0
- data/lib/generators/fae/model_generator.rb +11 -0
- data/lib/generators/fae/nested_index_scaffold_generator.rb +36 -0
- data/lib/generators/fae/nested_scaffold_generator.rb +51 -0
- data/lib/generators/fae/page_generator.rb +65 -0
- data/lib/generators/fae/scaffold_generator.rb +15 -0
- data/lib/generators/fae/templates/assets/fae.js +6 -0
- data/lib/generators/fae/templates/assets/fae.scss +2 -0
- data/lib/generators/fae/templates/controllers/nested_index_scaffold_controller.rb +81 -0
- data/lib/generators/fae/templates/controllers/nested_scaffold_controller.rb +13 -0
- data/lib/generators/fae/templates/controllers/scaffold_controller.rb +13 -0
- data/lib/generators/fae/templates/controllers/static_pages_controller.rb +10 -0
- data/lib/generators/fae/templates/initializers/fae.rb +63 -0
- data/lib/generators/fae/templates/initializers/fae_fine.rb +51 -0
- data/lib/generators/fae/templates/initializers/judge.rb +6 -0
- data/lib/generators/fae/templates/models/concerns/authorization_concern.rb +27 -0
- data/lib/generators/fae/templates/models/concerns/navigation_concern.rb +33 -0
- data/lib/generators/fae/templates/models/pages_model.rb +14 -0
- data/lib/generators/fae/templates/tasks/fae_tasks.rake +19 -0
- data/lib/generators/fae/templates/views/_form.html.slim +18 -0
- data/lib/generators/fae/templates/views/_form_index_nested.html.slim +13 -0
- data/lib/generators/fae/templates/views/_form_nested.html.slim +17 -0
- data/lib/generators/fae/templates/views/edit.html.slim +1 -0
- data/lib/generators/fae/templates/views/edit_nested.html.slim +3 -0
- data/lib/generators/fae/templates/views/index.html.slim +35 -0
- data/lib/generators/fae/templates/views/index_nested.html.slim +8 -0
- data/lib/generators/fae/templates/views/new.html.slim +1 -0
- data/lib/generators/fae/templates/views/new_nested.html.slim +3 -0
- data/lib/generators/fae/templates/views/static_page_form.html.slim +15 -0
- data/lib/generators/fae/templates/views/table_nested.html.slim +4 -0
- metadata +692 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/* global Fae */
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Fae form
|
|
5
|
+
* @namespace form
|
|
6
|
+
* @memberof Fae
|
|
7
|
+
*/
|
|
8
|
+
Fae.form = {
|
|
9
|
+
ready: function() {
|
|
10
|
+
// Mutate DOM to support two column labels for all standard inputs
|
|
11
|
+
this.makeTwoColumnLabels();
|
|
12
|
+
|
|
13
|
+
this.dates.init();
|
|
14
|
+
this.color.init();
|
|
15
|
+
this.text.init();
|
|
16
|
+
this.select.init();
|
|
17
|
+
this.checkbox.init();
|
|
18
|
+
this.validator.init();
|
|
19
|
+
this.cancel.init();
|
|
20
|
+
this.ajax.init();
|
|
21
|
+
this.filtering.init();
|
|
22
|
+
this.slugger.init();
|
|
23
|
+
|
|
24
|
+
// input type=file customization
|
|
25
|
+
// This doesn't work in IE. It's not worth figuring out why by this point. IE9 gets plain file uploader.
|
|
26
|
+
if (!FCH.IE9) {
|
|
27
|
+
$('.input.file').fileinputer();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// make all the hint areas
|
|
31
|
+
$('.hint').hinter();
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
makeTwoColumnLabels: function() {
|
|
35
|
+
$('.input label').each(function() {
|
|
36
|
+
var $element = $(this);
|
|
37
|
+
|
|
38
|
+
// Bail if we cannot find any helper_text
|
|
39
|
+
if (!$element.find('.helper_text').length) {
|
|
40
|
+
$element.addClass('has_no_helper_text');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// If present, get all DOM nodes w/ contents(), but ignore the .helper_text
|
|
44
|
+
var label_inner = $element.contents().filter(function() {
|
|
45
|
+
return !$(this).hasClass('helper_text');
|
|
46
|
+
});
|
|
47
|
+
var helper_text = $element.find('.helper_text');
|
|
48
|
+
|
|
49
|
+
// Replace existing label w/ newly wrapped elements, sans .helper_text
|
|
50
|
+
label_inner = $('<div class="label_inner" />').html(label_inner);
|
|
51
|
+
$element.html(label_inner);
|
|
52
|
+
|
|
53
|
+
// But then add .helper_text as a sibling
|
|
54
|
+
$element.append(helper_text);
|
|
55
|
+
|
|
56
|
+
// Ensure that we mark this input as having two column label support
|
|
57
|
+
$element.addClass('label--two_col');
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
};
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/* global Fae */
|
|
2
|
+
|
|
3
|
+
'use strict';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Fae form
|
|
7
|
+
* @namespace form
|
|
8
|
+
* @memberof Fae
|
|
9
|
+
*/
|
|
10
|
+
Fae.form.slugger = {
|
|
11
|
+
init: function() {
|
|
12
|
+
this.addListener();
|
|
13
|
+
},
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Attach listeners to inputs and update slug fields with original safe values from the original inputs
|
|
17
|
+
*/
|
|
18
|
+
addListener: function() {
|
|
19
|
+
var _this = this;
|
|
20
|
+
|
|
21
|
+
$('.slug').each(function() {
|
|
22
|
+
var $form = $(this).closest('form');
|
|
23
|
+
var $sluggers = $form.find('.slugger');
|
|
24
|
+
var $slug = $form.find('.slug');
|
|
25
|
+
var $select_slugger = $('.select.slugger');
|
|
26
|
+
|
|
27
|
+
if ($slug.val() !== '') {
|
|
28
|
+
$sluggers.removeClass('slugger');
|
|
29
|
+
|
|
30
|
+
} else {
|
|
31
|
+
// If it's a text field, listen for type input
|
|
32
|
+
$sluggers.keyup(function(){
|
|
33
|
+
var text = _this._digestSlug( $sluggers );
|
|
34
|
+
$slug.val( text );
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// If it's a select field, listen for the change
|
|
38
|
+
if ($select_slugger.length) {
|
|
39
|
+
$select_slugger.change(function(){
|
|
40
|
+
var text = _this._digestSlug( $sluggers );
|
|
41
|
+
$slug.val( text );
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Convert a group of selects or text fields into one slug string
|
|
51
|
+
* @access protected
|
|
52
|
+
* @param {jQuery} $sluggers - Input or inputs that should be converted into a URL-safe string
|
|
53
|
+
* @return {String}
|
|
54
|
+
*/
|
|
55
|
+
_digestSlug: function($sluggers) {
|
|
56
|
+
var slug_text = []
|
|
57
|
+
|
|
58
|
+
$sluggers.each(function() {
|
|
59
|
+
var $this = $(this);
|
|
60
|
+
|
|
61
|
+
if ($this.val().length) {
|
|
62
|
+
|
|
63
|
+
if ($this.is('input')) {
|
|
64
|
+
slug_text.push( $this.val() );
|
|
65
|
+
|
|
66
|
+
} else {
|
|
67
|
+
slug_text.push( $this.find('option:selected').text() );
|
|
68
|
+
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// Combine all active slug fields for the query
|
|
74
|
+
slug_text = slug_text.join(' ');
|
|
75
|
+
|
|
76
|
+
// Strip accented characters
|
|
77
|
+
var from = 'àáâãäæåçèéêëęēėìíîïñòóôõöùúûüýÿÀÁÂÃÄÇÈÉÊËÌÍÎÏÑÒÓÔÕÖÙÚÛÜÝ';
|
|
78
|
+
var to = 'aaaaaaaceeeeeeeiiiinooooouuuuyyAAAAACEEEEIIIINOOOOOUUUUY';
|
|
79
|
+
|
|
80
|
+
// Loop through all accented characters and replace with non-accents
|
|
81
|
+
for (var i = 0; i < from.length; i++) {
|
|
82
|
+
slug_text = slug_text.replace( new RegExp(from.charAt(i), 'g'), to.charAt(i) );
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Remove leading and trailing spaces
|
|
86
|
+
// Make them lowercase
|
|
87
|
+
// Remove slashes, quotes or periods
|
|
88
|
+
// Replace white spaces with a Fae.slug_separator
|
|
89
|
+
// Remove leading and trailing dashes
|
|
90
|
+
slug_text = slug_text
|
|
91
|
+
.trim()
|
|
92
|
+
.toLowerCase()
|
|
93
|
+
.replace(/[^<%= Fae.slug_separator %>\w\s]/g, '')
|
|
94
|
+
.replace(/[<%= Fae.slug_separator %>\s]+/g, '<%= Fae.slug_separator %>')
|
|
95
|
+
.replace(/(^<%= Fae.slug_separator %>)|(<%= Fae.slug_separator %>$)/g, '');
|
|
96
|
+
|
|
97
|
+
return slug_text;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
};
|
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
/* global Fae, judge, FCH */
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Fae form validator
|
|
5
|
+
* @namespace form.validator
|
|
6
|
+
* @memberof form
|
|
7
|
+
*/
|
|
8
|
+
Fae.form.validator = {
|
|
9
|
+
|
|
10
|
+
is_valid: '',
|
|
11
|
+
validations_called: 0,
|
|
12
|
+
validations_returned: 0,
|
|
13
|
+
validation_test_count: 0,
|
|
14
|
+
|
|
15
|
+
init: function () {
|
|
16
|
+
// validate all forms except the login form
|
|
17
|
+
if ($('form').not('#login_form').length) {
|
|
18
|
+
this.password_confirmation_validation.init();
|
|
19
|
+
this.passwordPresenceConditional();
|
|
20
|
+
this.bindValidationEvents();
|
|
21
|
+
this.formValidate();
|
|
22
|
+
this.length_counter.init();
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Validate the entire form on submit and stop it if the form is invalid
|
|
28
|
+
*/
|
|
29
|
+
formValidate: function () {
|
|
30
|
+
var _this = this;
|
|
31
|
+
|
|
32
|
+
FCH.$document.on('submit', 'form:not([data-remote=true])', function (e) {
|
|
33
|
+
var $this = $(this);
|
|
34
|
+
|
|
35
|
+
if ($this.data('passed_validation') !== 'true') {
|
|
36
|
+
|
|
37
|
+
// pause form submission
|
|
38
|
+
e.preventDefault();
|
|
39
|
+
|
|
40
|
+
// set defaults
|
|
41
|
+
_this.is_valid = true;
|
|
42
|
+
_this.validations_called = 0;
|
|
43
|
+
_this.validations_returned = 0;
|
|
44
|
+
_this.validation_test_count = 0;
|
|
45
|
+
|
|
46
|
+
// Scope the data-validation only to the form submitted
|
|
47
|
+
$('[data-validate]', $this).each(function () {
|
|
48
|
+
if ($(this).data('validate').length) {
|
|
49
|
+
_this.validations_called++;
|
|
50
|
+
_this._judgeIt($(this));
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// Catch visible errors for image/file inputs hitting the fae config file size limiter
|
|
55
|
+
$('.input.file', $this).each(function () {
|
|
56
|
+
if ($(this).hasClass('field_with_errors')) {
|
|
57
|
+
_this.is_valid = false;
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
_this.testValidation($this);
|
|
62
|
+
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
});
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Tests a forms validation after all validation checks have responded
|
|
70
|
+
* Polls validations responses every 50ms to allow uniqueness AJAX calls to complete
|
|
71
|
+
*/
|
|
72
|
+
testValidation: function($this) {
|
|
73
|
+
var _this = this;
|
|
74
|
+
_this.validation_test_count++;
|
|
75
|
+
|
|
76
|
+
setTimeout(function(){
|
|
77
|
+
|
|
78
|
+
// if all the validation checks have returned a response
|
|
79
|
+
if (_this.validations_called === _this.validations_returned) {
|
|
80
|
+
|
|
81
|
+
if (_this.is_valid) {
|
|
82
|
+
// if form is valid, submit it
|
|
83
|
+
$this.data('passed_validation', 'true');
|
|
84
|
+
|
|
85
|
+
$this.submit();
|
|
86
|
+
} else {
|
|
87
|
+
// otherwise scroll to the top to display alerts
|
|
88
|
+
Fae.navigation.language.checkForHiddenErrors();
|
|
89
|
+
FCH.smoothScroll($('#js-main-header'), 500, 100, 0);
|
|
90
|
+
|
|
91
|
+
if ($(".field_with_errors").length) {
|
|
92
|
+
$('.alert').slideDown('fast').delay(3000).slideUp('fast');
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
} else {
|
|
97
|
+
// check again if it hasn't run more than 50 times
|
|
98
|
+
// (to prevent against infinite loop)
|
|
99
|
+
if (_this.validation_test_count < 50) {
|
|
100
|
+
_this.testValidation($this);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
}, 50);
|
|
105
|
+
|
|
106
|
+
},
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Bind validation events based on input type
|
|
110
|
+
*/
|
|
111
|
+
bindValidationEvents: function ($scope) {
|
|
112
|
+
var _this = this;
|
|
113
|
+
|
|
114
|
+
if (typeof($scope) === 'undefined'){
|
|
115
|
+
$scope = $('body');
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
$scope.find('[data-validate]').each(function () {
|
|
119
|
+
var $this = $(this);
|
|
120
|
+
|
|
121
|
+
if ($this.data('validate').length) {
|
|
122
|
+
if ($this.is('input:not(.hasDatepicker), textarea')) {
|
|
123
|
+
// normal inputs validate on blur
|
|
124
|
+
$this.blur(function () {
|
|
125
|
+
_this._judgeIt($this);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
} else if ($this.hasClass('hasDatepicker')) {
|
|
129
|
+
// date pickers need a little delay
|
|
130
|
+
$this.blur(function () {
|
|
131
|
+
setTimeout(function(){ _this._judgeIt($this); }, 500);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
} else if ($this.is('select')) {
|
|
135
|
+
// selects validate on change
|
|
136
|
+
$this.change(function () {
|
|
137
|
+
_this._judgeIt($this);
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
},
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Initialize Judge on a field
|
|
147
|
+
* @protected
|
|
148
|
+
* @param {jQuery} $input - field to be validated
|
|
149
|
+
*/
|
|
150
|
+
_judgeIt: function ($input) {
|
|
151
|
+
var _this = this;
|
|
152
|
+
|
|
153
|
+
judge.validate($input[0], {
|
|
154
|
+
valid: function () {
|
|
155
|
+
_this.validations_returned++;
|
|
156
|
+
_this._createSuccessClass($input);
|
|
157
|
+
},
|
|
158
|
+
invalid: function (input, messages) {
|
|
159
|
+
_this.validations_returned++;
|
|
160
|
+
messages = _this._removeIgnoredErrors(messages);
|
|
161
|
+
if (messages.length) {
|
|
162
|
+
_this.is_valid = false;
|
|
163
|
+
_this._createOrReplaceError($input, messages);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
},
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Strips out ignored error messages
|
|
171
|
+
* @protected
|
|
172
|
+
* @param messages - array of error messages from Judge
|
|
173
|
+
*/
|
|
174
|
+
_removeIgnoredErrors: function (messages) {
|
|
175
|
+
// Ignored error messages from Judge:
|
|
176
|
+
// 'Judge validation for Release#name not allowed'
|
|
177
|
+
// 'Slug Request error: 0'
|
|
178
|
+
var ignored_error_substrings = ['Judge validation', 'Request error'];
|
|
179
|
+
|
|
180
|
+
// loop through messages
|
|
181
|
+
for (var i = 0; i < messages.length; i++) {
|
|
182
|
+
// loop through ignored errors
|
|
183
|
+
for (var j = 0; j < ignored_error_substrings.length; j++) {
|
|
184
|
+
// if the substring exists in the error message
|
|
185
|
+
if (messages[i].indexOf(ignored_error_substrings[j]) > -1) {
|
|
186
|
+
// log it in the console and remove message
|
|
187
|
+
window.console && console.log('Ignoring error: ', messages[i]);
|
|
188
|
+
messages.splice(i, 1);
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return messages;
|
|
195
|
+
},
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Adds and removes the appropriate classes to display the success styles
|
|
199
|
+
* @protected
|
|
200
|
+
* @param {jQuery} $input - Input field (can be a chosen object)
|
|
201
|
+
*/
|
|
202
|
+
_createSuccessClass: function ($input) {
|
|
203
|
+
var $styled_input = this._setTargetInput($input);
|
|
204
|
+
$styled_input.addClass('valid').removeClass('invalid');
|
|
205
|
+
|
|
206
|
+
$input.parent().removeClass('field_with_errors').children('.error').remove();
|
|
207
|
+
},
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Adds and removes the appropriate classes to display the error styles
|
|
211
|
+
* @protected
|
|
212
|
+
* @param {jQuery} $input - Input field
|
|
213
|
+
* @param {Array} messages - Error messages to display
|
|
214
|
+
*/
|
|
215
|
+
_createOrReplaceError: function ($input, messages) {
|
|
216
|
+
var $styled_input = this._setTargetInput($input);
|
|
217
|
+
$styled_input.addClass('invalid').removeClass('valid');
|
|
218
|
+
|
|
219
|
+
var $wrapper = $input.closest('.input');
|
|
220
|
+
if ($wrapper.children('.error').length) {
|
|
221
|
+
$wrapper.children('.error').text(messages.join(', '));
|
|
222
|
+
} else {
|
|
223
|
+
$wrapper.addClass('field_with_errors').append("<span class='error'>" + messages.join(', ') + "</span>");
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* A DRY method for setting the element that should take the .valid or .invalid style
|
|
229
|
+
* @protected
|
|
230
|
+
* @param {jQuery} $input - Input field for a chosen object
|
|
231
|
+
* @return {jQuery} The chosen container
|
|
232
|
+
*/
|
|
233
|
+
_setTargetInput: function ($input) {
|
|
234
|
+
var $styled_input = $input;
|
|
235
|
+
|
|
236
|
+
// If field is a chosen input
|
|
237
|
+
if ( $input.next('.chosen-container').length ) {
|
|
238
|
+
if ($input.next('.chosen-container').find('.chosen-single').length) {
|
|
239
|
+
$styled_input = $input.next('.chosen-container').find('.chosen-single');
|
|
240
|
+
|
|
241
|
+
} else if ($input.next('.chosen-container').find('.chosen-choices').length) {
|
|
242
|
+
$styled_input = $input.next('.chosen-container').find('.chosen-choices');
|
|
243
|
+
|
|
244
|
+
}
|
|
245
|
+
} else if ($input.hasClass('mde-enabled')) {
|
|
246
|
+
$styled_input = $input.siblings('.editor-toolbar, .CodeMirror-wrap');
|
|
247
|
+
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
return $styled_input;
|
|
251
|
+
},
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Removes a field's Judge validation
|
|
255
|
+
* @param {jQuery} $field - Input fields
|
|
256
|
+
* @param {String} kind - Type of validation (e.g. 'presence' or 'confirmation')
|
|
257
|
+
*/
|
|
258
|
+
stripValidation: function($field, kind) {
|
|
259
|
+
var validations = $field.data('validate');
|
|
260
|
+
|
|
261
|
+
for (var i = 0; i < validations.length; i++) {
|
|
262
|
+
// validation items can be strings or JSON objects
|
|
263
|
+
// let's convert the strings to JSON so we're dealing with consistent types
|
|
264
|
+
if (typeof validations[i] == 'string' || validations[i] instanceof String) {
|
|
265
|
+
validations[i] = JSON.parse(validations[i]);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// if the kind matches, remove it from the array
|
|
269
|
+
if (validations[i]['kind'] === kind) {
|
|
270
|
+
validations.splice(i, 1);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// convert JSON back to a string
|
|
274
|
+
validations[i] = JSON.stringify(validations[i]);
|
|
275
|
+
}
|
|
276
|
+
$field.attr('data-validate', '[' + validations + ']');
|
|
277
|
+
},
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Password Confirmation Validation
|
|
281
|
+
* @description Judge validates confirmation on the original field. This is a hack to remove Judge's validation and add it to the confirmation field
|
|
282
|
+
* @namespace
|
|
283
|
+
* @memberof! validator
|
|
284
|
+
*/
|
|
285
|
+
password_confirmation_validation: {
|
|
286
|
+
init: function() {
|
|
287
|
+
var _this = this;
|
|
288
|
+
|
|
289
|
+
_this.$password_field = $('#user_password');
|
|
290
|
+
_this.$password_confirmation_field = $('#user_password_confirmation');
|
|
291
|
+
|
|
292
|
+
if (_this.$password_confirmation_field.length) {
|
|
293
|
+
Fae.form.validator.stripValidation(_this.$password_field, 'confirmation');
|
|
294
|
+
_this.addCustomValidation();
|
|
295
|
+
}
|
|
296
|
+
},
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Validate password on blur and form submit; halt form execution if invalid
|
|
300
|
+
*/
|
|
301
|
+
addCustomValidation: function() {
|
|
302
|
+
var _this = this;
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Displays success or error depending on password validation
|
|
306
|
+
* @private
|
|
307
|
+
* @param {Object} self - The password_confirmation_validation object
|
|
308
|
+
* @see {@link validator.password_confirmation_validation.addCustomValidation addCustomValidation}
|
|
309
|
+
*/
|
|
310
|
+
function validateConfirmation() {
|
|
311
|
+
var validator = Fae.form.validator;
|
|
312
|
+
|
|
313
|
+
if (_this.$password_field.val() === _this.$password_confirmation_field.val()) {
|
|
314
|
+
validator._createSuccessClass(_this.$password_confirmation_field);
|
|
315
|
+
} else {
|
|
316
|
+
var message = ['must match Password'];
|
|
317
|
+
validator.is_valid = false;
|
|
318
|
+
validator._createOrReplaceError(_this.$password_confirmation_field, message);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
this.$password_confirmation_field.on('blur', validateConfirmation);
|
|
323
|
+
|
|
324
|
+
$('form').on('submit', function(ev) {
|
|
325
|
+
_this.is_valid = true;
|
|
326
|
+
validateConfirmation();
|
|
327
|
+
|
|
328
|
+
if (!_this.is_valid) {
|
|
329
|
+
ev.preventDefault();
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
},
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Judge always read the `on: :create` validations, so we need to strip the password presence validation on the user edit form
|
|
337
|
+
*/
|
|
338
|
+
passwordPresenceConditional: function() {
|
|
339
|
+
var $edit_user_password = $('.edit_user #user_password');
|
|
340
|
+
if ($edit_user_password.length) {
|
|
341
|
+
this.stripValidation($edit_user_password, 'presence');
|
|
342
|
+
}
|
|
343
|
+
},
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Length Counter
|
|
347
|
+
* @namespace
|
|
348
|
+
* @memberof! validator
|
|
349
|
+
*/
|
|
350
|
+
length_counter: {
|
|
351
|
+
|
|
352
|
+
init: function(){
|
|
353
|
+
this.findLengthValidations();
|
|
354
|
+
},
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Add counter text to fields that validate based on character counts
|
|
358
|
+
*/
|
|
359
|
+
findLengthValidations: function() {
|
|
360
|
+
var _this = this;
|
|
361
|
+
|
|
362
|
+
$('[data-validate]').each(function () {
|
|
363
|
+
var $this = $(this);
|
|
364
|
+
|
|
365
|
+
if ($this.data('validate').length ) {
|
|
366
|
+
var validations = $this.data('validate');
|
|
367
|
+
|
|
368
|
+
$.grep(validations, function(item){
|
|
369
|
+
if (item.kind === 'length'){
|
|
370
|
+
$this.data('length-max', item.options.maximum);
|
|
371
|
+
_this._setupCounter($this);
|
|
372
|
+
}
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
});
|
|
376
|
+
},
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* Sets up the counter
|
|
380
|
+
* @access protected
|
|
381
|
+
* @param {jQuery} $elem - Input field being counted
|
|
382
|
+
*/
|
|
383
|
+
_setupCounter: function($elem) {
|
|
384
|
+
var _this = this;
|
|
385
|
+
|
|
386
|
+
_this._createCounterDiv($elem);
|
|
387
|
+
_this.updateCounter($elem);
|
|
388
|
+
|
|
389
|
+
$elem
|
|
390
|
+
.keyup(function() {
|
|
391
|
+
_this.updateCounter($elem);
|
|
392
|
+
})
|
|
393
|
+
.keypress(function(e) {
|
|
394
|
+
if (_this._charactersLeft($elem) <= 0) {
|
|
395
|
+
if (e.keyCode !== 8 && e.keyCode !== 46) {
|
|
396
|
+
e.preventDefault();
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
});
|
|
400
|
+
},
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Creates counter HTML
|
|
404
|
+
* @protected
|
|
405
|
+
* @param {jQuery} $elem - Input field to evaluate
|
|
406
|
+
*/
|
|
407
|
+
_createCounterDiv: function($elem) {
|
|
408
|
+
if ($elem.siblings('.counter').length === 0) {
|
|
409
|
+
var text = "Maximum Characters: " + $elem.data('length-max');
|
|
410
|
+
text += " / <span class='characters-left'></span>";
|
|
411
|
+
|
|
412
|
+
var $counter_div = $('<div />', {
|
|
413
|
+
class: 'counter',
|
|
414
|
+
html: '<p>' + text + '</p>'
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
$elem.parent().append( $counter_div );
|
|
418
|
+
}
|
|
419
|
+
},
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* Updates the counter count and class
|
|
423
|
+
* @param {jQuery} $elem - Input field to evaluate
|
|
424
|
+
*/
|
|
425
|
+
updateCounter: function($elem) {
|
|
426
|
+
var $count_span = $elem.siblings('.counter').find('.characters-left');
|
|
427
|
+
if ($count_span.length) {
|
|
428
|
+
var current = this._charactersLeft($elem);
|
|
429
|
+
var text;
|
|
430
|
+
|
|
431
|
+
if (current >= 0) {
|
|
432
|
+
text = 'Characters Left: ';
|
|
433
|
+
$count_span.removeClass('overCount');
|
|
434
|
+
} else {
|
|
435
|
+
text = 'Characters Over: ';
|
|
436
|
+
$count_span.addClass('overCount');
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
$count_span.text(text + Math.abs(current));
|
|
440
|
+
}
|
|
441
|
+
},
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* Calculate character's left
|
|
445
|
+
* @protected
|
|
446
|
+
* @param {jQuery} $elem - Input field being counted
|
|
447
|
+
* @return {integer} The number of characters left
|
|
448
|
+
*/
|
|
449
|
+
_charactersLeft: function($elem) {
|
|
450
|
+
var input_value = $elem.val();
|
|
451
|
+
var current = $elem.data('length-max') - input_value.length;
|
|
452
|
+
// Rails counts a newline as two characters, so let's make up for it here
|
|
453
|
+
current -= (input_value.match(/\n/g) || []).length;
|
|
454
|
+
|
|
455
|
+
return current;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
};
|