renalware-core 2.0.123 → 2.0.124

Sign up to get free protection for your applications and to get access to all the features.
Files changed (117) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +0 -6
  3. data/app/assets/config/renalware/core/manifest.js +5 -0
  4. data/app/assets/images/renalware/icons/chevron-down.svg +1 -0
  5. data/app/assets/images/renalware/icons/chevron-up.svg +1 -0
  6. data/app/assets/images/renalware/icons/chevrons-down.svg +1 -0
  7. data/app/assets/images/renalware/icons/chevrons-up.svg +1 -0
  8. data/app/assets/javascripts/renalware/README.md +9 -0
  9. data/app/assets/javascripts/renalware/{charting/charting.js.erb → charting.js} +0 -2
  10. data/app/assets/javascripts/renalware/{ajax_errors.js → components/ajax_errors.js} +0 -0
  11. data/app/assets/javascripts/renalware/{aki_alerts.js → components/aki_alerts.js} +0 -0
  12. data/app/assets/javascripts/renalware/{appointments.js → components/appointments.js} +0 -0
  13. data/app/assets/javascripts/renalware/{behaviours.js → components/behaviours.js} +0 -0
  14. data/app/assets/javascripts/renalware/components/bla.es6 +1 -0
  15. data/app/assets/javascripts/renalware/{clipboard_setup.js → components/clipboard_setup.js} +0 -0
  16. data/app/assets/javascripts/renalware/components/clockpicker.js +742 -0
  17. data/app/assets/javascripts/renalware/{contacts.js → components/contacts.js} +0 -0
  18. data/app/assets/javascripts/renalware/{dialogs.js.erb → components/dialogs.js.erb} +0 -0
  19. data/app/assets/javascripts/renalware/{drugs.js → components/drugs.js} +0 -0
  20. data/app/assets/javascripts/renalware/{events.js → components/events.js} +0 -0
  21. data/app/assets/javascripts/renalware/{feed_only_inputs.js.erb → components/feed_only_inputs.js.erb} +0 -0
  22. data/app/assets/javascripts/renalware/{feeds.js → components/feeds.js} +0 -0
  23. data/app/assets/javascripts/renalware/{forms.js → components/forms.js} +0 -0
  24. data/app/assets/javascripts/renalware/{full_screen.js → components/full_screen.js} +0 -0
  25. data/app/assets/javascripts/renalware/{hd.js → components/hd.js} +0 -0
  26. data/app/assets/javascripts/renalware/{iframe.js → components/iframe.js} +0 -0
  27. data/app/assets/javascripts/renalware/{keyboard_shortcuts.js → components/keyboard_shortcuts.js} +0 -0
  28. data/app/assets/javascripts/renalware/{layout.js → components/layout.js} +0 -0
  29. data/app/assets/javascripts/renalware/{letters.js → components/letters.js} +0 -0
  30. data/app/assets/javascripts/renalware/{masonry.run.js → components/masonry.run.js} +0 -0
  31. data/app/assets/javascripts/renalware/{messaging.js → components/messaging.js} +0 -0
  32. data/app/assets/javascripts/renalware/{modality_codes.js → components/modality_codes.js} +0 -0
  33. data/app/assets/javascripts/renalware/{modality_reasons.js → components/modality_reasons.js} +0 -0
  34. data/app/assets/javascripts/renalware/{navigation.js → components/navigation.js} +0 -0
  35. data/app/assets/javascripts/renalware/{patient_ajax_search.js → components/patient_ajax_search.js} +0 -0
  36. data/app/assets/javascripts/renalware/{patient_menu.js → components/patient_menu.js} +0 -0
  37. data/app/assets/javascripts/renalware/{pd.js → components/pd.js} +0 -0
  38. data/app/assets/javascripts/renalware/{pdf.js → components/pdf.js} +0 -0
  39. data/app/assets/javascripts/renalware/{person_ajax_search.js → components/person_ajax_search.js} +0 -0
  40. data/app/assets/javascripts/renalware/{primary_care_physician_search.js → components/primary_care_physician_search.js} +0 -0
  41. data/app/assets/javascripts/renalware/{primary_care_physicians.js → components/primary_care_physicians.js} +0 -0
  42. data/app/assets/javascripts/renalware/{problems.js → components/problems.js} +0 -0
  43. data/app/assets/javascripts/renalware/{renal.js → components/renal.js} +0 -0
  44. data/app/assets/javascripts/renalware/{reporting.js.erb → components/reporting.js.erb} +0 -0
  45. data/app/assets/javascripts/renalware/{searchables.js → components/searchables.js} +0 -0
  46. data/app/assets/javascripts/renalware/{select2-ajax-search.js → components/select2-ajax-search.js} +0 -0
  47. data/app/assets/javascripts/renalware/{session_timeout_redirect.js.erb → components/session_timeout_redirect.js.erb} +0 -0
  48. data/app/assets/javascripts/renalware/{sortable.js → components/sortable.js} +0 -0
  49. data/app/assets/javascripts/renalware/{table.js → components/table.js} +0 -0
  50. data/app/assets/javascripts/renalware/{tabs.js → components/tabs.js} +0 -0
  51. data/app/assets/javascripts/renalware/components/toggler.js +64 -0
  52. data/app/assets/javascripts/renalware/{transplants.js → components/transplants.js} +0 -0
  53. data/app/assets/javascripts/renalware/{application.js.erb → core.js.erb} +1 -2
  54. data/app/assets/stylesheets/renalware/README.md +16 -0
  55. data/app/assets/stylesheets/renalware/base/_variables.scss +1 -0
  56. data/app/assets/stylesheets/renalware/{application.scss → core.scss} +0 -0
  57. data/app/assets/stylesheets/renalware/lib/_clockpicker.css +98 -98
  58. data/app/assets/stylesheets/renalware/partials/_button.scss +49 -0
  59. data/app/assets/stylesheets/renalware/{clipboard.scss → partials/_clipboard.scss} +0 -0
  60. data/app/assets/stylesheets/renalware/partials/_tables.scss +63 -1
  61. data/app/assets/stylesheets/renalware/partials/_toggling.scss +38 -0
  62. data/app/assets/stylesheets/renalware/{print/pathology_request_forms.scss → pathology_request_forms.scss} +0 -0
  63. data/app/controllers/renalware/letters/letters_controller.rb +1 -1
  64. data/app/controllers/renalware/problems/notes_controller.rb +6 -0
  65. data/app/helpers/renalware/application_helper.rb +0 -7
  66. data/app/helpers/renalware/link_helper.rb +13 -0
  67. data/app/helpers/renalware/mdm_helper.rb +2 -1
  68. data/app/helpers/renalware/toggle_helper.rb +22 -0
  69. data/app/javascript/controllers/{clipboard_controller.js → clipboard_controller.js.dead} +0 -0
  70. data/app/models/concerns/renalware/transaction_retry.rb +38 -0
  71. data/app/models/renalware/accesses/patient.rb +1 -1
  72. data/app/models/renalware/hd/session.rb +1 -0
  73. data/app/models/renalware/letters/letter.rb +1 -0
  74. data/app/models/renalware/modalities/modality.rb +1 -1
  75. data/app/models/renalware/patient.rb +9 -4
  76. data/app/models/renalware/patients/ingestion/commands/add_or_update_patient.rb +6 -0
  77. data/app/views/renalware/clinical/body_compositions/_table.html.slim +9 -2
  78. data/app/views/renalware/clinics/clinic_visits/_table.html.slim +2 -1
  79. data/app/views/renalware/clinics/clinic_visits/_table_row.html.slim +3 -8
  80. data/app/views/renalware/clinics/visits/_table.html.slim +6 -5
  81. data/app/views/renalware/clinics/visits/_table_row.html.slim +34 -12
  82. data/app/views/renalware/dashboard/letters/_letter.html.slim +0 -2
  83. data/app/views/renalware/events/events/_event.html.slim +6 -9
  84. data/app/views/renalware/events/events/_table.html.slim +3 -1
  85. data/app/views/renalware/hd/sessions/_row.html.slim +2 -6
  86. data/app/views/renalware/hd/sessions/_thead.html.slim +1 -0
  87. data/app/views/renalware/hd/sessions/dna/_row.html.slim +3 -6
  88. data/app/views/renalware/hospitals/units/index.html.slim +0 -2
  89. data/app/views/renalware/layouts/error.html.slim +1 -1
  90. data/app/views/renalware/letters/electronic_receipts/_table.html.slim +0 -1
  91. data/app/views/renalware/letters/electronic_receipts/sent.html.slim +0 -1
  92. data/app/views/renalware/letters/letters/_letter.html.slim +4 -7
  93. data/app/views/renalware/letters/letters/_table.html.slim +2 -1
  94. data/app/views/renalware/letters/lists/_letter.html.slim +8 -12
  95. data/app/views/renalware/letters/lists/_table.html.slim +4 -3
  96. data/app/views/renalware/mdm/_clinic_visits.html.slim +5 -0
  97. data/app/views/renalware/pathology/requests/requests/create.pdf.slim +1 -1
  98. data/app/views/renalware/pathology/requests/requests/new.html.slim +2 -19
  99. data/app/views/renalware/pathology/requests/requests/show.pdf.slim +1 -1
  100. data/app/views/renalware/problems/notes/_table.html.slim +12 -3
  101. data/app/views/renalware/snippets/snippets/_row.html.slim +0 -2
  102. data/app/views/renalware/surveys/_eq5d_summary_part.html.slim +1 -1
  103. data/app/views/renalware/surveys/_pos_s_summary_part.html.slim +1 -1
  104. data/config/routes/patients.rb +1 -1
  105. data/lib/renalware.rb +0 -13
  106. data/lib/renalware/engine.rb +3 -60
  107. data/lib/renalware/version.rb +1 -1
  108. data/lib/tasks/renalware.rake +3 -100
  109. metadata +63 -58
  110. data/app/assets/javascripts/renalware/clockpicker.js +0 -742
  111. data/app/assets/javascripts/renalware/toggler.js +0 -41
  112. data/app/javascript/packs/renalware_core.js +0 -20
  113. data/config/webpack/development.js +0 -5
  114. data/config/webpack/environment.js +0 -3
  115. data/config/webpack/production.js +0 -5
  116. data/config/webpack/test.js +0 -5
  117. data/config/webpacker.yml +0 -103
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a8947eece7d110e83bf494a41fd4f0c72fc654ca830236c6207abdd151d5d556
4
- data.tar.gz: f7717b64d5286fcc533e247fd278653851f79c263fb928fa136f11630ccaa9dd
3
+ metadata.gz: 965f9e69a6b55986cb882e50b82928bb99b2208966d7258a0fe5856d9a593db1
4
+ data.tar.gz: f93fa7318de181ff6177f5427570ad2fe005dad29845599ac7f27f606e49cd56
5
5
  SHA512:
6
- metadata.gz: 504ea58c9804a3f70209bac95fd4daa8f494fb0a3e78ef3b5bebdbda6a12d7efbd930590c2d69f0cdb31b36f0f4316834842866dc3c87f365a70335af389b9fa
7
- data.tar.gz: 4fd87df55586b2a7043baef87043986d7791b5d3a9b3f16228fab25235b1837e3d686d3eefca9b4969c42140f69c6614efdc8f39e30a0d394dcb44fcaf953b86
6
+ metadata.gz: 4000b4914976fb5c97455c8301b81e2076c32cf0400bc566f4613842f01570583a30b89f4aceda79c84dd478f57f55151b280859866fa8b8277317d4cad505aa
7
+ data.tar.gz: 265d952f82bd209271be9b36abf72c2c556f5cbe729e3e0e74c6346d27c0bb82ca9425324fcc359199078811e34bca7de5d36a249c8fc33f6e5cfdd5399092d1
data/Rakefile CHANGED
@@ -51,12 +51,6 @@ namespace :yarn do
51
51
  end
52
52
  end
53
53
 
54
- namespace :webpacker do
55
- task :compile do
56
- Rake::Task["app:renalware:webpacker_compile"].invoke
57
- end
58
- end
59
-
60
54
  # Default rake task to run all tests:
61
55
  # bundle exec rake
62
56
  task :engine_default_task do
@@ -0,0 +1,5 @@
1
+ //= link_tree ../../../images
2
+ //= link_directory ../../../stylesheets/renalware .css
3
+ //= link_directory ../../../javascripts/renalware .js
4
+ //= link renalware/modernizr
5
+ //= link renalware/iframeResizer.contentWindow.js
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-down"><polyline points="6 9 12 15 18 9"></polyline></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-up"><polyline points="18 15 12 9 6 15"></polyline></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevrons-down"><polyline points="7 13 12 18 17 13"></polyline><polyline points="7 6 12 11 17 6"></polyline></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevrons-up"><polyline points="17 11 12 6 7 11"></polyline><polyline points="17 18 12 13 7 18"></polyline></svg>
@@ -0,0 +1,9 @@
1
+ # Javascript
2
+
3
+ The js or js.erb files in this top-level folder will be compiled and linked
4
+ by sprockets 4 as individually downloadble .js assets.
5
+
6
+ core.jd.erb is the main js file which imports other .js files in
7
+ ./components and includes js assets from external gem dependencies.
8
+
9
+ See https://github.com/rails/sprockets#link_directory
@@ -1,4 +1,2 @@
1
1
  //= require chartkick
2
2
  //= require Chart.bundle
3
- //= require_tree .
4
- //
@@ -0,0 +1 @@
1
+ // console.log("es6")
@@ -0,0 +1,742 @@
1
+ /*!
2
+ * This file moved (and its .css counterpart) to app/assets (rather than included via a gem or
3
+ * living in ./vendor) because we have fixed a bug here and I want to make it explicit
4
+ * that we now have ownership of both files, and to prevent them being accidentally
5
+ * refreshed and thereby losing our changes.
6
+ *
7
+ * ClockPicker v0.0.7 (http://weareoutman.github.io/clockpicker/)
8
+ * Copyright 2014 Wang Shenwei.
9
+ * Licensed under MIT (https://github.com/weareoutman/clockpicker/blob/gh-pages/LICENSE)
10
+ */
11
+
12
+ ;(function(){
13
+ var $ = window.jQuery,
14
+ $win = $(window),
15
+ $doc = $(document),
16
+ $body;
17
+
18
+ // Can I use inline svg ?
19
+ var svgNS = 'http://www.w3.org/2000/svg',
20
+ svgSupported = 'SVGAngle' in window && (function(){
21
+ var supported,
22
+ el = document.createElement('div');
23
+ el.innerHTML = '<svg/>';
24
+ supported = (el.firstChild && el.firstChild.namespaceURI) == svgNS;
25
+ el.innerHTML = '';
26
+ return supported;
27
+ }());
28
+
29
+ // Can I use transition ?
30
+ var transitionSupported = (function(){
31
+ var style = document.createElement('div').style;
32
+ return 'transition' in style ||
33
+ 'WebkitTransition' in style ||
34
+ 'MozTransition' in style ||
35
+ 'msTransition' in style ||
36
+ 'OTransition' in style;
37
+ }());
38
+
39
+ // Listen touch events in touch screen device, instead of mouse events in desktop.
40
+ var touchSupported = 'ontouchstart' in window,
41
+ mousedownEvent = 'mousedown' + ( touchSupported ? ' touchstart' : ''),
42
+ mousemoveEvent = 'mousemove.clockpicker' + ( touchSupported ? ' touchmove.clockpicker' : ''),
43
+ mouseupEvent = 'mouseup.clockpicker' + ( touchSupported ? ' touchend.clockpicker' : '');
44
+
45
+ // Vibrate the device if supported
46
+ var vibrate = navigator.vibrate ? 'vibrate' : navigator.webkitVibrate ? 'webkitVibrate' : null;
47
+
48
+ function createSvgElement(name) {
49
+ return document.createElementNS(svgNS, name);
50
+ }
51
+
52
+ function leadingZero(num) {
53
+ return (num < 10 ? '0' : '') + num;
54
+ }
55
+
56
+ // Get a unique id
57
+ var idCounter = 0;
58
+ function uniqueId(prefix) {
59
+ var id = ++idCounter + '';
60
+ return prefix ? prefix + id : id;
61
+ }
62
+
63
+ // Clock size
64
+ var dialRadius = 100,
65
+ outerRadius = 80,
66
+ // innerRadius = 80 on 12 hour clock
67
+ innerRadius = 54,
68
+ tickRadius = 13,
69
+ diameter = dialRadius * 2,
70
+ duration = transitionSupported ? 350 : 1;
71
+
72
+ // Popover template
73
+ var tpl = [
74
+ '<div class="popover clockpicker-popover">',
75
+ '<div class="arrow"></div>',
76
+ '<div class="popover-title">',
77
+ '<span class="clockpicker-span-hours text-primary"></span>',
78
+ ' : ',
79
+ '<span class="clockpicker-span-minutes"></span>',
80
+ '<span class="clockpicker-span-am-pm"></span>',
81
+ '</div>',
82
+ '<div class="popover-content">',
83
+ '<div class="clockpicker-plate">',
84
+ '<div class="clockpicker-canvas"></div>',
85
+ '<div class="clockpicker-dial clockpicker-hours"></div>',
86
+ '<div class="clockpicker-dial clockpicker-minutes clockpicker-dial-out"></div>',
87
+ '</div>',
88
+ '<span class="clockpicker-am-pm-block">',
89
+ '</span>',
90
+ '</div>',
91
+ '</div>'
92
+ ].join('');
93
+
94
+ // ClockPicker
95
+ function ClockPicker(element, options) {
96
+ var popover = $(tpl),
97
+ plate = popover.find('.clockpicker-plate'),
98
+ hoursView = popover.find('.clockpicker-hours'),
99
+ minutesView = popover.find('.clockpicker-minutes'),
100
+ amPmBlock = popover.find('.clockpicker-am-pm-block'),
101
+ isInput = element.prop('tagName') === 'INPUT',
102
+ input = isInput ? element : element.find('input'),
103
+ addon = element.find('.input-group-addon .prefix'),
104
+ self = this,
105
+ timer;
106
+
107
+ this.id = uniqueId('cp');
108
+ this.element = element;
109
+ this.options = options;
110
+ this.isAppended = false;
111
+ this.isShown = false;
112
+ this.currentView = 'hours';
113
+ this.isInput = isInput;
114
+ this.input = input;
115
+ this.addon = addon;
116
+ this.popover = popover;
117
+ this.plate = plate;
118
+ this.hoursView = hoursView;
119
+ this.minutesView = minutesView;
120
+ this.amPmBlock = amPmBlock;
121
+ this.spanHours = popover.find('.clockpicker-span-hours');
122
+ this.spanMinutes = popover.find('.clockpicker-span-minutes');
123
+ this.spanAmPm = popover.find('.clockpicker-span-am-pm');
124
+ this.amOrPm = "PM";
125
+
126
+ // Setup for for 12 hour clock if option is selected
127
+ if (options.twelvehour) {
128
+
129
+ var amPmButtonsTemplate = ['<div class="clockpicker-am-pm-block">',
130
+ '<button type="button" class="btn btn-sm btn-default clockpicker-button clockpicker-am-button">',
131
+ 'AM</button>',
132
+ '<button type="button" class="btn btn-sm btn-default clockpicker-button clockpicker-pm-button">',
133
+ 'PM</button>',
134
+ '</div>'].join('');
135
+
136
+ var amPmButtons = $(amPmButtonsTemplate);
137
+ //amPmButtons.appendTo(plate);
138
+
139
+ ////Not working b/c they are not shown when this runs
140
+ //$('clockpicker-am-button')
141
+ // .on("click", function() {
142
+ // self.amOrPm = "AM";
143
+ // $('.clockpicker-span-am-pm').empty().append('AM');
144
+ // });
145
+ //
146
+ //$('clockpicker-pm-button')
147
+ // .on("click", function() {
148
+ // self.amOrPm = "PM";
149
+ // $('.clockpicker-span-am-pm').empty().append('PM');
150
+ // });
151
+
152
+ $('<button type="button" class="btn btn-sm btn-default clockpicker-button am-button">' + "AM" + '</button>')
153
+ .on("click", function() {
154
+ self.amOrPm = "AM";
155
+ $('.clockpicker-span-am-pm').empty().append('AM');
156
+ }).appendTo(this.amPmBlock);
157
+
158
+
159
+ $('<button type="button" class="btn btn-sm btn-default clockpicker-button pm-button">' + "PM" + '</button>')
160
+ .on("click", function() {
161
+ self.amOrPm = 'PM';
162
+ $('.clockpicker-span-am-pm').empty().append('PM');
163
+ }).appendTo(this.amPmBlock);
164
+
165
+ }
166
+
167
+ if (! options.autoclose) {
168
+ // If autoclose is not setted, append a button
169
+ $('<button type="button" class="btn btn-sm btn-default btn-block clockpicker-button">' + options.donetext + '</button>')
170
+ .click($.proxy(this.done, this))
171
+ .appendTo(popover);
172
+ }
173
+
174
+ // Placement and arrow align - make sure they make sense.
175
+ if ((options.placement === 'top' || options.placement === 'bottom') && (options.align === 'top' || options.align === 'bottom')) options.align = 'left';
176
+ if ((options.placement === 'left' || options.placement === 'right') && (options.align === 'left' || options.align === 'right')) options.align = 'top';
177
+
178
+ popover.addClass(options.placement);
179
+ popover.addClass('clockpicker-align-' + options.align);
180
+
181
+ this.spanHours.click($.proxy(this.toggleView, this, 'hours'));
182
+ this.spanMinutes.click($.proxy(this.toggleView, this, 'minutes'));
183
+
184
+ // Show or toggle
185
+ input.on('focus.clockpicker click.clockpicker', $.proxy(this.show, this));
186
+ addon.on('click.clockpicker', $.proxy(this.toggle, this));
187
+
188
+ // Build ticks
189
+ var tickTpl = $('<div class="clockpicker-tick"></div>'),
190
+ i, tick, radian, radius;
191
+
192
+ // Hours view
193
+ if (options.twelvehour) {
194
+ for (i = 1; i < 13; i += 1) {
195
+ tick = tickTpl.clone();
196
+ radian = i / 6 * Math.PI;
197
+ radius = outerRadius;
198
+ tick.css('font-size', '120%');
199
+ tick.css({
200
+ left: dialRadius + Math.sin(radian) * radius - tickRadius,
201
+ top: dialRadius - Math.cos(radian) * radius - tickRadius
202
+ });
203
+ tick.html(i === 0 ? '00' : i);
204
+ hoursView.append(tick);
205
+ tick.on(mousedownEvent, mousedown);
206
+ }
207
+ } else {
208
+ for (i = 0; i < 24; i += 1) {
209
+ tick = tickTpl.clone();
210
+ radian = i / 6 * Math.PI;
211
+ var inner = i > 0 && i < 13;
212
+ radius = inner ? innerRadius : outerRadius;
213
+ tick.css({
214
+ left: dialRadius + Math.sin(radian) * radius - tickRadius,
215
+ top: dialRadius - Math.cos(radian) * radius - tickRadius
216
+ });
217
+ if (inner) {
218
+ tick.css('font-size', '120%');
219
+ }
220
+ tick.html(i === 0 ? '00' : i);
221
+ hoursView.append(tick);
222
+ tick.on(mousedownEvent, mousedown);
223
+ }
224
+ }
225
+
226
+ // Minutes view
227
+ for (i = 0; i < 60; i += 5) {
228
+ tick = tickTpl.clone();
229
+ radian = i / 30 * Math.PI;
230
+ tick.css({
231
+ left: dialRadius + Math.sin(radian) * outerRadius - tickRadius,
232
+ top: dialRadius - Math.cos(radian) * outerRadius - tickRadius
233
+ });
234
+ tick.css('font-size', '120%');
235
+ tick.html(leadingZero(i));
236
+ minutesView.append(tick);
237
+ tick.on(mousedownEvent, mousedown);
238
+ }
239
+
240
+ // Clicking on minutes view space
241
+ plate.on(mousedownEvent, function(e){
242
+ if ($(e.target).closest('.clockpicker-tick').length === 0) {
243
+ mousedown(e, true);
244
+ }
245
+ });
246
+
247
+ // Mousedown or touchstart
248
+ function mousedown(e, space) {
249
+ var offset = plate.offset(),
250
+ isTouch = /^touch/.test(e.type),
251
+ x0 = offset.left + dialRadius,
252
+ y0 = offset.top + dialRadius,
253
+ dx = (isTouch ? e.originalEvent.touches[0] : e).pageX - x0,
254
+ dy = (isTouch ? e.originalEvent.touches[0] : e).pageY - y0,
255
+ z = Math.sqrt(dx * dx + dy * dy),
256
+ moved = false;
257
+
258
+ // When clicking on minutes view space, check the mouse position
259
+ if (space && (z < outerRadius - tickRadius || z > outerRadius + tickRadius)) {
260
+ return;
261
+ }
262
+ e.preventDefault();
263
+
264
+ // Set cursor style of body after 200ms
265
+ var movingTimer = setTimeout(function(){
266
+ $body.addClass('clockpicker-moving');
267
+ }, 200);
268
+
269
+ // Place the canvas to top
270
+ if (svgSupported) {
271
+ plate.append(self.canvas);
272
+ }
273
+
274
+ // Clock
275
+ self.setHand(dx, dy, ! space, true);
276
+
277
+ // Mousemove on document
278
+ $doc.off(mousemoveEvent).on(mousemoveEvent, function(e){
279
+ e.preventDefault();
280
+ var isTouch = /^touch/.test(e.type),
281
+ x = (isTouch ? e.originalEvent.touches[0] : e).pageX - x0,
282
+ y = (isTouch ? e.originalEvent.touches[0] : e).pageY - y0;
283
+ if (! moved && x === dx && y === dy) {
284
+ // Clicking in chrome on windows will trigger a mousemove event
285
+ return;
286
+ }
287
+ moved = true;
288
+ self.setHand(x, y, false, true);
289
+ });
290
+
291
+ // Mouseup on document
292
+ $doc.off(mouseupEvent).on(mouseupEvent, function(e){
293
+ $doc.off(mouseupEvent);
294
+ e.preventDefault();
295
+ var isTouch = /^touch/.test(e.type),
296
+ x = (isTouch ? e.originalEvent.changedTouches[0] : e).pageX - x0,
297
+ y = (isTouch ? e.originalEvent.changedTouches[0] : e).pageY - y0;
298
+ if ((space || moved) && x === dx && y === dy) {
299
+ self.setHand(x, y);
300
+ }
301
+ if (self.currentView === 'hours') {
302
+ self.toggleView('minutes', duration / 2);
303
+ } else {
304
+ if (options.autoclose) {
305
+ self.minutesView.addClass('clockpicker-dial-out');
306
+ setTimeout(function(){
307
+ self.done();
308
+ }, duration / 2);
309
+ }
310
+ }
311
+ plate.prepend(canvas);
312
+
313
+ // Reset cursor style of body
314
+ clearTimeout(movingTimer);
315
+ $body.removeClass('clockpicker-moving');
316
+
317
+ // Unbind mousemove event
318
+ $doc.off(mousemoveEvent);
319
+ });
320
+ }
321
+
322
+ if (svgSupported) {
323
+ // Draw clock hands and others
324
+ var canvas = popover.find('.clockpicker-canvas'),
325
+ svg = createSvgElement('svg');
326
+ svg.setAttribute('class', 'clockpicker-svg');
327
+ svg.setAttribute('width', diameter);
328
+ svg.setAttribute('height', diameter);
329
+ var g = createSvgElement('g');
330
+ g.setAttribute('transform', 'translate(' + dialRadius + ',' + dialRadius + ')');
331
+ var bearing = createSvgElement('circle');
332
+ bearing.setAttribute('class', 'clockpicker-canvas-bearing');
333
+ bearing.setAttribute('cx', 0);
334
+ bearing.setAttribute('cy', 0);
335
+ bearing.setAttribute('r', 2);
336
+ var hand = createSvgElement('line');
337
+ hand.setAttribute('x1', 0);
338
+ hand.setAttribute('y1', 0);
339
+ var bg = createSvgElement('circle');
340
+ bg.setAttribute('class', 'clockpicker-canvas-bg');
341
+ bg.setAttribute('r', tickRadius);
342
+ var fg = createSvgElement('circle');
343
+ fg.setAttribute('class', 'clockpicker-canvas-fg');
344
+ fg.setAttribute('r', 3.5);
345
+ g.appendChild(hand);
346
+ g.appendChild(bg);
347
+ g.appendChild(fg);
348
+ g.appendChild(bearing);
349
+ svg.appendChild(g);
350
+ canvas.append(svg);
351
+
352
+ this.hand = hand;
353
+ this.bg = bg;
354
+ this.fg = fg;
355
+ this.bearing = bearing;
356
+ this.g = g;
357
+ this.canvas = canvas;
358
+ }
359
+
360
+ raiseCallback(this.options.init);
361
+ }
362
+
363
+ function raiseCallback(callbackFunction) {
364
+ if (callbackFunction && typeof callbackFunction === "function") {
365
+ callbackFunction();
366
+ }
367
+ }
368
+
369
+ // Default options
370
+ ClockPicker.DEFAULTS = {
371
+ 'default': '', // default time, 'now' or '13:14' e.g.
372
+ fromnow: 0, // set default time to * milliseconds from now (using with default = 'now')
373
+ placement: 'bottom', // clock popover placement
374
+ align: 'left', // popover arrow align
375
+ donetext: '完成', // done button text
376
+ autoclose: false, // auto close when minute is selected
377
+ twelvehour: false, // change to 12 hour AM/PM clock from 24 hour
378
+ vibrate: true // vibrate the device when dragging clock hand
379
+ };
380
+
381
+ // Show or hide popover
382
+ ClockPicker.prototype.toggle = function(){
383
+ this[this.isShown ? 'hide' : 'show']();
384
+ };
385
+
386
+ // Set popover position
387
+ ClockPicker.prototype.locate = function(){
388
+ var element = this.element,
389
+ popover = this.popover,
390
+ offset = element.offset(),
391
+ width = element.outerWidth(),
392
+ height = element.outerHeight(),
393
+ placement = this.options.placement,
394
+ align = this.options.align,
395
+ styles = {},
396
+ self = this;
397
+
398
+ popover.show();
399
+
400
+ // Place the popover
401
+ switch (placement) {
402
+ case 'bottom':
403
+ styles.top = offset.top + height;
404
+ break;
405
+ case 'right':
406
+ styles.left = offset.left + width;
407
+ break;
408
+ case 'top':
409
+ styles.top = offset.top - popover.outerHeight();
410
+ break;
411
+ case 'left':
412
+ styles.left = offset.left - popover.outerWidth();
413
+ break;
414
+ }
415
+
416
+ // Align the popover arrow
417
+ switch (align) {
418
+ case 'left':
419
+ styles.left = offset.left;
420
+ break;
421
+ case 'right':
422
+ styles.left = offset.left + width - popover.outerWidth();
423
+ break;
424
+ case 'top':
425
+ styles.top = offset.top;
426
+ break;
427
+ case 'bottom':
428
+ styles.top = offset.top + height - popover.outerHeight();
429
+ break;
430
+ }
431
+
432
+ popover.css(styles);
433
+ };
434
+
435
+ // Show popover
436
+ ClockPicker.prototype.show = function(e){
437
+ // Not show again
438
+ if (this.isShown) {
439
+ return;
440
+ }
441
+
442
+ raiseCallback(this.options.beforeShow);
443
+
444
+ var self = this;
445
+
446
+ // Initialize
447
+ if (! this.isAppended) {
448
+ // Append popover to body
449
+ $body = $(document.body).append(this.popover);
450
+
451
+ // Reset position when resize
452
+ $win.on('resize.clockpicker' + this.id, function(){
453
+ if (self.isShown) {
454
+ self.locate();
455
+ }
456
+ });
457
+
458
+ this.isAppended = true;
459
+ }
460
+
461
+ // Get the time
462
+ var value = ((this.input.prop('value') || this.options['default'] || '') + '').split(':');
463
+ if (value[0] === 'now') {
464
+ var now = new Date(+ new Date() + this.options.fromnow);
465
+ value = [
466
+ now.getHours(),
467
+ now.getMinutes()
468
+ ];
469
+ }
470
+ this.hours = + value[0] || 0;
471
+ this.minutes = + value[1] || 0;
472
+ this.spanHours.html(leadingZero(this.hours));
473
+ this.spanMinutes.html(leadingZero(this.minutes));
474
+
475
+ // Toggle to hours view
476
+ this.toggleView('hours');
477
+
478
+ // Set position
479
+ this.locate();
480
+
481
+ this.isShown = true;
482
+
483
+ // Hide when clicking or tabbing on any element except the clock, input and addon
484
+ $doc.on('click.clockpicker.' + this.id + ' focusin.clockpicker.' + this.id, function(e){
485
+
486
+ /* TC 13/7/17
487
+ Fixed a bug here - changed
488
+ target.closest(self.addon).length === 0 &&
489
+ to
490
+ target.closest(self.addon.selector).length === 0 &&
491
+ Without this it is not possible to click on the clock icon to open the popover.
492
+ */
493
+ var target = $(e.target);
494
+ if (target.closest(self.popover).length === 0 &&
495
+ target.closest(self.addon.selector).length === 0 &&
496
+ target.closest(self.input).length === 0) {
497
+ self.hide();
498
+ }
499
+ });
500
+
501
+ // Hide when ESC is pressed
502
+ $doc.on('keyup.clockpicker.' + this.id, function(e){
503
+ if (e.keyCode === 27) {
504
+ self.hide();
505
+ }
506
+ });
507
+
508
+ raiseCallback(this.options.afterShow);
509
+ };
510
+
511
+ // Hide popover
512
+ ClockPicker.prototype.hide = function(){
513
+ raiseCallback(this.options.beforeHide);
514
+
515
+ this.isShown = false;
516
+
517
+ // Unbinding events on document
518
+ $doc.off('click.clockpicker.' + this.id + ' focusin.clockpicker.' + this.id);
519
+ $doc.off('keyup.clockpicker.' + this.id);
520
+
521
+ this.popover.hide();
522
+
523
+ raiseCallback(this.options.afterHide);
524
+ };
525
+
526
+ // Toggle to hours or minutes view
527
+ ClockPicker.prototype.toggleView = function(view, delay){
528
+ var raiseAfterHourSelect = false;
529
+ if (view === 'minutes' && $(this.hoursView).css("visibility") === "visible") {
530
+ raiseCallback(this.options.beforeHourSelect);
531
+ raiseAfterHourSelect = true;
532
+ }
533
+ var isHours = view === 'hours',
534
+ nextView = isHours ? this.hoursView : this.minutesView,
535
+ hideView = isHours ? this.minutesView : this.hoursView;
536
+
537
+ this.currentView = view;
538
+
539
+ this.spanHours.toggleClass('text-primary', isHours);
540
+ this.spanMinutes.toggleClass('text-primary', ! isHours);
541
+
542
+ // Let's make transitions
543
+ hideView.addClass('clockpicker-dial-out');
544
+ nextView.css('visibility', 'visible').removeClass('clockpicker-dial-out');
545
+
546
+ // Reset clock hand
547
+ this.resetClock(delay);
548
+
549
+ // After transitions ended
550
+ clearTimeout(this.toggleViewTimer);
551
+ this.toggleViewTimer = setTimeout(function(){
552
+ hideView.css('visibility', 'hidden');
553
+ }, duration);
554
+
555
+ if (raiseAfterHourSelect) {
556
+ raiseCallback(this.options.afterHourSelect);
557
+ }
558
+ };
559
+
560
+ // Reset clock hand
561
+ ClockPicker.prototype.resetClock = function(delay){
562
+ var view = this.currentView,
563
+ value = this[view],
564
+ isHours = view === 'hours',
565
+ unit = Math.PI / (isHours ? 6 : 30),
566
+ radian = value * unit,
567
+ radius = isHours && value > 0 && value < 13 ? innerRadius : outerRadius,
568
+ x = Math.sin(radian) * radius,
569
+ y = - Math.cos(radian) * radius,
570
+ self = this;
571
+ if (svgSupported && delay) {
572
+ self.canvas.addClass('clockpicker-canvas-out');
573
+ setTimeout(function(){
574
+ self.canvas.removeClass('clockpicker-canvas-out');
575
+ self.setHand(x, y);
576
+ }, delay);
577
+ } else {
578
+ this.setHand(x, y);
579
+ }
580
+ };
581
+
582
+ // Set clock hand to (x, y)
583
+ ClockPicker.prototype.setHand = function(x, y, roundBy5, dragging){
584
+ var radian = Math.atan2(x, - y),
585
+ isHours = this.currentView === 'hours',
586
+ unit = Math.PI / (isHours || roundBy5 ? 6 : 30),
587
+ z = Math.sqrt(x * x + y * y),
588
+ options = this.options,
589
+ inner = isHours && z < (outerRadius + innerRadius) / 2,
590
+ radius = inner ? innerRadius : outerRadius,
591
+ value;
592
+
593
+ if (options.twelvehour) {
594
+ radius = outerRadius;
595
+ }
596
+
597
+ // Radian should in range [0, 2PI]
598
+ if (radian < 0) {
599
+ radian = Math.PI * 2 + radian;
600
+ }
601
+
602
+ // Get the round value
603
+ value = Math.round(radian / unit);
604
+
605
+ // Get the round radian
606
+ radian = value * unit;
607
+
608
+ // Correct the hours or minutes
609
+ if (options.twelvehour) {
610
+ if (isHours) {
611
+ if (value === 0) {
612
+ value = 12;
613
+ }
614
+ } else {
615
+ if (roundBy5) {
616
+ value *= 5;
617
+ }
618
+ if (value === 60) {
619
+ value = 0;
620
+ }
621
+ }
622
+ } else {
623
+ if (isHours) {
624
+ if (value === 12) {
625
+ value = 0;
626
+ }
627
+ value = inner ? (value === 0 ? 12 : value) : value === 0 ? 0 : value + 12;
628
+ } else {
629
+ if (roundBy5) {
630
+ value *= 5;
631
+ }
632
+ if (value === 60) {
633
+ value = 0;
634
+ }
635
+ }
636
+ }
637
+
638
+ // Once hours or minutes changed, vibrate the device
639
+ if (this[this.currentView] !== value) {
640
+ if (vibrate && this.options.vibrate) {
641
+ // Do not vibrate too frequently
642
+ if (! this.vibrateTimer) {
643
+ navigator[vibrate](10);
644
+ this.vibrateTimer = setTimeout($.proxy(function(){
645
+ this.vibrateTimer = null;
646
+ }, this), 100);
647
+ }
648
+ }
649
+ }
650
+
651
+ this[this.currentView] = value;
652
+ this[isHours ? 'spanHours' : 'spanMinutes'].html(leadingZero(value));
653
+
654
+ // If svg is not supported, just add an active class to the tick
655
+ if (! svgSupported) {
656
+ this[isHours ? 'hoursView' : 'minutesView'].find('.clockpicker-tick').each(function(){
657
+ var tick = $(this);
658
+ tick.toggleClass('active', value === + tick.html());
659
+ });
660
+ return;
661
+ }
662
+
663
+ // Place clock hand at the top when dragging
664
+ if (dragging || (! isHours && value % 5)) {
665
+ this.g.insertBefore(this.hand, this.bearing);
666
+ this.g.insertBefore(this.bg, this.fg);
667
+ this.bg.setAttribute('class', 'clockpicker-canvas-bg clockpicker-canvas-bg-trans');
668
+ } else {
669
+ // Or place it at the bottom
670
+ this.g.insertBefore(this.hand, this.bg);
671
+ this.g.insertBefore(this.fg, this.bg);
672
+ this.bg.setAttribute('class', 'clockpicker-canvas-bg');
673
+ }
674
+
675
+ // Set clock hand and others' position
676
+ var cx = Math.sin(radian) * radius,
677
+ cy = - Math.cos(radian) * radius;
678
+ this.hand.setAttribute('x2', cx);
679
+ this.hand.setAttribute('y2', cy);
680
+ this.bg.setAttribute('cx', cx);
681
+ this.bg.setAttribute('cy', cy);
682
+ this.fg.setAttribute('cx', cx);
683
+ this.fg.setAttribute('cy', cy);
684
+ };
685
+
686
+ // Hours and minutes are selected
687
+ ClockPicker.prototype.done = function() {
688
+ raiseCallback(this.options.beforeDone);
689
+ this.hide();
690
+ var last = this.input.prop('value'),
691
+ value = leadingZero(this.hours) + ':' + leadingZero(this.minutes);
692
+ if (this.options.twelvehour) {
693
+ value = value + this.amOrPm;
694
+ }
695
+
696
+ this.input.prop('value', value);
697
+ if (value !== last) {
698
+ this.input.triggerHandler('change');
699
+ if (! this.isInput) {
700
+ this.element.trigger('change');
701
+ }
702
+ }
703
+
704
+ if (this.options.autoclose) {
705
+ this.input.trigger('blur');
706
+ }
707
+
708
+ raiseCallback(this.options.afterDone);
709
+ };
710
+
711
+ // Remove clockpicker from input
712
+ ClockPicker.prototype.remove = function() {
713
+ this.element.removeData('clockpicker');
714
+ this.input.off('focus.clockpicker click.clockpicker');
715
+ this.addon.off('click.clockpicker');
716
+ if (this.isShown) {
717
+ this.hide();
718
+ }
719
+ if (this.isAppended) {
720
+ $win.off('resize.clockpicker' + this.id);
721
+ this.popover.remove();
722
+ }
723
+ };
724
+
725
+ // Extends $.fn.clockpicker
726
+ $.fn.clockpicker = function(option){
727
+ var args = Array.prototype.slice.call(arguments, 1);
728
+ return this.each(function(){
729
+ var $this = $(this),
730
+ data = $this.data('clockpicker');
731
+ if (! data) {
732
+ var options = $.extend({}, ClockPicker.DEFAULTS, $this.data(), typeof option == 'object' && option);
733
+ $this.data('clockpicker', new ClockPicker($this, options));
734
+ } else {
735
+ // Manual operatsions. show, hide, remove, e.g.
736
+ if (typeof data[option] === 'function') {
737
+ data[option].apply(data, args);
738
+ }
739
+ }
740
+ });
741
+ };
742
+ }());