effective_bootstrap 0.7.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +644 -0
- data/app/assets/images/icons/activity.svg +13 -0
- data/app/assets/images/icons/airplay.svg +14 -0
- data/app/assets/images/icons/alert-circle.svg +15 -0
- data/app/assets/images/icons/alert-octagon.svg +15 -0
- data/app/assets/images/icons/alert-triangle.svg +15 -0
- data/app/assets/images/icons/align-center.svg +16 -0
- data/app/assets/images/icons/align-justify.svg +16 -0
- data/app/assets/images/icons/align-left.svg +16 -0
- data/app/assets/images/icons/align-right.svg +16 -0
- data/app/assets/images/icons/anchor.svg +15 -0
- data/app/assets/images/icons/aperture.svg +19 -0
- data/app/assets/images/icons/arrow-down-circle.svg +15 -0
- data/app/assets/images/icons/arrow-down-left.svg +14 -0
- data/app/assets/images/icons/arrow-down-right.svg +14 -0
- data/app/assets/images/icons/arrow-down.svg +14 -0
- data/app/assets/images/icons/arrow-left-circle.svg +15 -0
- data/app/assets/images/icons/arrow-left.svg +14 -0
- data/app/assets/images/icons/arrow-right-circle.svg +15 -0
- data/app/assets/images/icons/arrow-right.svg +14 -0
- data/app/assets/images/icons/arrow-up-circle.svg +15 -0
- data/app/assets/images/icons/arrow-up-left.svg +14 -0
- data/app/assets/images/icons/arrow-up-right.svg +14 -0
- data/app/assets/images/icons/arrow-up.svg +14 -0
- data/app/assets/images/icons/at-sign.svg +14 -0
- data/app/assets/images/icons/award.svg +14 -0
- data/app/assets/images/icons/bar-chart-2.svg +15 -0
- data/app/assets/images/icons/bar-chart.svg +15 -0
- data/app/assets/images/icons/battery-charging.svg +15 -0
- data/app/assets/images/icons/battery.svg +14 -0
- data/app/assets/images/icons/bell-off.svg +14 -0
- data/app/assets/images/icons/bell.svg +13 -0
- data/app/assets/images/icons/bluetooth.svg +13 -0
- data/app/assets/images/icons/bold.svg +14 -0
- data/app/assets/images/icons/book-open.svg +14 -0
- data/app/assets/images/icons/book.svg +14 -0
- data/app/assets/images/icons/bookmark.svg +13 -0
- data/app/assets/images/icons/box.svg +15 -0
- data/app/assets/images/icons/briefcase.svg +14 -0
- data/app/assets/images/icons/calendar.svg +16 -0
- data/app/assets/images/icons/camera-off.svg +14 -0
- data/app/assets/images/icons/camera.svg +14 -0
- data/app/assets/images/icons/cast.svg +14 -0
- data/app/assets/images/icons/check-circle.svg +14 -0
- data/app/assets/images/icons/check-square.svg +14 -0
- data/app/assets/images/icons/check.svg +13 -0
- data/app/assets/images/icons/chevron-down.svg +13 -0
- data/app/assets/images/icons/chevron-left.svg +13 -0
- data/app/assets/images/icons/chevron-right.svg +13 -0
- data/app/assets/images/icons/chevron-up.svg +13 -0
- data/app/assets/images/icons/chevrons-down.svg +14 -0
- data/app/assets/images/icons/chevrons-left.svg +14 -0
- data/app/assets/images/icons/chevrons-right.svg +14 -0
- data/app/assets/images/icons/chevrons-up.svg +14 -0
- data/app/assets/images/icons/chrome.svg +17 -0
- data/app/assets/images/icons/circle.svg +13 -0
- data/app/assets/images/icons/clipboard.svg +14 -0
- data/app/assets/images/icons/clock.svg +14 -0
- data/app/assets/images/icons/cloud-drizzle.svg +19 -0
- data/app/assets/images/icons/cloud-lightning.svg +14 -0
- data/app/assets/images/icons/cloud-off.svg +14 -0
- data/app/assets/images/icons/cloud-rain.svg +16 -0
- data/app/assets/images/icons/cloud-snow.svg +19 -0
- data/app/assets/images/icons/cloud.svg +13 -0
- data/app/assets/images/icons/code.svg +14 -0
- data/app/assets/images/icons/codepen.svg +17 -0
- data/app/assets/images/icons/command.svg +13 -0
- data/app/assets/images/icons/compass.svg +14 -0
- data/app/assets/images/icons/copy.svg +14 -0
- data/app/assets/images/icons/corner-down-left.svg +14 -0
- data/app/assets/images/icons/corner-down-right.svg +14 -0
- data/app/assets/images/icons/corner-left-down.svg +14 -0
- data/app/assets/images/icons/corner-left-up.svg +14 -0
- data/app/assets/images/icons/corner-right-down.svg +14 -0
- data/app/assets/images/icons/corner-right-up.svg +14 -0
- data/app/assets/images/icons/corner-up-left.svg +14 -0
- data/app/assets/images/icons/corner-up-right.svg +14 -0
- data/app/assets/images/icons/cpu.svg +22 -0
- data/app/assets/images/icons/credit-card.svg +14 -0
- data/app/assets/images/icons/crop.svg +14 -0
- data/app/assets/images/icons/crosshair.svg +17 -0
- data/app/assets/images/icons/database.svg +15 -0
- data/app/assets/images/icons/delete.svg +15 -0
- data/app/assets/images/icons/disc.svg +14 -0
- data/app/assets/images/icons/dollar-sign.svg +14 -0
- data/app/assets/images/icons/download-cloud.svg +15 -0
- data/app/assets/images/icons/download.svg +15 -0
- data/app/assets/images/icons/droplet.svg +13 -0
- data/app/assets/images/icons/edit-2.svg +13 -0
- data/app/assets/images/icons/edit-3.svg +14 -0
- data/app/assets/images/icons/edit.svg +14 -0
- data/app/assets/images/icons/external-link.svg +15 -0
- data/app/assets/images/icons/eye-off.svg +14 -0
- data/app/assets/images/icons/eye.svg +14 -0
- data/app/assets/images/icons/facebook-white.svg +7 -0
- data/app/assets/images/icons/facebook.svg +13 -0
- data/app/assets/images/icons/fast-forward.svg +14 -0
- data/app/assets/images/icons/feather.svg +15 -0
- data/app/assets/images/icons/file-minus.svg +15 -0
- data/app/assets/images/icons/file-plus.svg +16 -0
- data/app/assets/images/icons/file-text.svg +17 -0
- data/app/assets/images/icons/file.svg +14 -0
- data/app/assets/images/icons/film.svg +20 -0
- data/app/assets/images/icons/filter.svg +13 -0
- data/app/assets/images/icons/flag.svg +14 -0
- data/app/assets/images/icons/folder-minus.svg +14 -0
- data/app/assets/images/icons/folder-plus.svg +15 -0
- data/app/assets/images/icons/folder.svg +13 -0
- data/app/assets/images/icons/git-branch.svg +16 -0
- data/app/assets/images/icons/git-commit.svg +15 -0
- data/app/assets/images/icons/git-merge.svg +15 -0
- data/app/assets/images/icons/git-pull-request.svg +16 -0
- data/app/assets/images/icons/github.svg +13 -0
- data/app/assets/images/icons/gitlab.svg +13 -0
- data/app/assets/images/icons/globe.svg +15 -0
- data/app/assets/images/icons/google.svg +2 -0
- data/app/assets/images/icons/grid.svg +16 -0
- data/app/assets/images/icons/hard-drive.svg +16 -0
- data/app/assets/images/icons/hash.svg +16 -0
- data/app/assets/images/icons/headphones.svg +14 -0
- data/app/assets/images/icons/heart.svg +13 -0
- data/app/assets/images/icons/help-circle.svg +15 -0
- data/app/assets/images/icons/home.svg +14 -0
- data/app/assets/images/icons/image.svg +15 -0
- data/app/assets/images/icons/inbox.svg +14 -0
- data/app/assets/images/icons/info.svg +15 -0
- data/app/assets/images/icons/instagram.svg +15 -0
- data/app/assets/images/icons/italic.svg +15 -0
- data/app/assets/images/icons/layers.svg +15 -0
- data/app/assets/images/icons/layout.svg +15 -0
- data/app/assets/images/icons/life-buoy.svg +19 -0
- data/app/assets/images/icons/link-2.svg +14 -0
- data/app/assets/images/icons/link.svg +14 -0
- data/app/assets/images/icons/linkedin.svg +15 -0
- data/app/assets/images/icons/list.svg +18 -0
- data/app/assets/images/icons/loader.svg +20 -0
- data/app/assets/images/icons/lock.svg +14 -0
- data/app/assets/images/icons/log-in.svg +15 -0
- data/app/assets/images/icons/log-out.svg +15 -0
- data/app/assets/images/icons/mail.svg +14 -0
- data/app/assets/images/icons/map-pin.svg +14 -0
- data/app/assets/images/icons/map.svg +15 -0
- data/app/assets/images/icons/maximize-2.svg +16 -0
- data/app/assets/images/icons/maximize.svg +13 -0
- data/app/assets/images/icons/menu.svg +15 -0
- data/app/assets/images/icons/message-circle.svg +13 -0
- data/app/assets/images/icons/message-square.svg +13 -0
- data/app/assets/images/icons/mic-off.svg +17 -0
- data/app/assets/images/icons/mic.svg +16 -0
- data/app/assets/images/icons/minimize-2.svg +16 -0
- data/app/assets/images/icons/minimize.svg +13 -0
- data/app/assets/images/icons/minus-circle.svg +14 -0
- data/app/assets/images/icons/minus-square.svg +14 -0
- data/app/assets/images/icons/minus.svg +13 -0
- data/app/assets/images/icons/monitor.svg +15 -0
- data/app/assets/images/icons/moon.svg +13 -0
- data/app/assets/images/icons/more-horizontal.svg +15 -0
- data/app/assets/images/icons/more-vertical.svg +15 -0
- data/app/assets/images/icons/move.svg +18 -0
- data/app/assets/images/icons/music.svg +14 -0
- data/app/assets/images/icons/navigation-2.svg +13 -0
- data/app/assets/images/icons/navigation.svg +13 -0
- data/app/assets/images/icons/octagon.svg +13 -0
- data/app/assets/images/icons/package.svg +16 -0
- data/app/assets/images/icons/paperclip.svg +13 -0
- data/app/assets/images/icons/pause-circle.svg +15 -0
- data/app/assets/images/icons/pause.svg +14 -0
- data/app/assets/images/icons/percent.svg +15 -0
- data/app/assets/images/icons/phone-call.svg +13 -0
- data/app/assets/images/icons/phone-forwarded.svg +15 -0
- data/app/assets/images/icons/phone-incoming.svg +15 -0
- data/app/assets/images/icons/phone-missed.svg +15 -0
- data/app/assets/images/icons/phone-off.svg +14 -0
- data/app/assets/images/icons/phone-outgoing.svg +15 -0
- data/app/assets/images/icons/phone.svg +13 -0
- data/app/assets/images/icons/pie-chart.svg +14 -0
- data/app/assets/images/icons/play-circle.svg +14 -0
- data/app/assets/images/icons/play.svg +13 -0
- data/app/assets/images/icons/plus-circle.svg +15 -0
- data/app/assets/images/icons/plus-square.svg +15 -0
- data/app/assets/images/icons/plus.svg +14 -0
- data/app/assets/images/icons/pocket.svg +14 -0
- data/app/assets/images/icons/power.svg +14 -0
- data/app/assets/images/icons/printer.svg +15 -0
- data/app/assets/images/icons/radio.svg +14 -0
- data/app/assets/images/icons/refresh-ccw.svg +15 -0
- data/app/assets/images/icons/refresh-cw.svg +15 -0
- data/app/assets/images/icons/repeat.svg +16 -0
- data/app/assets/images/icons/rewind.svg +14 -0
- data/app/assets/images/icons/rotate-ccw.svg +14 -0
- data/app/assets/images/icons/rotate-cw.svg +14 -0
- data/app/assets/images/icons/rss.svg +15 -0
- data/app/assets/images/icons/save.svg +15 -0
- data/app/assets/images/icons/scissors.svg +17 -0
- data/app/assets/images/icons/search.svg +14 -0
- data/app/assets/images/icons/send.svg +14 -0
- data/app/assets/images/icons/server.svg +16 -0
- data/app/assets/images/icons/settings.svg +14 -0
- data/app/assets/images/icons/share-2.svg +17 -0
- data/app/assets/images/icons/share.svg +15 -0
- data/app/assets/images/icons/shield-off.svg +15 -0
- data/app/assets/images/icons/shield.svg +13 -0
- data/app/assets/images/icons/shopping-bag.svg +15 -0
- data/app/assets/images/icons/shopping-cart.svg +15 -0
- data/app/assets/images/icons/shuffle.svg +17 -0
- data/app/assets/images/icons/sidebar.svg +14 -0
- data/app/assets/images/icons/skip-back.svg +14 -0
- data/app/assets/images/icons/skip-forward.svg +14 -0
- data/app/assets/images/icons/slack.svg +17 -0
- data/app/assets/images/icons/slash.svg +14 -0
- data/app/assets/images/icons/sliders.svg +21 -0
- data/app/assets/images/icons/smartphone.svg +14 -0
- data/app/assets/images/icons/speaker.svg +15 -0
- data/app/assets/images/icons/spinner.svg +1 -0
- data/app/assets/images/icons/square.svg +13 -0
- data/app/assets/images/icons/star.svg +13 -0
- data/app/assets/images/icons/stop-circle.svg +14 -0
- data/app/assets/images/icons/sun.svg +21 -0
- data/app/assets/images/icons/sunrise.svg +20 -0
- data/app/assets/images/icons/sunset.svg +20 -0
- data/app/assets/images/icons/tablet.svg +22 -0
- data/app/assets/images/icons/tag.svg +14 -0
- data/app/assets/images/icons/target.svg +15 -0
- data/app/assets/images/icons/terminal.svg +14 -0
- data/app/assets/images/icons/thermometer.svg +13 -0
- data/app/assets/images/icons/thumbs-down.svg +13 -0
- data/app/assets/images/icons/thumbs-up.svg +13 -0
- data/app/assets/images/icons/toggle-left.svg +14 -0
- data/app/assets/images/icons/toggle-right.svg +14 -0
- data/app/assets/images/icons/trash-2.svg +16 -0
- data/app/assets/images/icons/trash.svg +14 -0
- data/app/assets/images/icons/trending-down.svg +14 -0
- data/app/assets/images/icons/trending-up.svg +14 -0
- data/app/assets/images/icons/triangle.svg +13 -0
- data/app/assets/images/icons/truck.svg +16 -0
- data/app/assets/images/icons/tv.svg +14 -0
- data/app/assets/images/icons/twitter.svg +13 -0
- data/app/assets/images/icons/type.svg +15 -0
- data/app/assets/images/icons/umbrella.svg +13 -0
- data/app/assets/images/icons/underline.svg +14 -0
- data/app/assets/images/icons/unlock.svg +14 -0
- data/app/assets/images/icons/upload-cloud.svg +16 -0
- data/app/assets/images/icons/upload.svg +15 -0
- data/app/assets/images/icons/user-check.svg +15 -0
- data/app/assets/images/icons/user-minus.svg +15 -0
- data/app/assets/images/icons/user-plus.svg +16 -0
- data/app/assets/images/icons/user-x.svg +16 -0
- data/app/assets/images/icons/user.svg +14 -0
- data/app/assets/images/icons/users.svg +16 -0
- data/app/assets/images/icons/video-off.svg +14 -0
- data/app/assets/images/icons/video.svg +14 -0
- data/app/assets/images/icons/voicemail.svg +15 -0
- data/app/assets/images/icons/volume-1.svg +14 -0
- data/app/assets/images/icons/volume-2.svg +14 -0
- data/app/assets/images/icons/volume-x.svg +15 -0
- data/app/assets/images/icons/volume.svg +13 -0
- data/app/assets/images/icons/watch.svg +15 -0
- data/app/assets/images/icons/wifi-off.svg +19 -0
- data/app/assets/images/icons/wifi.svg +16 -0
- data/app/assets/images/icons/wind.svg +13 -0
- data/app/assets/images/icons/x-circle.svg +15 -0
- data/app/assets/images/icons/x-square.svg +15 -0
- data/app/assets/images/icons/x.svg +14 -0
- data/app/assets/images/icons/zap-off.svg +16 -0
- data/app/assets/images/icons/zap.svg +13 -0
- data/app/assets/images/icons/zoom-in.svg +16 -0
- data/app/assets/images/icons/zoom-out.svg +15 -0
- data/app/assets/javascripts/effective_bootstrap.js +25 -0
- data/app/assets/javascripts/effective_bootstrap/base.js.coffee +22 -0
- data/app/assets/javascripts/effective_bootstrap/confirm.js.coffee.erb +23 -0
- data/app/assets/javascripts/effective_bootstrap/form.js.coffee +182 -0
- data/app/assets/javascripts/effective_bootstrap/logic.js.coffee +64 -0
- data/app/assets/javascripts/effective_bootstrap/other.js.coffee +4 -0
- data/app/assets/javascripts/effective_bootstrap/tabs.js +14 -0
- data/app/assets/javascripts/effective_checks/initialize.js.coffee +7 -0
- data/app/assets/javascripts/effective_checks/input.js +1 -0
- data/app/assets/javascripts/effective_ck_editor/initialize.js.coffee +72 -0
- data/app/assets/javascripts/effective_ck_editor/input.js +1 -0
- data/app/assets/javascripts/effective_clear/initialize.js.coffee +3 -0
- data/app/assets/javascripts/effective_clear/input.js +1 -0
- data/app/assets/javascripts/effective_date/initialize.js.coffee +7 -0
- data/app/assets/javascripts/effective_date/input.js +5 -0
- data/app/assets/javascripts/effective_datetime/bootstrap-datetimepicker.js +2636 -0
- data/app/assets/javascripts/effective_datetime/initialize.js.coffee +7 -0
- data/app/assets/javascripts/effective_datetime/input.js +5 -0
- data/app/assets/javascripts/effective_datetime/overrides.js.coffee +45 -0
- data/app/assets/javascripts/effective_datetime/turbolinks.js.coffee +5 -0
- data/app/assets/javascripts/effective_editor/image-drop-and-paste.js +3 -0
- data/app/assets/javascripts/effective_editor/image-resize.js +2 -0
- data/app/assets/javascripts/effective_editor/initialize.js.coffee +138 -0
- data/app/assets/javascripts/effective_editor/input.js +4 -0
- data/app/assets/javascripts/effective_editor/quill.js +11496 -0
- data/app/assets/javascripts/effective_file/initialize.js.coffee +19 -0
- data/app/assets/javascripts/effective_file/input.js +1 -0
- data/app/assets/javascripts/effective_integer/initialize.js.coffee +6 -0
- data/app/assets/javascripts/effective_integer/input.js +1 -0
- data/app/assets/javascripts/effective_number_text/initialize.js.coffee +6 -0
- data/app/assets/javascripts/effective_number_text/input.js +1 -0
- data/app/assets/javascripts/effective_percent/initialize.js.coffee +39 -0
- data/app/assets/javascripts/effective_percent/input.js +1 -0
- data/app/assets/javascripts/effective_phone/initialize.js.coffee +4 -0
- data/app/assets/javascripts/effective_phone/input.js +2 -0
- data/app/assets/javascripts/effective_phone/jquery.maskedInput.js +182 -0
- data/app/assets/javascripts/effective_price/initialize.js.coffee +43 -0
- data/app/assets/javascripts/effective_price/input.js +1 -0
- data/app/assets/javascripts/effective_radio/initialize.js.coffee +36 -0
- data/app/assets/javascripts/effective_radio/input.js +1 -0
- data/app/assets/javascripts/effective_select/initialize.js.coffee +56 -0
- data/app/assets/javascripts/effective_select/input.js +3 -0
- data/app/assets/javascripts/effective_select/overrides.js.coffee +60 -0
- data/app/assets/javascripts/effective_select/select2.js +5747 -0
- data/app/assets/javascripts/effective_select_or_text/initialize.js +30 -0
- data/app/assets/javascripts/effective_select_or_text/input.js +1 -0
- data/app/assets/javascripts/effective_time/initialize.js.coffee +7 -0
- data/app/assets/javascripts/effective_time/input.js +5 -0
- data/app/assets/javascripts/effective_time_zone_select/initialize.js.coffee +13 -0
- data/app/assets/javascripts/effective_time_zone_select/input.js +1 -0
- data/app/assets/javascripts/moment/locale/af.js +72 -0
- data/app/assets/javascripts/moment/locale/ar-dz.js +58 -0
- data/app/assets/javascripts/moment/locale/ar-kw.js +58 -0
- data/app/assets/javascripts/moment/locale/ar-ly.js +121 -0
- data/app/assets/javascripts/moment/locale/ar-ma.js +58 -0
- data/app/assets/javascripts/moment/locale/ar-sa.js +103 -0
- data/app/assets/javascripts/moment/locale/ar-tn.js +58 -0
- data/app/assets/javascripts/moment/locale/ar.js +134 -0
- data/app/assets/javascripts/moment/locale/az.js +104 -0
- data/app/assets/javascripts/moment/locale/be.js +131 -0
- data/app/assets/javascripts/moment/locale/bg.js +89 -0
- data/app/assets/javascripts/moment/locale/bm.js +57 -0
- data/app/assets/javascripts/moment/locale/bn.js +118 -0
- data/app/assets/javascripts/moment/locale/bo.js +118 -0
- data/app/assets/javascripts/moment/locale/br.js +107 -0
- data/app/assets/javascripts/moment/locale/bs.js +150 -0
- data/app/assets/javascripts/moment/locale/ca.js +87 -0
- data/app/assets/javascripts/moment/locale/cs.js +171 -0
- data/app/assets/javascripts/moment/locale/cv.js +62 -0
- data/app/assets/javascripts/moment/locale/cy.js +79 -0
- data/app/assets/javascripts/moment/locale/da.js +59 -0
- data/app/assets/javascripts/moment/locale/de-at.js +75 -0
- data/app/assets/javascripts/moment/locale/de-ch.js +75 -0
- data/app/assets/javascripts/moment/locale/de.js +75 -0
- data/app/assets/javascripts/moment/locale/dv.js +98 -0
- data/app/assets/javascripts/moment/locale/el.js +99 -0
- data/app/assets/javascripts/moment/locale/en-SG.js +66 -0
- data/app/assets/javascripts/moment/locale/en-au.js +66 -0
- data/app/assets/javascripts/moment/locale/en-ca.js +62 -0
- data/app/assets/javascripts/moment/locale/en-gb.js +66 -0
- data/app/assets/javascripts/moment/locale/en-ie.js +66 -0
- data/app/assets/javascripts/moment/locale/en-il.js +61 -0
- data/app/assets/javascripts/moment/locale/en-nz.js +66 -0
- data/app/assets/javascripts/moment/locale/eo.js +70 -0
- data/app/assets/javascripts/moment/locale/es-do.js +91 -0
- data/app/assets/javascripts/moment/locale/es-us.js +91 -0
- data/app/assets/javascripts/moment/locale/es.js +91 -0
- data/app/assets/javascripts/moment/locale/et.js +79 -0
- data/app/assets/javascripts/moment/locale/eu.js +65 -0
- data/app/assets/javascripts/moment/locale/fa.js +105 -0
- data/app/assets/javascripts/moment/locale/fi.js +108 -0
- data/app/assets/javascripts/moment/locale/fo.js +59 -0
- data/app/assets/javascripts/moment/locale/fr-ca.js +73 -0
- data/app/assets/javascripts/moment/locale/fr-ch.js +77 -0
- data/app/assets/javascripts/moment/locale/fr.js +82 -0
- data/app/assets/javascripts/moment/locale/fy.js +74 -0
- data/app/assets/javascripts/moment/locale/ga.js +76 -0
- data/app/assets/javascripts/moment/locale/gd.js +75 -0
- data/app/assets/javascripts/moment/locale/gl.js +76 -0
- data/app/assets/javascripts/moment/locale/gom-latn.js +122 -0
- data/app/assets/javascripts/moment/locale/gu.js +123 -0
- data/app/assets/javascripts/moment/locale/he.js +96 -0
- data/app/assets/javascripts/moment/locale/hi.js +123 -0
- data/app/assets/javascripts/moment/locale/hr.js +153 -0
- data/app/assets/javascripts/moment/locale/hu.js +109 -0
- data/app/assets/javascripts/moment/locale/hy-am.js +94 -0
- data/app/assets/javascripts/moment/locale/id.js +81 -0
- data/app/assets/javascripts/moment/locale/is.js +131 -0
- data/app/assets/javascripts/moment/locale/it-ch.js +68 -0
- data/app/assets/javascripts/moment/locale/it.js +68 -0
- data/app/assets/javascripts/moment/locale/ja.js +91 -0
- data/app/assets/javascripts/moment/locale/jv.js +81 -0
- data/app/assets/javascripts/moment/locale/ka.js +88 -0
- data/app/assets/javascripts/moment/locale/kk.js +86 -0
- data/app/assets/javascripts/moment/locale/km.js +109 -0
- data/app/assets/javascripts/moment/locale/kn.js +125 -0
- data/app/assets/javascripts/moment/locale/ko.js +80 -0
- data/app/assets/javascripts/moment/locale/ku.js +118 -0
- data/app/assets/javascripts/moment/locale/ky.js +86 -0
- data/app/assets/javascripts/moment/locale/lb.js +135 -0
- data/app/assets/javascripts/moment/locale/lo.js +69 -0
- data/app/assets/javascripts/moment/locale/lt.js +117 -0
- data/app/assets/javascripts/moment/locale/lv.js +96 -0
- data/app/assets/javascripts/moment/locale/me.js +111 -0
- data/app/assets/javascripts/moment/locale/mi.js +63 -0
- data/app/assets/javascripts/moment/locale/mk.js +89 -0
- data/app/assets/javascripts/moment/locale/ml.js +80 -0
- data/app/assets/javascripts/moment/locale/mn.js +103 -0
- data/app/assets/javascripts/moment/locale/mr.js +159 -0
- data/app/assets/javascripts/moment/locale/ms-my.js +81 -0
- data/app/assets/javascripts/moment/locale/ms.js +81 -0
- data/app/assets/javascripts/moment/locale/mt.js +59 -0
- data/app/assets/javascripts/moment/locale/my.js +92 -0
- data/app/assets/javascripts/moment/locale/nb.js +61 -0
- data/app/assets/javascripts/moment/locale/ne.js +122 -0
- data/app/assets/javascripts/moment/locale/nl-be.js +86 -0
- data/app/assets/javascripts/moment/locale/nl.js +86 -0
- data/app/assets/javascripts/moment/locale/nn.js +59 -0
- data/app/assets/javascripts/moment/locale/pa-in.js +123 -0
- data/app/assets/javascripts/moment/locale/pl.js +125 -0
- data/app/assets/javascripts/moment/locale/pt-br.js +60 -0
- data/app/assets/javascripts/moment/locale/pt.js +64 -0
- data/app/assets/javascripts/moment/locale/ro.js +74 -0
- data/app/assets/javascripts/moment/locale/ru.js +181 -0
- data/app/assets/javascripts/moment/locale/sd.js +97 -0
- data/app/assets/javascripts/moment/locale/se.js +59 -0
- data/app/assets/javascripts/moment/locale/si.js +70 -0
- data/app/assets/javascripts/moment/locale/sk.js +155 -0
- data/app/assets/javascripts/moment/locale/sl.js +172 -0
- data/app/assets/javascripts/moment/locale/sq.js +67 -0
- data/app/assets/javascripts/moment/locale/sr-cyrl.js +110 -0
- data/app/assets/javascripts/moment/locale/sr.js +110 -0
- data/app/assets/javascripts/moment/locale/ss.js +87 -0
- data/app/assets/javascripts/moment/locale/sv.js +68 -0
- data/app/assets/javascripts/moment/locale/sw.js +58 -0
- data/app/assets/javascripts/moment/locale/ta.js +128 -0
- data/app/assets/javascripts/moment/locale/te.js +88 -0
- data/app/assets/javascripts/moment/locale/tet.js +66 -0
- data/app/assets/javascripts/moment/locale/tg.js +115 -0
- data/app/assets/javascripts/moment/locale/th.js +66 -0
- data/app/assets/javascripts/moment/locale/tl-ph.js +61 -0
- data/app/assets/javascripts/moment/locale/tlh.js +121 -0
- data/app/assets/javascripts/moment/locale/tr.js +93 -0
- data/app/assets/javascripts/moment/locale/tzl.js +90 -0
- data/app/assets/javascripts/moment/locale/tzm-latn.js +57 -0
- data/app/assets/javascripts/moment/locale/tzm.js +57 -0
- data/app/assets/javascripts/moment/locale/ug-cn.js +118 -0
- data/app/assets/javascripts/moment/locale/uk.js +153 -0
- data/app/assets/javascripts/moment/locale/ur.js +97 -0
- data/app/assets/javascripts/moment/locale/uz-latn.js +57 -0
- data/app/assets/javascripts/moment/locale/uz.js +57 -0
- data/app/assets/javascripts/moment/locale/vi.js +78 -0
- data/app/assets/javascripts/moment/locale/x-pseudo.js +67 -0
- data/app/assets/javascripts/moment/locale/yo.js +59 -0
- data/app/assets/javascripts/moment/locale/zh-cn.js +109 -0
- data/app/assets/javascripts/moment/locale/zh-hk.js +102 -0
- data/app/assets/javascripts/moment/locale/zh-tw.js +102 -0
- data/app/assets/javascripts/moment/moment.js +4603 -0
- data/app/assets/stylesheets/effective_bootstrap.scss +12 -0
- data/app/assets/stylesheets/effective_bootstrap/base.scss +4 -0
- data/app/assets/stylesheets/effective_bootstrap/forms.scss +65 -0
- data/app/assets/stylesheets/effective_bootstrap/icons.scss +67 -0
- data/app/assets/stylesheets/effective_bootstrap/overrides.scss +14 -0
- data/app/assets/stylesheets/effective_checks/input.scss +8 -0
- data/app/assets/stylesheets/effective_date/input.scss +1 -0
- data/app/assets/stylesheets/effective_datetime/bootstrap-datetimepicker.scss +374 -0
- data/app/assets/stylesheets/effective_datetime/input.scss +2 -0
- data/app/assets/stylesheets/effective_datetime/overrides.scss +31 -0
- data/app/assets/stylesheets/effective_editor/input.scss +2 -0
- data/app/assets/stylesheets/effective_editor/overrides.scss +25 -0
- data/app/assets/stylesheets/effective_editor/quill.scss +948 -0
- data/app/assets/stylesheets/effective_file/input.scss +46 -0
- data/app/assets/stylesheets/effective_radio/input.scss +29 -0
- data/app/assets/stylesheets/effective_select/bootstrap-theme.css +564 -0
- data/app/assets/stylesheets/effective_select/input.scss +3 -0
- data/app/assets/stylesheets/effective_select/overrides.scss +115 -0
- data/app/assets/stylesheets/effective_select/select2.css +484 -0
- data/app/assets/stylesheets/effective_select_or_text/input.scss +6 -0
- data/app/assets/stylesheets/effective_time/input.scss +1 -0
- data/app/helpers/effective_bootstrap_helper.rb +371 -0
- data/app/helpers/effective_editor_helper.rb +29 -0
- data/app/helpers/effective_form_builder_helper.rb +74 -0
- data/app/helpers/effective_icons_helper.rb +51 -0
- data/app/models/effective/access_denied.rb +17 -0
- data/app/models/effective/form_builder.rb +199 -0
- data/app/models/effective/form_input.rb +434 -0
- data/app/models/effective/form_inputs/check_box.rb +70 -0
- data/app/models/effective/form_inputs/checks.rb +99 -0
- data/app/models/effective/form_inputs/ck_editor.rb +48 -0
- data/app/models/effective/form_inputs/clear.rb +22 -0
- data/app/models/effective/form_inputs/collection_input.rb +168 -0
- data/app/models/effective/form_inputs/date_field.rb +34 -0
- data/app/models/effective/form_inputs/datetime_field.rb +83 -0
- data/app/models/effective/form_inputs/delete.rb +26 -0
- data/app/models/effective/form_inputs/editor.rb +88 -0
- data/app/models/effective/form_inputs/email_cc_field.rb +19 -0
- data/app/models/effective/form_inputs/email_field.rb +20 -0
- data/app/models/effective/form_inputs/error_field.rb +47 -0
- data/app/models/effective/form_inputs/file_field.rb +135 -0
- data/app/models/effective/form_inputs/float_field.rb +20 -0
- data/app/models/effective/form_inputs/form_group.rb +15 -0
- data/app/models/effective/form_inputs/integer_field.rb +18 -0
- data/app/models/effective/form_inputs/number_field.rb +10 -0
- data/app/models/effective/form_inputs/number_text_field.rb +15 -0
- data/app/models/effective/form_inputs/password_field.rb +24 -0
- data/app/models/effective/form_inputs/percent_field.rb +38 -0
- data/app/models/effective/form_inputs/phone_field.rb +39 -0
- data/app/models/effective/form_inputs/price_field.rb +32 -0
- data/app/models/effective/form_inputs/radios.rb +175 -0
- data/app/models/effective/form_inputs/remote_link_to.rb +30 -0
- data/app/models/effective/form_inputs/reset.rb +22 -0
- data/app/models/effective/form_inputs/save.rb +22 -0
- data/app/models/effective/form_inputs/search_field.rb +15 -0
- data/app/models/effective/form_inputs/select.rb +176 -0
- data/app/models/effective/form_inputs/select_or_text.rb +70 -0
- data/app/models/effective/form_inputs/static_field.rb +41 -0
- data/app/models/effective/form_inputs/submit.rb +109 -0
- data/app/models/effective/form_inputs/text_area.rb +11 -0
- data/app/models/effective/form_inputs/text_field.rb +6 -0
- data/app/models/effective/form_inputs/time_field.rb +34 -0
- data/app/models/effective/form_inputs/time_zone_select.rb +15 -0
- data/app/models/effective/form_inputs/url_field.rb +20 -0
- data/app/models/effective/form_logic.rb +45 -0
- data/app/models/effective/form_logics/hide_if.rb +39 -0
- data/app/models/effective/form_logics/show_if.rb +39 -0
- data/app/models/effective/form_logics/show_if_any.rb +42 -0
- data/app/views/effective/style_guide/__fields.html.haml +43 -0
- data/app/views/effective/style_guide/__inline_fields.html.haml +4 -0
- data/app/views/effective/style_guide/_effective_form_with.html.haml +26 -0
- data/app/views/effective/style_guide/_feather_icons.html.haml +9 -0
- data/config/effective_bootstrap.rb +27 -0
- data/lib/effective_bootstrap.rb +33 -0
- data/lib/effective_bootstrap/engine.rb +15 -0
- data/lib/effective_bootstrap/version.rb +3 -0
- data/lib/generators/effective_bootstrap/install_generator.rb +14 -0
- metadata +650 -0
@@ -0,0 +1,51 @@
|
|
1
|
+
module EffectiveIconsHelper
|
2
|
+
|
3
|
+
# icon('check', class: 'big-4')
|
4
|
+
# icon('check', class: 'small-3')
|
5
|
+
def icon(svg, options = {})
|
6
|
+
svg = svg.to_s.chomp('.svg')
|
7
|
+
|
8
|
+
options.reverse_merge!(nocomment: true)
|
9
|
+
options[:class] = [options[:class], "eb-icon eb-icon-#{svg}"].compact.join(' ')
|
10
|
+
|
11
|
+
inline_svg_tag("icons/#{svg}.svg", options)
|
12
|
+
end
|
13
|
+
|
14
|
+
def icon_to(svg, url, options = {})
|
15
|
+
link_to(icon(svg), url, options)
|
16
|
+
end
|
17
|
+
|
18
|
+
def new_icon_to(path, options = {})
|
19
|
+
icon_to('plus', path, { title: 'New' }.merge(options))
|
20
|
+
end
|
21
|
+
|
22
|
+
def show_icon_to(path, options = {})
|
23
|
+
icon_to('eye', path, { title: 'Show' }.merge(options))
|
24
|
+
end
|
25
|
+
|
26
|
+
def edit_icon_to(path, options = {})
|
27
|
+
icon_to('edit', path, { title: 'Edit' }.merge(options))
|
28
|
+
end
|
29
|
+
|
30
|
+
def destroy_icon_to(path, options = {})
|
31
|
+
defaults = { title: 'Destroy', data: { method: :delete, confirm: 'Delete this item?' } }
|
32
|
+
icon_to('trash', path, defaults.merge(options))
|
33
|
+
end
|
34
|
+
|
35
|
+
def settings_icon_to(path, options = {})
|
36
|
+
icon_to('cog', path, { title: 'Settings' }.merge(options))
|
37
|
+
end
|
38
|
+
|
39
|
+
def ok_icon_to(path, options = {})
|
40
|
+
icon_to('ok', path, { title: 'OK' }.merge(options))
|
41
|
+
end
|
42
|
+
|
43
|
+
def approve_icon_to(path, options = {})
|
44
|
+
icon_to('ok', path, { title: 'Approve' }.merge(options))
|
45
|
+
end
|
46
|
+
|
47
|
+
def remove_icon_to(path, options = {})
|
48
|
+
icon_to('remove', path, { title: 'Remove' }.merge(options))
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
unless defined?(Effective::AccessDenied)
|
2
|
+
module Effective
|
3
|
+
class AccessDenied < StandardError
|
4
|
+
attr_reader :action, :subject
|
5
|
+
|
6
|
+
def initialize(message = nil, action = nil, subject = nil)
|
7
|
+
@message = message
|
8
|
+
@action = action
|
9
|
+
@subject = subject
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
@message || I18n.t(:'unauthorized.default', :default => 'Access Denied')
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,199 @@
|
|
1
|
+
module Effective
|
2
|
+
class FormBuilder < ActionView::Helpers::FormBuilder
|
3
|
+
|
4
|
+
attr_accessor :template, :layout, :action, :readonly, :disabled, :remote
|
5
|
+
|
6
|
+
delegate :content_tag, to: :template
|
7
|
+
|
8
|
+
def initialize(object_name, object, template, options)
|
9
|
+
@template = template
|
10
|
+
|
11
|
+
@layout = (options.delete(:layout) || :vertical).to_sym
|
12
|
+
@action = options.delete(:action)
|
13
|
+
@readonly = options.delete(:readonly)
|
14
|
+
@disabled = options.delete(:disabled)
|
15
|
+
@remote = options[:remote]
|
16
|
+
|
17
|
+
super
|
18
|
+
end
|
19
|
+
|
20
|
+
alias_method :super_number_field, :number_field
|
21
|
+
alias_method :super_text_field, :text_field
|
22
|
+
alias_method :super_text_area, :text_area
|
23
|
+
|
24
|
+
def clear(name = 'Clear', options = {})
|
25
|
+
(options = name; name = 'Clear') if name.kind_of?(Hash)
|
26
|
+
Effective::FormInputs::Clear.new(name, options, builder: self).to_html
|
27
|
+
end
|
28
|
+
|
29
|
+
def check_box(name, options = {})
|
30
|
+
Effective::FormInputs::CheckBox.new(name, options, builder: self).to_html {
|
31
|
+
checked_value = options.fetch(:checked_value, '1')
|
32
|
+
unchecked_value = options.fetch(:unchecked_value, '0')
|
33
|
+
super(name, options.except(:checked_value, :unchecked_value), checked_value, unchecked_value)
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
def checks(name, choices = nil, *args)
|
38
|
+
options = args.extract_options!.merge!(collection: choices)
|
39
|
+
Effective::FormInputs::Checks.new(name, options, builder: self).to_html
|
40
|
+
end
|
41
|
+
|
42
|
+
def ck_editor(name, options = {}, &block)
|
43
|
+
Effective::FormInputs::CkEditor.new(name, options, builder: self).to_html(&block)
|
44
|
+
end
|
45
|
+
|
46
|
+
def date_field(name, options = {})
|
47
|
+
Effective::FormInputs::DateField.new(name, options, builder: self).to_html { super(name, options) }
|
48
|
+
end
|
49
|
+
|
50
|
+
def datetime_field(name, options = {})
|
51
|
+
Effective::FormInputs::DatetimeField.new(name, options, builder: self).to_html { super(name, options) }
|
52
|
+
end
|
53
|
+
|
54
|
+
def delete(name = 'Remove', url = nil, options = {}, &block)
|
55
|
+
options[:href] ||= url
|
56
|
+
Effective::FormInputs::Delete.new(name, options, builder: self).to_html(&block)
|
57
|
+
end
|
58
|
+
|
59
|
+
def editor(name, options = {}, &block)
|
60
|
+
Effective::FormInputs::Editor.new(name, options, builder: self).to_html(&block)
|
61
|
+
end
|
62
|
+
|
63
|
+
def email_field(name, options = {})
|
64
|
+
Effective::FormInputs::EmailField.new(name, options, builder: self).to_html { super(name, options) }
|
65
|
+
end
|
66
|
+
|
67
|
+
def email_cc_field(name, options = {})
|
68
|
+
Effective::FormInputs::EmailCcField.new(name, options, builder: self).to_html
|
69
|
+
end
|
70
|
+
|
71
|
+
def error(name = nil, options = {})
|
72
|
+
Effective::FormInputs::ErrorField.new(name, options, builder: self).to_html()
|
73
|
+
end
|
74
|
+
alias_method :errors, :error
|
75
|
+
|
76
|
+
def file_field(name, options = {})
|
77
|
+
Effective::FormInputs::FileField.new(name, options, builder: self).to_html { super(name, options) }
|
78
|
+
end
|
79
|
+
|
80
|
+
def float_field(name, options = {})
|
81
|
+
Effective::FormInputs::FloatField.new(name, options, builder: self).to_html
|
82
|
+
end
|
83
|
+
|
84
|
+
def form_group(name = nil, options = {}, &block)
|
85
|
+
Effective::FormInputs::FormGroup.new(name, options, builder: self).to_html(&block)
|
86
|
+
end
|
87
|
+
|
88
|
+
def integer_field(name, options = {})
|
89
|
+
Effective::FormInputs::IntegerField.new(name, options, builder: self).to_html
|
90
|
+
end
|
91
|
+
|
92
|
+
# This is gonna be a post?
|
93
|
+
def remote_link_to(name, url, options = {}, &block)
|
94
|
+
options[:href] ||= url
|
95
|
+
Effective::FormInputs::RemoteLinkTo.new(name, options, builder: self).to_html(&block)
|
96
|
+
end
|
97
|
+
|
98
|
+
def search_field(name, options = {})
|
99
|
+
Effective::FormInputs::SearchField.new(name, options, builder: self).to_html { super(name, options) }
|
100
|
+
end
|
101
|
+
|
102
|
+
def number_field(name, options = {})
|
103
|
+
Effective::FormInputs::NumberField.new(name, options, builder: self).to_html { super(name, options) }
|
104
|
+
end
|
105
|
+
|
106
|
+
def number_text_field(name, options = {})
|
107
|
+
Effective::FormInputs::NumberTextField.new(name, options, builder: self).to_html
|
108
|
+
end
|
109
|
+
|
110
|
+
def password_field(name, options = {})
|
111
|
+
Effective::FormInputs::PasswordField.new(name, options, builder: self).to_html { super(name, options) }
|
112
|
+
end
|
113
|
+
|
114
|
+
def percent_field(name, options = {})
|
115
|
+
Effective::FormInputs::PercentField.new(name, options, builder: self).to_html
|
116
|
+
end
|
117
|
+
|
118
|
+
def phone_field(name, options = {})
|
119
|
+
Effective::FormInputs::PhoneField.new(name, options, builder: self).to_html { super(name, options) }
|
120
|
+
end
|
121
|
+
alias_method :tel_field, :phone_field
|
122
|
+
alias_method :telephone_field, :phone_field
|
123
|
+
|
124
|
+
def price_field(name, options = {})
|
125
|
+
Effective::FormInputs::PriceField.new(name, options, builder: self).to_html { super(name, options) }
|
126
|
+
end
|
127
|
+
|
128
|
+
def save(name = 'Save', options = {})
|
129
|
+
(options = name; name = 'Save') if name.kind_of?(Hash)
|
130
|
+
Effective::FormInputs::Save.new(name, options, builder: self).to_html { super(name, options) }
|
131
|
+
end
|
132
|
+
|
133
|
+
def select(name, choices = nil, *args)
|
134
|
+
options = args.extract_options!.merge!(collection: choices)
|
135
|
+
Effective::FormInputs::Select.new(name, options, builder: self).to_html
|
136
|
+
end
|
137
|
+
|
138
|
+
def select_or_text(name, name_text, choices = nil, *args)
|
139
|
+
options = args.extract_options!.merge!(name_text: name_text, collection: choices)
|
140
|
+
Effective::FormInputs::SelectOrText.new(name, options, builder: self).to_html
|
141
|
+
end
|
142
|
+
|
143
|
+
def submit(name = 'Save', options = {}, &block)
|
144
|
+
(options = name; name = 'Save') if name.kind_of?(Hash)
|
145
|
+
Effective::FormInputs::Submit.new(name, options, builder: self).to_html(&block)
|
146
|
+
end
|
147
|
+
|
148
|
+
def static_field(name, options = {}, &block)
|
149
|
+
options = { value: options } if options.kind_of?(String)
|
150
|
+
Effective::FormInputs::StaticField.new(name, options, builder: self).to_html(&block)
|
151
|
+
end
|
152
|
+
|
153
|
+
def radios(name, choices = nil, *args)
|
154
|
+
options = args.extract_options!.merge!(collection: choices)
|
155
|
+
Effective::FormInputs::Radios.new(name, options, builder: self).to_html
|
156
|
+
end
|
157
|
+
|
158
|
+
def reset(name = 'Reset', options = {})
|
159
|
+
(options = name; name = 'Reset') if name.kind_of?(Hash)
|
160
|
+
Effective::FormInputs::Reset.new(name, options, builder: self).to_html
|
161
|
+
end
|
162
|
+
|
163
|
+
def text_area(name, options = {})
|
164
|
+
Effective::FormInputs::TextArea.new(name, options, builder: self).to_html { super(name, options) }
|
165
|
+
end
|
166
|
+
|
167
|
+
def text_field(name, options = {})
|
168
|
+
Effective::FormInputs::TextField.new(name, options, builder: self).to_html { super(name, options) }
|
169
|
+
end
|
170
|
+
|
171
|
+
def time_field(name, options = {})
|
172
|
+
Effective::FormInputs::TimeField.new(name, options, builder: self).to_html { super(name, options) }
|
173
|
+
end
|
174
|
+
|
175
|
+
def time_zone_select(name, options = {})
|
176
|
+
opts = options.merge(collection: Effective::FormInputs::TimeZoneSelect.time_zone_collection)
|
177
|
+
Effective::FormInputs::TimeZoneSelect.new(name, opts, builder: self).to_html
|
178
|
+
end
|
179
|
+
|
180
|
+
def url_field(name, options = {})
|
181
|
+
Effective::FormInputs::UrlField.new(name, options, builder: self).to_html { super(name, options) }
|
182
|
+
end
|
183
|
+
|
184
|
+
# Logics
|
185
|
+
def hide_if(*args, &block)
|
186
|
+
Effective::FormLogics::HideIf.new(*args, builder: self).to_html(&block)
|
187
|
+
end
|
188
|
+
|
189
|
+
def show_if(*args, &block)
|
190
|
+
Effective::FormLogics::ShowIf.new(*args, builder: self).to_html(&block)
|
191
|
+
end
|
192
|
+
|
193
|
+
def show_if_any(*args, &block)
|
194
|
+
Effective::FormLogics::ShowIfAny.new(*args, builder: self).to_html(&block)
|
195
|
+
end
|
196
|
+
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
@@ -0,0 +1,434 @@
|
|
1
|
+
module Effective
|
2
|
+
class FormInput
|
3
|
+
attr_accessor :name, :options
|
4
|
+
|
5
|
+
BLANK = ''.html_safe
|
6
|
+
EXCLUSIVE_CLASS_PREFIXES = [] # None
|
7
|
+
EXCLUSIVE_CLASS_SUFFIXES = ['-primary', '-secondary', '-success', '-danger', '-warning', '-info', '-light', '-dark']
|
8
|
+
|
9
|
+
delegate :object, to: :@builder
|
10
|
+
delegate :capture, :content_tag, :link_to, :icon, :asset_path, to: :@template
|
11
|
+
|
12
|
+
# So this takes in the options for an entire form group.
|
13
|
+
def initialize(name, options, builder:, html_options: nil)
|
14
|
+
@builder = builder
|
15
|
+
@template = builder.template
|
16
|
+
|
17
|
+
@name = name
|
18
|
+
@options = extract_options!(options, html_options: html_options)
|
19
|
+
apply_input_options!
|
20
|
+
end
|
21
|
+
|
22
|
+
def input_group_options
|
23
|
+
{ input_group: { class: 'input-group' }, prepend: false, append: false }
|
24
|
+
end
|
25
|
+
|
26
|
+
def input_html_options
|
27
|
+
{ class: 'form-control' }
|
28
|
+
end
|
29
|
+
|
30
|
+
def input_js_options
|
31
|
+
{}
|
32
|
+
end
|
33
|
+
|
34
|
+
def label_options
|
35
|
+
case layout
|
36
|
+
when :horizontal
|
37
|
+
{ class: 'col-sm-2 col-form-label'}
|
38
|
+
when :inline
|
39
|
+
{ class: 'sr-only' }
|
40
|
+
else
|
41
|
+
{ }
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def feedback_options
|
46
|
+
case layout
|
47
|
+
when :inline
|
48
|
+
false
|
49
|
+
else
|
50
|
+
{ valid: { class: 'valid-feedback' }, invalid: { class: 'invalid-feedback' } }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def hint_options
|
55
|
+
case layout
|
56
|
+
when :inline
|
57
|
+
{ tag: :small, class: 'text-muted', id: "#{tag_id}_hint" }
|
58
|
+
else
|
59
|
+
{ tag: :small, class: 'form-text text-muted', id: "#{tag_id}_hint" }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def wrapper_options
|
64
|
+
case layout
|
65
|
+
when :horizontal
|
66
|
+
{ class: 'form-group row' }
|
67
|
+
else
|
68
|
+
{ class: 'form-group' }
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def to_html(&block)
|
73
|
+
wrap(&block)
|
74
|
+
end
|
75
|
+
|
76
|
+
protected
|
77
|
+
|
78
|
+
def wrap(&block)
|
79
|
+
case layout
|
80
|
+
when :inline
|
81
|
+
build_content(&block)
|
82
|
+
when :horizontal
|
83
|
+
build_wrapper do
|
84
|
+
(build_label.presence || content_tag(:div, '', class: 'col-sm-2')) +
|
85
|
+
content_tag(:div, build_content(&block), class: 'col-sm-10')
|
86
|
+
end
|
87
|
+
else # Vertical
|
88
|
+
build_wrapper { build_content(&block) }
|
89
|
+
end.html_safe
|
90
|
+
end
|
91
|
+
|
92
|
+
def build_wrapper(&block)
|
93
|
+
content_tag(:div, yield, options[:wrapper])
|
94
|
+
end
|
95
|
+
|
96
|
+
def build_content(&block)
|
97
|
+
return build_input_group_content(&block) if input_group?
|
98
|
+
|
99
|
+
if layout == :horizontal
|
100
|
+
build_input(&block) + build_feedback + build_hint
|
101
|
+
else
|
102
|
+
build_label + build_input(&block) + build_feedback + build_hint
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def build_input_group_content(&block)
|
107
|
+
if layout == :horizontal
|
108
|
+
build_input_group { build_input(&block) } + build_hint
|
109
|
+
else
|
110
|
+
build_label + build_input_group { build_input(&block) } + build_hint
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def build_input_group(&block) # Includes input and feedback
|
115
|
+
content_tag(:div, '', options[:input_group][:input_group]) do # Twice here, kind of weird.
|
116
|
+
[
|
117
|
+
(content_tag(:div, options[:input_group][:prepend], class: 'input-group-prepend') if options[:input_group][:prepend]),
|
118
|
+
build_input(&block),
|
119
|
+
(content_tag(:div, options[:input_group][:append], class: 'input-group-append') if options[:input_group][:append]),
|
120
|
+
build_feedback
|
121
|
+
].compact.join.html_safe
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def build_label
|
126
|
+
return BLANK if options[:label] == false
|
127
|
+
return BLANK if name.kind_of?(NilClass)
|
128
|
+
|
129
|
+
text = options[:label].delete(:text)
|
130
|
+
name_to_s = name.to_s
|
131
|
+
|
132
|
+
text ||= (
|
133
|
+
if object && name_to_s.ends_with?('_id')
|
134
|
+
object.class.human_attribute_name(name_to_s.chomp('_id'))
|
135
|
+
elsif object && name_to_s.ends_with?('_ids')
|
136
|
+
object.class.human_attribute_name(name_to_s.chomp('_ids').pluralize)
|
137
|
+
elsif object
|
138
|
+
object.class.human_attribute_name(name)
|
139
|
+
else
|
140
|
+
BLANK
|
141
|
+
end
|
142
|
+
)
|
143
|
+
|
144
|
+
if options[:input][:id]
|
145
|
+
options[:label][:for] = options[:input][:id]
|
146
|
+
end
|
147
|
+
|
148
|
+
@builder.label(name, text.html_safe, options[:label])
|
149
|
+
end
|
150
|
+
|
151
|
+
def build_input(&block)
|
152
|
+
capture(&block)
|
153
|
+
end
|
154
|
+
|
155
|
+
def build_hint
|
156
|
+
return BLANK unless options[:hint] && options[:hint][:text]
|
157
|
+
|
158
|
+
tag = options[:hint].delete(:tag)
|
159
|
+
text = options[:hint].delete(:text)
|
160
|
+
|
161
|
+
content_tag(tag, text.html_safe, options[:hint])
|
162
|
+
end
|
163
|
+
|
164
|
+
def build_feedback
|
165
|
+
return BLANK if options[:feedback] == false
|
166
|
+
|
167
|
+
invalid = object.errors[name].to_sentence.presence if object.respond_to?(:errors)
|
168
|
+
invalid ||= options[:feedback][:invalid].delete(:text).presence
|
169
|
+
invalid ||= [("can't be blank" if options[:input][:required]), ('must be valid' if validated?(name))].compact.join(' and ').presence
|
170
|
+
invalid ||= "can't be blank or is invalid"
|
171
|
+
|
172
|
+
valid = options[:feedback][:valid].delete(:text) || 'Looks good!'
|
173
|
+
|
174
|
+
content_tag(:div, invalid.html_safe, options[:feedback][:invalid]) +
|
175
|
+
content_tag(:div, valid.html_safe, options[:feedback][:valid])
|
176
|
+
end
|
177
|
+
|
178
|
+
def has_error?(name = nil)
|
179
|
+
return false unless object.respond_to?(:errors)
|
180
|
+
|
181
|
+
if name
|
182
|
+
object.errors[name].present? || (parent_object && parent_object.errors[name].present?)
|
183
|
+
else
|
184
|
+
object.errors.present? || parent_object&.errors&.present?
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def required?(name)
|
189
|
+
return false unless object && name
|
190
|
+
|
191
|
+
obj = (object.class == Class) ? object : object.class
|
192
|
+
return false unless obj.respond_to?(:validators_on)
|
193
|
+
|
194
|
+
if name.to_s.ends_with?('_id')
|
195
|
+
return required_presence?(obj, name) || required_presence?(obj, name[0...-3])
|
196
|
+
end
|
197
|
+
|
198
|
+
required_presence?(obj, name)
|
199
|
+
end
|
200
|
+
|
201
|
+
def required_presence?(obj, name)
|
202
|
+
obj.validators_on(name).any? do |v|
|
203
|
+
(
|
204
|
+
v.kind_of?(ActiveRecord::Validations::PresenceValidator) ||
|
205
|
+
v.kind_of?(ActiveModel::Validations::AcceptanceValidator)
|
206
|
+
) && required_options?(v.options)
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
def required_options?(opts)
|
211
|
+
return true unless (opts.key?(:if) || opts.key?(:unless))
|
212
|
+
|
213
|
+
if opts[:if].respond_to?(:call)
|
214
|
+
return object.instance_exec(&opts[:if])
|
215
|
+
end
|
216
|
+
|
217
|
+
if opts[:if].kind_of?(Symbol)
|
218
|
+
return object.send(opts[:if])
|
219
|
+
end
|
220
|
+
|
221
|
+
if opts.key?(:if)
|
222
|
+
return opts[:if]
|
223
|
+
end
|
224
|
+
|
225
|
+
if opts[:unless].respond_to?(:call)
|
226
|
+
return !object.instance_exec(&opts[:unless])
|
227
|
+
end
|
228
|
+
|
229
|
+
if opts[:unless].kind_of?(Symbol)
|
230
|
+
return !object.send(opts[:unless])
|
231
|
+
end
|
232
|
+
|
233
|
+
if opts.key?(:unless)
|
234
|
+
return !opts[:unless]
|
235
|
+
end
|
236
|
+
|
237
|
+
false
|
238
|
+
end
|
239
|
+
|
240
|
+
def validated?(name)
|
241
|
+
return false unless object && name
|
242
|
+
|
243
|
+
obj = (object.class == Class) ? object : object.class
|
244
|
+
return false unless obj.respond_to?(:validators_on)
|
245
|
+
|
246
|
+
obj.validators_on(name).any? do |v|
|
247
|
+
!(v.kind_of?(ActiveRecord::Validations::PresenceValidator) || v.kind_of?(ActiveModel::Validations::AcceptanceValidator))
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
def input_group?
|
252
|
+
(options[:input_group][:append] || options[:input_group][:prepend]).present?
|
253
|
+
end
|
254
|
+
|
255
|
+
# Used for passwords and to not apply server side feedback
|
256
|
+
def reset_feedback?
|
257
|
+
return @reset_feedback unless @reset_feedback.nil?
|
258
|
+
@reset_feedback = options[:feedback].present? && (options[:feedback].delete(:reset) == true)
|
259
|
+
end
|
260
|
+
|
261
|
+
def value
|
262
|
+
@_value ||= (options.delete(:value) || options[:input]&.delete(:value))
|
263
|
+
@_value ||= (object.public_send(name) if object.respond_to?(name))
|
264
|
+
end
|
265
|
+
|
266
|
+
def unique_id(item = nil)
|
267
|
+
if item && item.respond_to?(value_method)
|
268
|
+
item_value = (item.send(value_method).to_s.parameterize.presence rescue nil)
|
269
|
+
end
|
270
|
+
|
271
|
+
[tag_id, item_value, object_id].compact.join('_')
|
272
|
+
end
|
273
|
+
|
274
|
+
private
|
275
|
+
|
276
|
+
# Here we split them into { wrapper: {}, label: {}, hint: {}, input: {} }
|
277
|
+
# And make sure to keep any additional options on the input: {}
|
278
|
+
def extract_options!(options, html_options: nil)
|
279
|
+
options.symbolize_keys!
|
280
|
+
html_options.symbolize_keys! if html_options
|
281
|
+
|
282
|
+
# effective_bootstrap specific options
|
283
|
+
layout = options.delete(:layout) # Symbol
|
284
|
+
wrapper = options.delete(:wrapper) # Hash
|
285
|
+
input_group = { append: options.delete(:append), prepend: options.delete(:prepend), input_group: options.delete(:input_group) }.compact
|
286
|
+
|
287
|
+
feedback = options.delete(:feedback) # Hash
|
288
|
+
label = options.delete(:label) # String or Hash
|
289
|
+
hint = options.delete(:hint) # String or Hash
|
290
|
+
|
291
|
+
input_html = options.delete(:input_html) || {} # Hash
|
292
|
+
input_js = options.delete(:input_js) || {} # Hash
|
293
|
+
|
294
|
+
# Every other option goes to input
|
295
|
+
@options = input = (html_options || options)
|
296
|
+
|
297
|
+
# Merge all the default objects, and intialize everything
|
298
|
+
wrapper = merge_defaults!(wrapper, wrapper_options)
|
299
|
+
input_group = merge_defaults!(input_group, input_group_options)
|
300
|
+
feedback = merge_defaults!(feedback, feedback_options)
|
301
|
+
|
302
|
+
label = merge_defaults!(label, label_options)
|
303
|
+
hint = merge_defaults!(hint, hint_options)
|
304
|
+
|
305
|
+
merge_defaults!(input.merge!(input_html), input_html_options)
|
306
|
+
merge_defaults!(input_js, input_js_options)
|
307
|
+
|
308
|
+
if input_js.present?
|
309
|
+
merge_defaults!(input_js, input_js_options_method_name)
|
310
|
+
input['data-input-js-options'] = JSON.generate(input_js)
|
311
|
+
end
|
312
|
+
|
313
|
+
{ layout: layout, wrapper: wrapper, input_group: input_group, label: label, hint: hint, input: input, feedback: feedback }
|
314
|
+
end
|
315
|
+
|
316
|
+
def apply_input_options!
|
317
|
+
# Server side validation
|
318
|
+
if has_error?
|
319
|
+
if has_error?(name)
|
320
|
+
options[:input][:class] = [options[:input][:class], 'is-invalid'].compact.join(' ')
|
321
|
+
elsif reset_feedback?
|
322
|
+
# Nothing
|
323
|
+
else
|
324
|
+
options[:input][:class] = [options[:input][:class], 'is-valid'].compact.join(' ')
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
if required?(name) && (options[:input].delete(:required) != false)
|
329
|
+
options[:input][:required] = 'required'
|
330
|
+
end
|
331
|
+
|
332
|
+
if readonly?
|
333
|
+
options[:input][:readonly] = 'readonly'
|
334
|
+
|
335
|
+
unless options[:input][:class].to_s.include?('form-control-plaintext')
|
336
|
+
options[:input][:class] = options[:input][:class].to_s.sub('form-control', 'form-control-plaintext')
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
if disabled?
|
341
|
+
options[:input][:disabled] = 'disabled'
|
342
|
+
end
|
343
|
+
|
344
|
+
if options[:hint] && options[:hint][:text] && options[:hint][:id]
|
345
|
+
options[:input].reverse_merge!('aria-describedby': options[:hint][:id])
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
def merge_defaults!(obj, defaults)
|
350
|
+
defaults = {} if defaults.nil?
|
351
|
+
|
352
|
+
case obj
|
353
|
+
when false
|
354
|
+
false
|
355
|
+
when nil, true
|
356
|
+
defaults
|
357
|
+
when String
|
358
|
+
defaults.merge(text: obj)
|
359
|
+
when Hash
|
360
|
+
html_classes = (obj[:class].to_s.split(' ') + defaults[:class].to_s.split(' ')).uniq
|
361
|
+
|
362
|
+
# Try to smart merge bootstrap classes
|
363
|
+
if (exclusive = html_classes.select { |c| c.include?('-') }).length > 1
|
364
|
+
EXCLUSIVE_CLASS_PREFIXES.each do |prefix|
|
365
|
+
prefixed = exclusive.select { |c| c.start_with?(prefix) }
|
366
|
+
prefixed[1..-1].each { |c| html_classes.delete(c) } if prefixed.length > 1
|
367
|
+
end
|
368
|
+
|
369
|
+
suffixed = exclusive.select { |c| EXCLUSIVE_CLASS_SUFFIXES.any? { |suffix| c.end_with?(suffix) } }
|
370
|
+
suffixed[1..-1].each { |c| html_classes.delete(c) } if suffixed.length > 1
|
371
|
+
end
|
372
|
+
|
373
|
+
obj[:class] = html_classes.join(' ') if html_classes.present?
|
374
|
+
obj.reverse_merge!(defaults)
|
375
|
+
obj
|
376
|
+
else
|
377
|
+
defaults.merge(text: obj.to_s)
|
378
|
+
end
|
379
|
+
end
|
380
|
+
|
381
|
+
def layout
|
382
|
+
options[:layout] || @builder.layout
|
383
|
+
end
|
384
|
+
|
385
|
+
def form_readonly?
|
386
|
+
@builder.readonly
|
387
|
+
end
|
388
|
+
|
389
|
+
def readonly?
|
390
|
+
options.dig(:input, :readonly).present? || form_readonly?
|
391
|
+
end
|
392
|
+
|
393
|
+
def disabled?
|
394
|
+
options.dig(:input, :disabled).present? || form_disabled?
|
395
|
+
end
|
396
|
+
|
397
|
+
def form_disabled?
|
398
|
+
@builder.disabled
|
399
|
+
end
|
400
|
+
|
401
|
+
def form_remote?
|
402
|
+
@builder.remote
|
403
|
+
end
|
404
|
+
|
405
|
+
def parent_object
|
406
|
+
@builder.options[:parent_builder]&.object
|
407
|
+
end
|
408
|
+
|
409
|
+
# https://github.com/rails/rails/blob/master/actionview/lib/action_view/helpers/tags/base.rb#L120
|
410
|
+
def tag_id(index = nil)
|
411
|
+
case
|
412
|
+
when @builder.object_name.empty?
|
413
|
+
sanitized_method_name.dup
|
414
|
+
when index
|
415
|
+
"#{sanitized_object_name}_#{index}_#{sanitized_method_name}"
|
416
|
+
else
|
417
|
+
"#{sanitized_object_name}_#{sanitized_method_name}"
|
418
|
+
end.downcase.parameterize
|
419
|
+
end
|
420
|
+
|
421
|
+
def sanitized_object_name
|
422
|
+
@builder.object_name.to_s.gsub(/\]\[|[^-a-zA-Z0-9:.]/, "_").sub(/_$/, "")
|
423
|
+
end
|
424
|
+
|
425
|
+
def sanitized_method_name
|
426
|
+
name.to_s.sub(/\?$/, "")
|
427
|
+
end
|
428
|
+
|
429
|
+
def input_js_options_method_name
|
430
|
+
{ method_name: "effective_#{self.class.name.split('::').last.underscore.chomp('_field')}" }
|
431
|
+
end
|
432
|
+
|
433
|
+
end
|
434
|
+
end
|