bootstrap_form_extensions 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/Rakefile +34 -0
  4. data/app/assets/javascripts/bootstrap_form_extensions/arrayed_field.js +70 -0
  5. data/app/assets/javascripts/bootstrap_form_extensions/bootstrap-timepicker.min.js +5 -0
  6. data/app/assets/javascripts/bootstrap_form_extensions/index.js +2 -0
  7. data/app/assets/javascripts/bootstrap_form_extensions/jquery.html5data.min.js +7 -0
  8. data/app/assets/javascripts/bootstrap_form_extensions/scheduler.js +226 -0
  9. data/app/assets/javascripts/bootstrap_form_extensions/select_or_new.js +76 -0
  10. data/app/assets/javascripts/bootstrap_form_extensions/time_picker.js +61 -0
  11. data/app/assets/javascripts/bootstrap_form_extensions/timespan.js +60 -0
  12. data/app/assets/stylesheets/bootstrap_form_extensions/bootstrap-timepicker.min.css +10 -0
  13. data/app/assets/stylesheets/bootstrap_form_extensions/common.css +11 -0
  14. data/app/assets/stylesheets/bootstrap_form_extensions/index.css +4 -0
  15. data/app/assets/stylesheets/bootstrap_form_extensions/scheduler.css +31 -0
  16. data/app/assets/stylesheets/bootstrap_form_extensions/submit_bar.css +4 -0
  17. data/app/views/bootstrap_form_extensions/_submit_bar.html.erb +36 -0
  18. data/lib/bootstrap_form_extensions.rb +22 -0
  19. data/lib/bootstrap_form_extensions/arrayed_field.rb +107 -0
  20. data/lib/bootstrap_form_extensions/date_time_pickers.rb +71 -0
  21. data/lib/bootstrap_form_extensions/helpers.rb +18 -0
  22. data/lib/bootstrap_form_extensions/scheduler.rb +72 -0
  23. data/lib/bootstrap_form_extensions/select_or_new.rb +36 -0
  24. data/lib/bootstrap_form_extensions/submit_bar.rb +65 -0
  25. data/lib/bootstrap_form_extensions/timespan.rb +55 -0
  26. data/lib/bootstrap_form_extensions/version.rb +3 -0
  27. data/lib/tasks/rails_bootstrap_form_extensions_tasks.rake +4 -0
  28. data/test/arrayed_field_test.rb +63 -0
  29. data/test/bootstrap_form_extensions_test.rb +7 -0
  30. data/test/date_time_pickers_test.rb +50 -0
  31. data/test/dummy/README.rdoc +28 -0
  32. data/test/dummy/Rakefile +6 -0
  33. data/test/dummy/app/assets/javascripts/application.js +13 -0
  34. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  35. data/test/dummy/app/controllers/application_controller.rb +5 -0
  36. data/test/dummy/app/helpers/application_helper.rb +2 -0
  37. data/test/dummy/app/models/category.rb +7 -0
  38. data/test/dummy/app/models/thing.rb +46 -0
  39. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  40. data/test/dummy/bin/bundle +3 -0
  41. data/test/dummy/bin/rails +4 -0
  42. data/test/dummy/bin/rake +4 -0
  43. data/test/dummy/bin/setup +29 -0
  44. data/test/dummy/config.ru +4 -0
  45. data/test/dummy/config/application.rb +26 -0
  46. data/test/dummy/config/boot.rb +5 -0
  47. data/test/dummy/config/database.yml +25 -0
  48. data/test/dummy/config/environment.rb +5 -0
  49. data/test/dummy/config/environments/development.rb +41 -0
  50. data/test/dummy/config/environments/production.rb +79 -0
  51. data/test/dummy/config/environments/test.rb +42 -0
  52. data/test/dummy/config/initializers/assets.rb +11 -0
  53. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  54. data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
  55. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  56. data/test/dummy/config/initializers/inflections.rb +16 -0
  57. data/test/dummy/config/initializers/mime_types.rb +4 -0
  58. data/test/dummy/config/initializers/session_store.rb +3 -0
  59. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  60. data/test/dummy/config/locales/en.yml +23 -0
  61. data/test/dummy/config/routes.rb +3 -0
  62. data/test/dummy/config/secrets.yml +22 -0
  63. data/test/dummy/db/migrate/20150918185031_create_things.rb +9 -0
  64. data/test/dummy/db/migrate/20150924203053_add_timespan.rb +7 -0
  65. data/test/dummy/db/migrate/20150929213249_add_arrayed_field.rb +7 -0
  66. data/test/dummy/db/migrate/20151006171627_add_another_arrayed_field.rb +7 -0
  67. data/test/dummy/db/migrate/20151006181943_add_json_field.rb +7 -0
  68. data/test/dummy/db/migrate/20151007213131_add_scheduler_field.rb +7 -0
  69. data/test/dummy/db/migrate/20151030194330_add_date_time.rb +7 -0
  70. data/test/dummy/db/migrate/20151106165522_add_category.rb +10 -0
  71. data/test/dummy/db/schema.rb +31 -0
  72. data/test/dummy/db/test.sqlite3 +0 -0
  73. data/test/dummy/log/development.log +0 -0
  74. data/test/dummy/log/test.log +1997 -0
  75. data/test/dummy/public/404.html +67 -0
  76. data/test/dummy/public/422.html +67 -0
  77. data/test/dummy/public/500.html +66 -0
  78. data/test/dummy/public/favicon.ico +0 -0
  79. data/test/dummy/test/fixtures/things.yml +8 -0
  80. data/test/javascripts/arrayed_field_spec.js +101 -0
  81. data/test/javascripts/helpers/function_bind_polyfill_for_phantomjs.js +32 -0
  82. data/test/javascripts/helpers/jasmine-jquery.js +838 -0
  83. data/test/javascripts/scheduler_spec.js +354 -0
  84. data/test/javascripts/select_or_new_spec.js +113 -0
  85. data/test/javascripts/support/jasmine.yml +127 -0
  86. data/test/javascripts/support/jasmine_helper.rb +19 -0
  87. data/test/javascripts/time_picker_spec.js +42 -0
  88. data/test/javascripts/timespan_spec.js +81 -0
  89. data/test/javascripts/vendor/bootstrap.min.js +7 -0
  90. data/test/javascripts/vendor/jquery-2.1.4.min.js +4 -0
  91. data/test/scheduler_serializer_test.rb +200 -0
  92. data/test/scheduler_test.rb +15 -0
  93. data/test/select_or_new_test.rb +37 -0
  94. data/test/submit_bar_test.rb +112 -0
  95. data/test/test_helper.rb +37 -0
  96. data/test/timespan_test.rb +47 -0
  97. metadata +291 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9d9010d6c32f20076166779783d1c7d8583815d1
4
+ data.tar.gz: 9d09b237499a487dd7c29c6ef61e5bb926b2c52a
5
+ SHA512:
6
+ metadata.gz: 4706c80767401dc93e138ef182a1396365916630ba1a5aa37b451a987bf33d7f173a976f8ffb85d8b5a62dc4bfa32831287ae31d168e50b06fdd7bd93a092dc4
7
+ data.tar.gz: 7411609ead208eb9c1bc96ce3a38296108ff27b5c66f965f731a4a92f5880d5c7f2c7f79e8b38ac11fd28259390507a463134456e40c61c174dee15623bf0c96
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2015 Jesús Dugarte
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,34 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'BootstrapFormExtensions'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+
18
+ Bundler::GemHelper.install_tasks
19
+
20
+ require 'rake/testtask'
21
+
22
+ Rake::TestTask.new(:test) do |t|
23
+ t.libs << 'lib'
24
+ t.libs << 'test'
25
+ t.pattern = 'test/**/*_test.rb'
26
+ t.verbose = false
27
+ end
28
+
29
+ task default: :test
30
+
31
+
32
+ require 'jasmine'
33
+ ENV['JASMINE_CONFIG_PATH'] = 'test/javascripts/support/jasmine.yml'
34
+ load 'jasmine/tasks/jasmine.rake'
@@ -0,0 +1,70 @@
1
+ +function ($) {
2
+ 'use strict';
3
+
4
+ // ARRAYED FIELD CLASS DEFINITION
5
+ // ==============================
6
+
7
+ var ArrayedField = function (element) {
8
+ this.$container = $(element)
9
+ this.$container.on('click.bsfe.arrayedfield.data-api', '.add-arrayed-field-row', this.addRow.bind(this))
10
+ this.$container.on('click.bsfe.arrayedfield.data-api', '.remove-arrayed-field-row', this.removeRow.bind(this))
11
+ }
12
+
13
+ ArrayedField.VERSION = '1.0.0'
14
+
15
+ ArrayedField.prototype.addRow = function (event) {
16
+ var blueprint = this.$container.find(".blueprint-for-arrayed-field > .row").clone(true)
17
+ blueprint.find('[data-name]').each(function (i, field) {
18
+ $(field)
19
+ .attr('name', $(field).data('name'))
20
+ .removeAttr('data-name')
21
+ })
22
+ blueprint.appendTo(this.$container.find(".arrayed-field-rows"))
23
+ blueprint.trigger("added.bsfe.arrayedfield")
24
+ }
25
+
26
+ ArrayedField.prototype.removeRow = function (event) {
27
+ var $target = $(event.target)
28
+ var $rows = $target.closest('.arrayed-field-rows')
29
+ $target.closest('.row').remove()
30
+ $rows.trigger("removed.bsfe.arrayedfield")
31
+ }
32
+
33
+
34
+ // ARRAYED FIELD PLUGIN DEFINITION
35
+ // ===============================
36
+
37
+ function Plugin() {
38
+ return $(this).each(function () {
39
+ var $this = $(this)
40
+ var data = $this.data('bsfe.arrayedfield')
41
+
42
+ if (!data) $this.data('bsfe.arrayedfield', (data = new ArrayedField(this)))
43
+ })
44
+ }
45
+
46
+ var old = $.fn.arrayedfield
47
+
48
+ $.fn.arrayedfield = Plugin
49
+ $.fn.arrayedfield.Constructor = ArrayedField
50
+
51
+
52
+ // ARRAYED FIELD NO CONFLICT
53
+ // =========================
54
+
55
+ $.fn.arrayedfield.noConflict = function () {
56
+ $.fn.arrayedfield = old
57
+ return this
58
+ }
59
+
60
+
61
+ // ARRAYED FIELD DATA-API
62
+ // ======================
63
+
64
+ $(window).on('load page:load page:restore', function () {
65
+ $('[data-arrayed-field]').each(function () {
66
+ Plugin.call(this)
67
+ })
68
+ })
69
+
70
+ }(jQuery);
@@ -0,0 +1,5 @@
1
+ /*! bootstrap-timepicker v0.5.0
2
+ * http://jdewit.github.com/bootstrap-timepicker
3
+ * Copyright (c) 2015 Joris de Wit
4
+ * MIT License
5
+ */!function(a,b,c){"use strict";var d=function(b,c){this.widget="",this.$element=a(b),this.defaultTime=c.defaultTime,this.disableFocus=c.disableFocus,this.disableMousewheel=c.disableMousewheel,this.isOpen=c.isOpen,this.minuteStep=c.minuteStep,this.modalBackdrop=c.modalBackdrop,this.orientation=c.orientation,this.secondStep=c.secondStep,this.snapToStep=c.snapToStep,this.showInputs=c.showInputs,this.showMeridian=c.showMeridian,this.showSeconds=c.showSeconds,this.template=c.template,this.appendWidgetTo=c.appendWidgetTo,this.showWidgetOnAddonClick=c.showWidgetOnAddonClick,this.maxHours=c.maxHours,this.explicitMode=c.explicitMode,this.handleDocumentClick=function(a){var b=a.data.scope;b.$element.parent().find(a.target).length||b.$widget.is(a.target)||b.$widget.find(a.target).length||b.hideWidget()},this._init()};d.prototype={constructor:d,_init:function(){var b=this;this.showWidgetOnAddonClick&&this.$element.parent().hasClass("input-group")&&this.$element.parent().hasClass("bootstrap-timepicker")?(this.$element.parent(".input-group.bootstrap-timepicker").find(".input-group-addon").on({"click.timepicker":a.proxy(this.showWidget,this)}),this.$element.on({"focus.timepicker":a.proxy(this.highlightUnit,this),"click.timepicker":a.proxy(this.highlightUnit,this),"keydown.timepicker":a.proxy(this.elementKeydown,this),"blur.timepicker":a.proxy(this.blurElement,this),"mousewheel.timepicker DOMMouseScroll.timepicker":a.proxy(this.mousewheel,this)})):this.template?this.$element.on({"focus.timepicker":a.proxy(this.showWidget,this),"click.timepicker":a.proxy(this.showWidget,this),"blur.timepicker":a.proxy(this.blurElement,this),"mousewheel.timepicker DOMMouseScroll.timepicker":a.proxy(this.mousewheel,this)}):this.$element.on({"focus.timepicker":a.proxy(this.highlightUnit,this),"click.timepicker":a.proxy(this.highlightUnit,this),"keydown.timepicker":a.proxy(this.elementKeydown,this),"blur.timepicker":a.proxy(this.blurElement,this),"mousewheel.timepicker DOMMouseScroll.timepicker":a.proxy(this.mousewheel,this)}),this.template!==!1?this.$widget=a(this.getTemplate()).on("click",a.proxy(this.widgetClick,this)):this.$widget=!1,this.showInputs&&this.$widget!==!1&&this.$widget.find("input").each(function(){a(this).on({"click.timepicker":function(){a(this).select()},"keydown.timepicker":a.proxy(b.widgetKeydown,b),"keyup.timepicker":a.proxy(b.widgetKeyup,b)})}),this.setDefaultTime(this.defaultTime)},blurElement:function(){this.highlightedUnit=null,this.updateFromElementVal()},clear:function(){this.hour="",this.minute="",this.second="",this.meridian="",this.$element.val("")},decrementHour:function(){if(this.showMeridian)if(1===this.hour)this.hour=12;else{if(12===this.hour)return this.hour--,this.toggleMeridian();if(0===this.hour)return this.hour=11,this.toggleMeridian();this.hour--}else this.hour<=0?this.hour=this.maxHours-1:this.hour--},decrementMinute:function(a){var b;b=a?this.minute-a:this.minute-this.minuteStep,0>b?(this.decrementHour(),this.minute=b+60):this.minute=b},decrementSecond:function(){var a=this.second-this.secondStep;0>a?(this.decrementMinute(!0),this.second=a+60):this.second=a},elementKeydown:function(a){switch(a.which){case 9:if(a.shiftKey){if("hour"===this.highlightedUnit)break;this.highlightPrevUnit()}else{if(this.showMeridian&&"meridian"===this.highlightedUnit||this.showSeconds&&"second"===this.highlightedUnit||!this.showMeridian&&!this.showSeconds&&"minute"===this.highlightedUnit)break;this.highlightNextUnit()}a.preventDefault(),this.updateFromElementVal();break;case 27:this.updateFromElementVal();break;case 37:a.preventDefault(),this.highlightPrevUnit(),this.updateFromElementVal();break;case 38:switch(a.preventDefault(),this.highlightedUnit){case"hour":this.incrementHour(),this.highlightHour();break;case"minute":this.incrementMinute(),this.highlightMinute();break;case"second":this.incrementSecond(),this.highlightSecond();break;case"meridian":this.toggleMeridian(),this.highlightMeridian()}this.update();break;case 39:a.preventDefault(),this.highlightNextUnit(),this.updateFromElementVal();break;case 40:switch(a.preventDefault(),this.highlightedUnit){case"hour":this.decrementHour(),this.highlightHour();break;case"minute":this.decrementMinute(),this.highlightMinute();break;case"second":this.decrementSecond(),this.highlightSecond();break;case"meridian":this.toggleMeridian(),this.highlightMeridian()}this.update()}},getCursorPosition:function(){var a=this.$element.get(0);if("selectionStart"in a)return a.selectionStart;if(c.selection){a.focus();var b=c.selection.createRange(),d=c.selection.createRange().text.length;return b.moveStart("character",-a.value.length),b.text.length-d}},getTemplate:function(){var a,b,c,d,e,f;switch(this.showInputs?(b='<input type="text" class="bootstrap-timepicker-hour" maxlength="2"/>',c='<input type="text" class="bootstrap-timepicker-minute" maxlength="2"/>',d='<input type="text" class="bootstrap-timepicker-second" maxlength="2"/>',e='<input type="text" class="bootstrap-timepicker-meridian" maxlength="2"/>'):(b='<span class="bootstrap-timepicker-hour"></span>',c='<span class="bootstrap-timepicker-minute"></span>',d='<span class="bootstrap-timepicker-second"></span>',e='<span class="bootstrap-timepicker-meridian"></span>'),f='<table><tr><td><a href="#" data-action="incrementHour"><span class="glyphicon glyphicon-chevron-up"></span></a></td><td class="separator">&nbsp;</td><td><a href="#" data-action="incrementMinute"><span class="glyphicon glyphicon-chevron-up"></span></a></td>'+(this.showSeconds?'<td class="separator">&nbsp;</td><td><a href="#" data-action="incrementSecond"><span class="glyphicon glyphicon-chevron-up"></span></a></td>':"")+(this.showMeridian?'<td class="separator">&nbsp;</td><td class="meridian-column"><a href="#" data-action="toggleMeridian"><span class="glyphicon glyphicon-chevron-up"></span></a></td>':"")+"</tr><tr><td>"+b+'</td> <td class="separator">:</td><td>'+c+"</td> "+(this.showSeconds?'<td class="separator">:</td><td>'+d+"</td>":"")+(this.showMeridian?'<td class="separator">&nbsp;</td><td>'+e+"</td>":"")+'</tr><tr><td><a href="#" data-action="decrementHour"><span class="glyphicon glyphicon-chevron-down"></span></a></td><td class="separator"></td><td><a href="#" data-action="decrementMinute"><span class="glyphicon glyphicon-chevron-down"></span></a></td>'+(this.showSeconds?'<td class="separator">&nbsp;</td><td><a href="#" data-action="decrementSecond"><span class="glyphicon glyphicon-chevron-down"></span></a></td>':"")+(this.showMeridian?'<td class="separator">&nbsp;</td><td><a href="#" data-action="toggleMeridian"><span class="glyphicon glyphicon-chevron-down"></span></a></td>':"")+"</tr></table>",this.template){case"modal":a='<div class="bootstrap-timepicker-widget modal hide fade in" data-backdrop="'+(this.modalBackdrop?"true":"false")+'"><div class="modal-header"><a href="#" class="close" data-dismiss="modal">×</a><h3>Pick a Time</h3></div><div class="modal-content">'+f+'</div><div class="modal-footer"><a href="#" class="btn btn-primary" data-dismiss="modal">OK</a></div></div>';break;case"dropdown":a='<div class="bootstrap-timepicker-widget dropdown-menu">'+f+"</div>"}return a},getTime:function(){return""===this.hour?"":this.hour+":"+(1===this.minute.toString().length?"0"+this.minute:this.minute)+(this.showSeconds?":"+(1===this.second.toString().length?"0"+this.second:this.second):"")+(this.showMeridian?" "+this.meridian:"")},hideWidget:function(){this.isOpen!==!1&&(this.$element.trigger({type:"hide.timepicker",time:{value:this.getTime(),hours:this.hour,minutes:this.minute,seconds:this.second,meridian:this.meridian}}),"modal"===this.template&&this.$widget.modal?this.$widget.modal("hide"):this.$widget.removeClass("open"),a(c).off("mousedown.timepicker, touchend.timepicker",this.handleDocumentClick),this.isOpen=!1,this.$widget.detach())},highlightUnit:function(){this.position=this.getCursorPosition(),this.position>=0&&this.position<=2?this.highlightHour():this.position>=3&&this.position<=5?this.highlightMinute():this.position>=6&&this.position<=8?this.showSeconds?this.highlightSecond():this.highlightMeridian():this.position>=9&&this.position<=11&&this.highlightMeridian()},highlightNextUnit:function(){switch(this.highlightedUnit){case"hour":this.highlightMinute();break;case"minute":this.showSeconds?this.highlightSecond():this.showMeridian?this.highlightMeridian():this.highlightHour();break;case"second":this.showMeridian?this.highlightMeridian():this.highlightHour();break;case"meridian":this.highlightHour()}},highlightPrevUnit:function(){switch(this.highlightedUnit){case"hour":this.showMeridian?this.highlightMeridian():this.showSeconds?this.highlightSecond():this.highlightMinute();break;case"minute":this.highlightHour();break;case"second":this.highlightMinute();break;case"meridian":this.showSeconds?this.highlightSecond():this.highlightMinute()}},highlightHour:function(){var a=this.$element.get(0),b=this;this.highlightedUnit="hour",a.setSelectionRange&&setTimeout(function(){b.hour<10?a.setSelectionRange(0,1):a.setSelectionRange(0,2)},0)},highlightMinute:function(){var a=this.$element.get(0),b=this;this.highlightedUnit="minute",a.setSelectionRange&&setTimeout(function(){b.hour<10?a.setSelectionRange(2,4):a.setSelectionRange(3,5)},0)},highlightSecond:function(){var a=this.$element.get(0),b=this;this.highlightedUnit="second",a.setSelectionRange&&setTimeout(function(){b.hour<10?a.setSelectionRange(5,7):a.setSelectionRange(6,8)},0)},highlightMeridian:function(){var a=this.$element.get(0),b=this;this.highlightedUnit="meridian",a.setSelectionRange&&(this.showSeconds?setTimeout(function(){b.hour<10?a.setSelectionRange(8,10):a.setSelectionRange(9,11)},0):setTimeout(function(){b.hour<10?a.setSelectionRange(5,7):a.setSelectionRange(6,8)},0))},incrementHour:function(){if(this.showMeridian){if(11===this.hour)return this.hour++,this.toggleMeridian();12===this.hour&&(this.hour=0)}return this.hour===this.maxHours-1?void(this.hour=0):void this.hour++},incrementMinute:function(a){var b;b=a?this.minute+a:this.minute+this.minuteStep-this.minute%this.minuteStep,b>59?(this.incrementHour(),this.minute=b-60):this.minute=b},incrementSecond:function(){var a=this.second+this.secondStep-this.second%this.secondStep;a>59?(this.incrementMinute(!0),this.second=a-60):this.second=a},mousewheel:function(b){if(!this.disableMousewheel){b.preventDefault(),b.stopPropagation();var c=b.originalEvent.wheelDelta||-b.originalEvent.detail,d=null;switch("mousewheel"===b.type?d=-1*b.originalEvent.wheelDelta:"DOMMouseScroll"===b.type&&(d=40*b.originalEvent.detail),d&&(b.preventDefault(),a(this).scrollTop(d+a(this).scrollTop())),this.highlightedUnit){case"minute":c>0?this.incrementMinute():this.decrementMinute(),this.highlightMinute();break;case"second":c>0?this.incrementSecond():this.decrementSecond(),this.highlightSecond();break;case"meridian":this.toggleMeridian(),this.highlightMeridian();break;default:c>0?this.incrementHour():this.decrementHour(),this.highlightHour()}return!1}},changeToNearestStep:function(a,b){return a%b===0?a:Math.round(a%b/b)?(a+(b-a%b))%60:a-a%b},place:function(){if(!this.isInline){var c=this.$widget.outerWidth(),d=this.$widget.outerHeight(),e=10,f=a(b).width(),g=a(b).height(),h=a(b).scrollTop(),i=parseInt(this.$element.parents().filter(function(){return"auto"!==a(this).css("z-index")}).first().css("z-index"),10)+10,j=this.component?this.component.parent().offset():this.$element.offset(),k=this.component?this.component.outerHeight(!0):this.$element.outerHeight(!1),l=this.component?this.component.outerWidth(!0):this.$element.outerWidth(!1),m=j.left,n=j.top;this.$widget.removeClass("timepicker-orient-top timepicker-orient-bottom timepicker-orient-right timepicker-orient-left"),"auto"!==this.orientation.x?(this.picker.addClass("datepicker-orient-"+this.orientation.x),"right"===this.orientation.x&&(m-=c-l)):(this.$widget.addClass("timepicker-orient-left"),j.left<0?m-=j.left-e:j.left+c>f&&(m=f-c-e));var o,p,q=this.orientation.y;"auto"===q&&(o=-h+j.top-d,p=h+g-(j.top+k+d),q=Math.max(o,p)===p?"top":"bottom"),this.$widget.addClass("timepicker-orient-"+q),"top"===q?n+=k:n-=d+parseInt(this.$widget.css("padding-top"),10),this.$widget.css({top:n,left:m,zIndex:i})}},remove:function(){a("document").off(".timepicker"),this.$widget&&this.$widget.remove(),delete this.$element.data().timepicker},setDefaultTime:function(a){if(this.$element.val())this.updateFromElementVal();else if("current"===a){var b=new Date,c=b.getHours(),d=b.getMinutes(),e=b.getSeconds(),f="AM";0!==e&&(e=Math.ceil(b.getSeconds()/this.secondStep)*this.secondStep,60===e&&(d+=1,e=0)),0!==d&&(d=Math.ceil(b.getMinutes()/this.minuteStep)*this.minuteStep,60===d&&(c+=1,d=0)),this.showMeridian&&(0===c?c=12:c>=12?(c>12&&(c-=12),f="PM"):f="AM"),this.hour=c,this.minute=d,this.second=e,this.meridian=f,this.update()}else a===!1?(this.hour=0,this.minute=0,this.second=0,this.meridian="AM"):this.setTime(a)},setTime:function(a,b){if(!a)return void this.clear();var c,d,e,f,g,h;if("object"==typeof a&&a.getMonth)e=a.getHours(),f=a.getMinutes(),g=a.getSeconds(),this.showMeridian&&(h="AM",e>12&&(h="PM",e%=12),12===e&&(h="PM"));else{if(c=(/a/i.test(a)?1:0)+(/p/i.test(a)?2:0),c>2)return void this.clear();if(d=a.replace(/[^0-9\:]/g,"").split(":"),e=d[0]?d[0].toString():d.toString(),this.explicitMode&&e.length>2&&e.length%2!==0)return void this.clear();f=d[1]?d[1].toString():"",g=d[2]?d[2].toString():"",e.length>4&&(g=e.slice(-2),e=e.slice(0,-2)),e.length>2&&(f=e.slice(-2),e=e.slice(0,-2)),f.length>2&&(g=f.slice(-2),f=f.slice(0,-2)),e=parseInt(e,10),f=parseInt(f,10),g=parseInt(g,10),isNaN(e)&&(e=0),isNaN(f)&&(f=0),isNaN(g)&&(g=0),g>59&&(g=59),f>59&&(f=59),e>=this.maxHours&&(e=this.maxHours-1),this.showMeridian?(e>12&&(c=2,e-=12),c||(c=1),0===e&&(e=12),h=1===c?"AM":"PM"):12>e&&2===c?e+=12:e>=this.maxHours?e=this.maxHours-1:0>e&&(e=0)}this.hour=e,this.snapToStep?(this.minute=this.changeToNearestStep(f,this.minuteStep),this.second=this.changeToNearestStep(g,this.secondStep)):(this.minute=f,this.second=g),this.meridian=h,this.update(b)},showWidget:function(){this.isOpen||this.$element.is(":disabled")||(this.$widget.appendTo(this.appendWidgetTo),a(c).on("mousedown.timepicker, touchend.timepicker",{scope:this},this.handleDocumentClick),this.$element.trigger({type:"show.timepicker",time:{value:this.getTime(),hours:this.hour,minutes:this.minute,seconds:this.second,meridian:this.meridian}}),this.place(),this.disableFocus&&this.$element.blur(),""===this.hour&&(this.defaultTime?this.setDefaultTime(this.defaultTime):this.setTime("0:0:0")),"modal"===this.template&&this.$widget.modal?this.$widget.modal("show").on("hidden",a.proxy(this.hideWidget,this)):this.isOpen===!1&&this.$widget.addClass("open"),this.isOpen=!0)},toggleMeridian:function(){this.meridian="AM"===this.meridian?"PM":"AM"},update:function(a){this.updateElement(),a||this.updateWidget(),this.$element.trigger({type:"changeTime.timepicker",time:{value:this.getTime(),hours:this.hour,minutes:this.minute,seconds:this.second,meridian:this.meridian}})},updateElement:function(){this.$element.val(this.getTime()).change()},updateFromElementVal:function(){this.setTime(this.$element.val())},updateWidget:function(){if(this.$widget!==!1){var a=this.hour,b=1===this.minute.toString().length?"0"+this.minute:this.minute,c=1===this.second.toString().length?"0"+this.second:this.second;this.showInputs?(this.$widget.find("input.bootstrap-timepicker-hour").val(a),this.$widget.find("input.bootstrap-timepicker-minute").val(b),this.showSeconds&&this.$widget.find("input.bootstrap-timepicker-second").val(c),this.showMeridian&&this.$widget.find("input.bootstrap-timepicker-meridian").val(this.meridian)):(this.$widget.find("span.bootstrap-timepicker-hour").text(a),this.$widget.find("span.bootstrap-timepicker-minute").text(b),this.showSeconds&&this.$widget.find("span.bootstrap-timepicker-second").text(c),this.showMeridian&&this.$widget.find("span.bootstrap-timepicker-meridian").text(this.meridian))}},updateFromWidgetInputs:function(){if(this.$widget!==!1){var a=this.$widget.find("input.bootstrap-timepicker-hour").val()+":"+this.$widget.find("input.bootstrap-timepicker-minute").val()+(this.showSeconds?":"+this.$widget.find("input.bootstrap-timepicker-second").val():"")+(this.showMeridian?this.$widget.find("input.bootstrap-timepicker-meridian").val():"");this.setTime(a,!0)}},widgetClick:function(b){b.stopPropagation(),b.preventDefault();var c=a(b.target),d=c.closest("a").data("action");d&&this[d](),this.update(),c.is("input")&&c.get(0).setSelectionRange(0,2)},widgetKeydown:function(b){var c=a(b.target),d=c.attr("class").replace("bootstrap-timepicker-","");switch(b.which){case 9:if(b.shiftKey){if("hour"===d)return this.hideWidget()}else if(this.showMeridian&&"meridian"===d||this.showSeconds&&"second"===d||!this.showMeridian&&!this.showSeconds&&"minute"===d)return this.hideWidget();break;case 27:this.hideWidget();break;case 38:switch(b.preventDefault(),d){case"hour":this.incrementHour();break;case"minute":this.incrementMinute();break;case"second":this.incrementSecond();break;case"meridian":this.toggleMeridian()}this.setTime(this.getTime()),c.get(0).setSelectionRange(0,2);break;case 40:switch(b.preventDefault(),d){case"hour":this.decrementHour();break;case"minute":this.decrementMinute();break;case"second":this.decrementSecond();break;case"meridian":this.toggleMeridian()}this.setTime(this.getTime()),c.get(0).setSelectionRange(0,2)}},widgetKeyup:function(a){(65===a.which||77===a.which||80===a.which||46===a.which||8===a.which||a.which>=48&&a.which<=57||a.which>=96&&a.which<=105)&&this.updateFromWidgetInputs()}},a.fn.timepicker=function(b){var c=Array.apply(null,arguments);return c.shift(),this.each(function(){var e=a(this),f=e.data("timepicker"),g="object"==typeof b&&b;f||e.data("timepicker",f=new d(this,a.extend({},a.fn.timepicker.defaults,g,a(this).data()))),"string"==typeof b&&f[b].apply(f,c)})},a.fn.timepicker.defaults={defaultTime:"current",disableFocus:!1,disableMousewheel:!1,isOpen:!1,minuteStep:15,modalBackdrop:!1,orientation:{x:"auto",y:"auto"},secondStep:15,snapToStep:!1,showSeconds:!1,showInputs:!0,showMeridian:!0,template:"dropdown",appendWidgetTo:"body",showWidgetOnAddonClick:!0,maxHours:24,explicitMode:!1},a.fn.timepicker.Constructor=d,a(c).on("focus.timepicker.data-api click.timepicker.data-api",'[data-provide="timepicker"]',function(b){var c=a(this);c.data("timepicker")||(b.preventDefault(),c.timepicker())})}(jQuery,window,document);
@@ -0,0 +1,2 @@
1
+ //= require bootstrap-datepicker
2
+ //= require_tree .
@@ -0,0 +1,7 @@
1
+ /*
2
+ * $.html5data v1.0
3
+ * Copyright 2011, Mark Dalgleish
4
+ *
5
+ * This content is released under the MIT License
6
+ * github.com/markdalgleish/jquery-html5data/blob/master/MIT-LICENSE.txt
7
+ */(function(a,b){a.fn.html5data=function(c,d){var e={parseBooleans:!0,parseNumbers:!0,parseNulls:!0,parseJSON:!0,parse:b},f=a.extend({},e,d),g=[],h="data-"+(c?c+"-":""),i=function(b){var c=b.toLowerCase(),d=b.charAt(0);return f.parseBooleans===!0&&c==="true"?!0:f.parseBooleans===!0&&c==="false"?!1:f.parseNulls===!0&&c==="null"?null:f.parseNumbers===!0&&!isNaN(b*1)?b*1:f.parseJSON===!0&&d==="["||d==="{"?a.parseJSON(b):typeof f.parse=="function"?f.parse(b):b};this.each(function(){var a={},b,c,d;for(var e=0,f=this.attributes.length;e<f;e++){b=this.attributes[e];if(b.name.indexOf(h)===0){d="",c=b.name.replace(h,"").split("-");for(var j=0,k=c.length;j<k;j++)d+=j===0?c[j].toLowerCase():c[j].charAt(0).toUpperCase()+c[j].slice(1).toLowerCase();a[d]=i(b.value)}}g.push(a)});return g.length===1?g[0]:g},a.html5data=function(b,c,d){return a(b).html5data(c,d)}})(jQuery)
@@ -0,0 +1,226 @@
1
+ +function ($) {
2
+ 'use strict';
3
+
4
+
5
+ // SCHEDULER CLASS DEFINITION
6
+ // ==========================
7
+
8
+ var Scheduler = function (element) {
9
+ this.days = [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ]
10
+ this.$element = $(element)
11
+ this.createEvents()
12
+ this.setInitialValues()
13
+ }
14
+
15
+ Scheduler.VERSION = '1.0.0'
16
+
17
+ Scheduler.prototype.createEvents = function (event) {
18
+ this.$element.on('click.bsfe.scheduler.data-api', 'table.scheduler-badge', this.editSchedule.bind(this))
19
+ }
20
+
21
+ Scheduler.prototype.setInitialValues = function (event) {
22
+ var hidden_field = this.hiddenField()
23
+ if (hidden_field.length > 0) {
24
+ this.values = JSON.parse(hidden_field.val())
25
+ } else {
26
+ this.values = []
27
+ }
28
+ }
29
+
30
+ Scheduler.prototype.editSchedule = function (event) {
31
+ this.createModal()
32
+ this.$modal.modal({ keyboard: true })
33
+ }
34
+
35
+ Scheduler.prototype.createModal = function () {
36
+ this.$container = this.modalTemplate()
37
+ this.$container.appendTo('body')
38
+ this.$modal = this.$container.find('.modal')
39
+ this.createModalEvents()
40
+ }
41
+
42
+ Scheduler.prototype.createModalEvents = function () {
43
+ this.$modal.on('click.bsfe.scheduler.data-api', 'a.hour-header', this.toggleHour.bind(this))
44
+ this.$modal.on('click.bsfe.scheduler.data-api', 'a.day-header', this.toggleDay.bind(this))
45
+ this.$modal.on('click.bsfe.scheduler.data-api', 'td.clickable', this.toggleOne.bind(this))
46
+ this.$modal.on('click.bsfe.scheduler.data-api', 'a.all', this.toggleAll.bind(this, true))
47
+ this.$modal.on('click.bsfe.scheduler.data-api', 'a.none', this.toggleAll.bind(this, false))
48
+ this.$modal.on('click.bsfe.scheduler.data-api', 'button.apply', this.apply.bind(this))
49
+ this.$modal.on('click.bsfe.scheduler.data-api', 'button.cancel', this.removeModal.bind(this))
50
+ }
51
+
52
+ Scheduler.prototype.removeModal = function () {
53
+ this.$modal.modal('hide')
54
+ this.$container.remove()
55
+ }
56
+
57
+ Scheduler.prototype.toggleHour = function (event) {
58
+ var hour = $(event.target).data('hour')
59
+ var cells = this.$modal.find("td[data-hour=" + hour + "]")
60
+ this.toggleLine(cells)
61
+ }
62
+
63
+ Scheduler.prototype.toggleDay = function (event) {
64
+ var cells = $(event.target).closest('tr').find('td.clickable')
65
+ this.toggleLine(cells)
66
+ }
67
+
68
+ Scheduler.prototype.toggleAll = function (value) {
69
+ var cells = this.$modal.find('td.clickable')
70
+ this.toggle(cells, value)
71
+ }
72
+
73
+ Scheduler.prototype.toggleOne = function (event) {
74
+ var cell = $(event.target)
75
+ var value = cell.hasClass('off')
76
+ this.toggle(cell, value)
77
+ }
78
+
79
+ Scheduler.prototype.toggleLine = function (cells) {
80
+ var ctOn = cells.filter('.on').length
81
+ var ctOff = cells.filter('.off').length
82
+ var value = ctOn < ctOff
83
+ this.toggle(cells, value)
84
+ }
85
+
86
+ Scheduler.prototype.toggle = function (cells, value) {
87
+ cells.toggleClass('on', value)
88
+ cells.toggleClass('off', !value)
89
+ }
90
+
91
+ Scheduler.prototype.apply = function () {
92
+ this.assignValues()
93
+ this.updateBadge()
94
+ this.removeModal()
95
+ }
96
+
97
+ Scheduler.prototype.assignValues = function () {
98
+ var self = this
99
+ this.scanTable(this.$modal.find("td.clickable"), function (cell, day, hour) {
100
+ self.values[day][hour] = cell.hasClass('on')
101
+ })
102
+ this.hiddenField().val(JSON.stringify(this.values))
103
+ }
104
+
105
+ Scheduler.prototype.updateBadge = function () {
106
+ var self = this
107
+ this.scanTable(this.$element.find('table.scheduler-badge td'), function (cell, day, hour) {
108
+ self.toggle(cell, this.values[day][hour])
109
+ })
110
+ }
111
+
112
+ Scheduler.prototype.scanTable = function (elements, action) {
113
+ var self = this, cell, day, hour
114
+ elements.each(function (index, element) {
115
+ cell = $(element)
116
+ day = cell.data('day')
117
+ hour = cell.data('hour')
118
+ action.call(self, cell, day, hour)
119
+ })
120
+ }
121
+
122
+ Scheduler.prototype.hiddenField = function () {
123
+ return this.$element.find('.scheduler-hidden-field')
124
+ }
125
+
126
+
127
+ // SCHEDULER HTML
128
+ // ===========================
129
+
130
+ Scheduler.prototype.modalTemplate = function () {
131
+ return $("<div id='scheduler-container'>" +
132
+ " <div class='modal wider-modal' tabindex='-1'>" +
133
+ " <div class='modal-dialog'>" +
134
+ " <div class='modal-content'>" +
135
+ " <div class='modal-header'>" +
136
+ " <button type='button' class='close' data-dismiss='modal' aria-hidden='true'>&times;</button>" +
137
+ " <h3>Schedule</h3>" +
138
+ " </div>" +
139
+ " <div class='modal-body'>" + this.scheduleTable() + this.linksAllNone() + "</div>" +
140
+ " <div class='modal-footer'>" +
141
+ " <button class='btn btn-primary apply' type='button' data-dismiss='modal'>Apply</button>" +
142
+ " <button class='btn btn-default cancel' type='button' data-dismiss='modal'>Cancel</button>" +
143
+ " </div>" +
144
+ " </div>" +
145
+ " </div>" +
146
+ " </div>" +
147
+ "</div>"
148
+ )
149
+ }
150
+
151
+ Scheduler.prototype.scheduleTable = function () {
152
+ return "<table class='scheduler-editor'>" + this.hourHeaders() + this.dayRows() + "</table>"
153
+ }
154
+
155
+ Scheduler.prototype.hourHeaders = function () {
156
+ var headers, hour, hours = []
157
+ for (hour = 0; hour <= 23; hour++) {
158
+ hours.push("<th><a class='hour-header' data-hour='" + hour + "'>" + (this.hourLabel(hour)) + "</a></th>")
159
+ }
160
+ return "<tr><th></th>" + hours.join('') + "</tr>"
161
+ }
162
+
163
+ Scheduler.prototype.hourLabel = function (hour) {
164
+ if (hour === 0) return '12am'
165
+ if (hour < 12) return hour + "am"
166
+ if (hour === 12) return hour + "pm"
167
+ return (hour - 12) + "pm"
168
+ }
169
+
170
+ Scheduler.prototype.dayRows = function () {
171
+ var rows, day, hour, hours, first, on_off
172
+ rows = []
173
+ for (day = 0; day <= 6; day++) {
174
+ first = "<td><a class='day-header'>" + this.days[day] + "</a></td>"
175
+ hours = []
176
+ for (hour = 0; hour <= 23; hour++) {
177
+ on_off = this.values[day][hour] === 't' || this.values[day][hour] === true ? 'on' : 'off'
178
+ hours.push("<td class='clickable " + on_off + "' data-day=" + day + " data-hour=" + hour + "></td>")
179
+ }
180
+ rows.push("<tr>" + (first + hours.join('')) + "</tr>")
181
+ }
182
+ return rows.join('')
183
+ }
184
+
185
+ Scheduler.prototype.linksAllNone = function () {
186
+ return "<br><a class='all'>all</a>&nbsp;&nbsp;&nbsp;<a class='none'>none</a>"
187
+ }
188
+
189
+
190
+ // SCHEDULER PLUGIN DEFINITION
191
+ // ===========================
192
+
193
+ function Plugin() {
194
+ return $(this).each(function () {
195
+ var $this = $(this)
196
+ var data = $this.data('bsfe.scheduler')
197
+
198
+ if (!data) $this.data('bsfe.scheduler', (data = new Scheduler(this)))
199
+ })
200
+ }
201
+
202
+ var old = $.fn.scheduler
203
+
204
+ $.fn.scheduler = Plugin
205
+ $.fn.scheduler.Constructor = Scheduler
206
+
207
+
208
+ // SCHEDULER NO CONFLICT
209
+ // =====================
210
+
211
+ $.fn.scheduler.noConflict = function () {
212
+ $.fn.scheduler = old
213
+ return this
214
+ }
215
+
216
+
217
+ // SCHEDULER DATA-API
218
+ // ==================
219
+
220
+ $(window).on('load page:load page:restore', function () {
221
+ $('[data-scheduler]').each(function () {
222
+ Plugin.call(this)
223
+ })
224
+ })
225
+
226
+ }(jQuery);
@@ -0,0 +1,76 @@
1
+ +function ($) {
2
+ 'use strict';
3
+
4
+
5
+ // SELECT-OR-NEW CLASS DEFINITION
6
+ // ==============================
7
+
8
+ var SelectOrNew = function (element) {
9
+ this.$element = $(element)
10
+ this.$select = this.$element.find('select')
11
+ this.$input = this.$element.find('input[type="text"]')
12
+ this.$inputGroup = this.$element.find('div.input-group')
13
+ this.createEvents()
14
+ }
15
+
16
+ SelectOrNew.VERSION = '1.0.0'
17
+
18
+ SelectOrNew.prototype.createEvents = function () {
19
+ this.$element.on('change.bsfe.select-or-new.data-api', 'select', this.changeSelection.bind(this))
20
+ this.$element.on('click.bsfe.select-or-new.data-api', 'div.input-group-addon', this.cancelNew.bind(this))
21
+ }
22
+
23
+ SelectOrNew.prototype.changeSelection = function (event) {
24
+ if (this.$select.val() == '0') {
25
+ this.$select.hide()
26
+ this.$inputGroup.show()
27
+ this.$input.focus()
28
+ }
29
+ }
30
+
31
+ SelectOrNew.prototype.cancelNew = function (event) {
32
+ this.$inputGroup.hide()
33
+ this.$input.val('')
34
+ this.$select.val('')
35
+ this.$select.show()
36
+ this.$select.focus()
37
+ }
38
+
39
+
40
+ // SELECT-OR-NEW PLUGIN DEFINITION
41
+ // ===============================
42
+
43
+ function Plugin() {
44
+ return $(this).each(function () {
45
+ var $this = $(this)
46
+ var data = $this.data('bsfe.select-or-new')
47
+
48
+ if (!data) $this.data('bsfe.select-or-new', (data = new SelectOrNew(this)))
49
+ })
50
+ }
51
+
52
+ var old = $.fn.selectOrNew
53
+
54
+ $.fn.selectOrNew = Plugin
55
+ $.fn.selectOrNew.Constructor = SelectOrNew
56
+
57
+
58
+ // SELECT-OR-NEW NO CONFLICT
59
+ // =========================
60
+
61
+ $.fn.selectOrNew.noConflict = function () {
62
+ $.fn.selectOrNew = old
63
+ return this
64
+ }
65
+
66
+
67
+ // SELECT-OR-NEW DATA-API
68
+ // ======================
69
+
70
+ $(window).on('load page:load page:restore', function () {
71
+ $('[data-select-or-new]').each(function () {
72
+ Plugin.call(this)
73
+ })
74
+ })
75
+
76
+ }(jQuery);