anjlab-widgets 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/.gitignore +18 -0
  2. data/Gemfile +13 -0
  3. data/LICENSE +22 -0
  4. data/README.md +29 -0
  5. data/Rakefile +2 -0
  6. data/anjlab-widgets.gemspec +23 -0
  7. data/lib/anjlab-widgets.rb +7 -0
  8. data/lib/anjlab-widgets/engine.rb +8 -0
  9. data/lib/anjlab-widgets/version.rb +5 -0
  10. data/spec/dummy/README.rdoc +261 -0
  11. data/spec/dummy/Rakefile +7 -0
  12. data/spec/dummy/app/assets/javascripts/application.js +17 -0
  13. data/spec/dummy/app/assets/stylesheets/application.css.scss +3 -0
  14. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  15. data/spec/dummy/app/controllers/widgets_controller.rb +10 -0
  16. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  17. data/spec/dummy/app/mailers/.gitkeep +0 -0
  18. data/spec/dummy/app/models/.gitkeep +0 -0
  19. data/spec/dummy/app/views/layouts/application.html.erb +20 -0
  20. data/spec/dummy/app/views/widgets/all.html.erb +7 -0
  21. data/spec/dummy/app/views/widgets/datepicker.html.erb +5 -0
  22. data/spec/dummy/app/views/widgets/timepicker.html.erb +1 -0
  23. data/spec/dummy/config.ru +4 -0
  24. data/spec/dummy/config/application.rb +61 -0
  25. data/spec/dummy/config/boot.rb +10 -0
  26. data/spec/dummy/config/database.yml +25 -0
  27. data/spec/dummy/config/environment.rb +5 -0
  28. data/spec/dummy/config/environments/development.rb +37 -0
  29. data/spec/dummy/config/environments/production.rb +67 -0
  30. data/spec/dummy/config/environments/test.rb +37 -0
  31. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  32. data/spec/dummy/config/initializers/inflections.rb +15 -0
  33. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  34. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  35. data/spec/dummy/config/initializers/session_store.rb +8 -0
  36. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  37. data/spec/dummy/config/locales/en.yml +5 -0
  38. data/spec/dummy/config/routes.rb +7 -0
  39. data/spec/dummy/db/development.sqlite3 +0 -0
  40. data/spec/dummy/lib/assets/.gitkeep +0 -0
  41. data/spec/dummy/log/.gitkeep +0 -0
  42. data/spec/dummy/log/development.log +11308 -0
  43. data/spec/dummy/public/404.html +26 -0
  44. data/spec/dummy/public/422.html +26 -0
  45. data/spec/dummy/public/500.html +25 -0
  46. data/spec/dummy/public/favicon.ico +0 -0
  47. data/spec/dummy/script/rails +6 -0
  48. data/spec/spec_helper.rb +9 -0
  49. data/spec/views/widgets/datepicker_spec.rb +9 -0
  50. data/vendor/assets/javascripts/anjlab/datepicker.js.coffee +369 -0
  51. data/vendor/assets/javascripts/anjlab/timepicker.js.coffee +135 -0
  52. data/vendor/assets/stylesheets/anjlab/datepicker.css.scss +85 -0
  53. data/vendor/assets/stylesheets/anjlab/timepicker.css.scss +34 -0
  54. metadata +225 -0
@@ -0,0 +1,26 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The page you were looking for doesn't exist (404)</title>
5
+ <style type="text/css">
6
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
7
+ div.dialog {
8
+ width: 25em;
9
+ padding: 0 4em;
10
+ margin: 4em auto 0 auto;
11
+ border: 1px solid #ccc;
12
+ border-right-color: #999;
13
+ border-bottom-color: #999;
14
+ }
15
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <!-- This file lives in public/404.html -->
21
+ <div class="dialog">
22
+ <h1>The page you were looking for doesn't exist.</h1>
23
+ <p>You may have mistyped the address or the page may have moved.</p>
24
+ </div>
25
+ </body>
26
+ </html>
@@ -0,0 +1,26 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The change you wanted was rejected (422)</title>
5
+ <style type="text/css">
6
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
7
+ div.dialog {
8
+ width: 25em;
9
+ padding: 0 4em;
10
+ margin: 4em auto 0 auto;
11
+ border: 1px solid #ccc;
12
+ border-right-color: #999;
13
+ border-bottom-color: #999;
14
+ }
15
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <!-- This file lives in public/422.html -->
21
+ <div class="dialog">
22
+ <h1>The change you wanted was rejected.</h1>
23
+ <p>Maybe you tried to change something you didn't have access to.</p>
24
+ </div>
25
+ </body>
26
+ </html>
@@ -0,0 +1,25 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>We're sorry, but something went wrong (500)</title>
5
+ <style type="text/css">
6
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
7
+ div.dialog {
8
+ width: 25em;
9
+ padding: 0 4em;
10
+ margin: 4em auto 0 auto;
11
+ border: 1px solid #ccc;
12
+ border-right-color: #999;
13
+ border-bottom-color: #999;
14
+ }
15
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <!-- This file lives in public/500.html -->
21
+ <div class="dialog">
22
+ <h1>We're sorry, but something went wrong.</h1>
23
+ </div>
24
+ </body>
25
+ </html>
File without changes
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
3
+
4
+ APP_PATH = File.expand_path('../../config/application', __FILE__)
5
+ require File.expand_path('../../config/boot', __FILE__)
6
+ require 'rails/commands'
@@ -0,0 +1,9 @@
1
+ ENV["RAILS_ENV"] = "development"
2
+
3
+ require File.expand_path("../dummy/config/environment.rb", __FILE__)
4
+ require "rspec/rails"
5
+ require "rspec/autorun"
6
+
7
+ RSpec.configure do |config|
8
+
9
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ describe "widgets/datepicker" do
4
+
5
+ it "renders" do
6
+ render
7
+ end
8
+
9
+ end
@@ -0,0 +1,369 @@
1
+ Locales =
2
+ en:
3
+ dates:
4
+ format: 'mm/dd/yyyy'
5
+ weekStart: 0
6
+ days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
7
+ daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
8
+ daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"]
9
+ months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
10
+ monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
11
+ ru:
12
+ dates:
13
+ format: 'dd.mm.yyyy'
14
+ weekStart: 1
15
+ days: ["Воскресенье", "Понедельник", "Вторник", "Среда", "Четверг", "Пятница", "Суббота", "Воскресенье"]
16
+ daysShort: ["Вск", "Пон", "Втр", "Срд", "Чтв", "Птн", "Суб", "Вск"]
17
+ daysMin: ["Вс", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб", "Вс"]
18
+ months: ["Январь", "Февраль", "Март", "Апрель", "Май", "Июнь", "Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь"]
19
+ monthsShort: ["Янв", "Фев", "Мар", "Апр", "Май", "Июн", "Июл", "Авг", "Сен", "Окт", "Ноя", "Дек"]
20
+
21
+ DateTools =
22
+ modes: [
23
+ {
24
+ clsName: 'days'
25
+ navFnc: 'Month'
26
+ navStep: 1
27
+ },
28
+ {
29
+ clsName: 'months'
30
+ navFnc: 'FullYear'
31
+ navStep: 1
32
+ },
33
+ {
34
+ clsName: 'years'
35
+ navFnc: 'FullYear'
36
+ navStep: 10
37
+ }
38
+ ]
39
+ isLeapYear: (year) ->
40
+ (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0))
41
+
42
+ getDaysInMonth: (year, month) ->
43
+ [31, (if DateTools.isLeapYear(year) then 29 else 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]
44
+
45
+ parseFormat: (format) ->
46
+ separator = format.match(/[.\/-].*?/)
47
+ parts = format.split(/\W+/)
48
+ if !separator || !parts || parts.length == 0
49
+ throw new Error("Invalid date format.")
50
+
51
+ {
52
+ separator: separator
53
+ parts: parts
54
+ }
55
+
56
+ parseDate: (date, format) ->
57
+ parts = date.split(format.separator)
58
+ date = new Date()
59
+
60
+ if parts.length == format.parts.length
61
+ for i in [0...format.parts.length]
62
+ val = parseInt(parts[i], 10) || 1;
63
+ switch format.parts[i]
64
+ when 'dd', 'd'
65
+ d = val
66
+ when 'mm', 'm'
67
+ m = val - 1
68
+ when 'yy'
69
+ y = 2000 + val
70
+ when 'yyyy'
71
+ y = val
72
+ date = new Date(y, m , d)
73
+
74
+ date
75
+
76
+ formatDate: (date, format) ->
77
+ val = {
78
+ d: date.getDate()
79
+ m: date.getMonth() + 1
80
+ yy: date.getFullYear().toString().substring(2)
81
+ yyyy: date.getFullYear()
82
+ }
83
+ val.dd = (if val.d < 10 then '0' else '') + val.d
84
+ val.mm = (if val.m < 10 then '0' else '') + val.m
85
+ date = []
86
+ for i in [0...format.parts.length]
87
+ date.push val[format.parts[i]]
88
+ date.join format.separator
89
+
90
+ getLocale: () ->
91
+ $('html').prop('lang') || 'en'
92
+
93
+ headTemplate: '<thead>'+
94
+ '<tr>'+
95
+ '<th class="prev"><i class="icon-arrow-left"/></th>'+
96
+ '<th colspan="5" class="switch"></th>'+
97
+ '<th class="next"><i class="icon-arrow-right"/></th>'+
98
+ '</tr>'+
99
+ '</thead>'
100
+
101
+ contTemplate: '<tbody><tr><td colspan="7"></td></tr></tbody>'
102
+
103
+ DateTools.template = '<div class="datepicker dropdown-menu">'+
104
+ '<div class="datepicker-days">'+
105
+ '<table class=" table-condensed">'+
106
+ DateTools.headTemplate+
107
+ '<tbody></tbody>'+
108
+ '</table>'+
109
+ '</div>'+
110
+ '<div class="datepicker-months">'+
111
+ '<table class="table-condensed">'+
112
+ DateTools.headTemplate+
113
+ DateTools.contTemplate+
114
+ '</table>'+
115
+ '</div>'+
116
+ '<div class="datepicker-years">'+
117
+ '<table class="table-condensed">'+
118
+ DateTools.headTemplate+
119
+ DateTools.contTemplate+
120
+ '</table>'+
121
+ '</div>'+
122
+ '</div>'
123
+
124
+ class Datepicker
125
+
126
+ constructor: (element, options)->
127
+ @element = $(element)
128
+ @locale = options.locale || @element.data('date-locale') || DateTools.getLocale()
129
+ @format = DateTools.parseFormat(options.format || this.element.data('date-format') || Locales[@locale].dates.format);
130
+ @picker = $(DateTools.template).appendTo('body').on {
131
+ click: $.proxy(@click, this)
132
+ mousedown: $.proxy(@mousedown, this)
133
+ }
134
+
135
+ @isInput = @element.is('input');
136
+ @component = if @element.is('.date') then @element.find('.add-on') else false;
137
+
138
+ if @isInput
139
+ @element.on {
140
+ focus: $.proxy(@show, this)
141
+ blur: $.proxy(@hide, this)
142
+ keyup: $.proxy(@update, this)
143
+ }
144
+ else
145
+ if @component
146
+ @component.on 'click', $.proxy(@show, this)
147
+ else
148
+ @element.on 'click', $.proxy(@show, this)
149
+
150
+ @viewMode = 0;
151
+ @weekStart = options.weekStart || @element.data('date-weekstart') || Locales[@locale].dates.weekStart
152
+ @weekEnd = if this.weekStart == 0 then 6 else @weekStart - 1
153
+ @fillDow()
154
+ @fillMonths()
155
+ @update()
156
+ @showMode()
157
+
158
+ show: (e) ->
159
+ @picker.show()
160
+ @height = if @component then @component.outerHeight() else @element.outerHeight()
161
+ @place()
162
+ $(window).on('resize', $.proxy(@place, this))
163
+ if e
164
+ e.stopPropagation()
165
+ e.preventDefault()
166
+
167
+ $(document).on('mousedown', $.proxy(@hide, this)) if !@isInput
168
+
169
+ @element.trigger
170
+ type: 'show'
171
+ date: @date
172
+
173
+ hide: ->
174
+ @picker.hide()
175
+ $(window).off 'resize', @place
176
+ @viewMode = 0
177
+ @showMode()
178
+ $(document).off('mousedown', @hide) if !@isInput
179
+
180
+ @setValue()
181
+ @element.trigger
182
+ type: 'hide'
183
+ date: @date
184
+
185
+ setValue: ->
186
+ formated = DateTools.formatDate(@date, @format)
187
+ if !@isInput
188
+ if @component
189
+ @element.find('input').prop('value', formated)
190
+ @element.data('date', formated)
191
+ else
192
+ @element.prop('value', formated)
193
+
194
+ place: ->
195
+ offset = if @component then @component.offset() else @element.offset()
196
+ @picker.css
197
+ top: offset.top + @height
198
+ left: offset.left
199
+
200
+ update: ->
201
+ @date = DateTools.parseDate(
202
+ if @isInput then this.element.prop('value') else this.element.data('date'),
203
+ @format
204
+ )
205
+
206
+ @viewDate = new Date(@date)
207
+ @fill()
208
+
209
+ fillDow: ->
210
+ dowCnt = @weekStart
211
+ html = ['<tr>']
212
+ while dowCnt < @weekStart + 7
213
+ html.push '<th class="dow">'
214
+ html.push Locales[@locale].dates.daysMin[(dowCnt++)%7]
215
+ html.push '</th>'
216
+ html.push '</tr>'
217
+
218
+ @picker.find('.datepicker-days thead').append(html.join(''))
219
+
220
+ fillMonths: ->
221
+ html = []
222
+ i = 0
223
+ while i < 12
224
+ html.push '<span class="month">'
225
+ html.push Locales[@locale].dates.monthsShort[i++]
226
+ html.push '</span>'
227
+
228
+ @picker.find('.datepicker-months td').append(html.join(''))
229
+
230
+ fill: ->
231
+ d = new Date(@viewDate)
232
+ year = d.getFullYear()
233
+ month = d.getMonth()
234
+ currentDate = @date.valueOf()
235
+
236
+ @picker.find('.datepicker-days th:eq(1)').text(Locales[@locale].dates.months[month]+' '+year)
237
+ prevMonth = new Date(year, month-1, 28,0,0,0,0)
238
+ day = DateTools.getDaysInMonth(prevMonth.getFullYear(), prevMonth.getMonth())
239
+ prevMonth.setDate(day)
240
+ prevMonth.setDate(day - (prevMonth.getDay() - this.weekStart + 7)%7)
241
+ nextMonth = new Date(prevMonth);
242
+ nextMonth.setDate(nextMonth.getDate() + 42)
243
+ nextMonth = nextMonth.valueOf()
244
+ html = [];
245
+
246
+ while prevMonth.valueOf() < nextMonth
247
+ html.push '<tr>' if prevMonth.getDay() == this.weekStart
248
+
249
+ clsName = '';
250
+ if prevMonth.getMonth() < month
251
+ clsName += ' old'
252
+ else if prevMonth.getMonth() > month
253
+ clsName += ' new'
254
+
255
+ if prevMonth.valueOf() == currentDate
256
+ clsName += ' active'
257
+
258
+ html.push "<td class='day#{clsName}'>#{prevMonth.getDate()}</td>"
259
+ html.push '</tr>' if prevMonth.getDay() == @weekEnd
260
+
261
+ prevMonth.setDate(prevMonth.getDate()+1)
262
+
263
+
264
+ @picker.find('.datepicker-days tbody').empty().append(html.join(''))
265
+ currentYear = this.date.getFullYear()
266
+
267
+ months = @picker.find('.datepicker-months').find('th:eq(1)').text(year).end().find('span').removeClass('active')
268
+ months.eq(this.date.getMonth()).addClass('active') if currentYear == year
269
+
270
+ html = '';
271
+ year = parseInt(year/10, 10) * 10
272
+ yearCont = @picker.find('.datepicker-years').find('th:eq(1)').text(year + '-' + (year + 9)).end().find('td')
273
+ year -= 1;
274
+ for i in [-1...11]
275
+ html += '<span class="year'+(i == -1 || if i == 10 then ' old' else '')+(if currentYear == year then ' active' else '')+'">'+year+'</span>'
276
+ year += 1;
277
+ yearCont.html html
278
+
279
+ click: (e)->
280
+ e.stopPropagation()
281
+ e.preventDefault()
282
+ target = $(e.target).closest('span, td, th')
283
+ if target.length == 1
284
+ switch target[0].nodeName.toLowerCase()
285
+ when 'th'
286
+ switch target[0].className
287
+ when 'switch'
288
+ @showMode(1)
289
+ when 'prev', 'next'
290
+ @viewDate['set'+DateTools.modes[this.viewMode].navFnc].call(
291
+ @viewDate,
292
+ @viewDate['get'+DateTools.modes[this.viewMode].navFnc].call(this.viewDate) +
293
+ DateTools.modes[this.viewMode].navStep * (if target[0].className == 'prev' then -1 else 1))
294
+ @fill()
295
+ when 'span'
296
+ if target.is('.month')
297
+ month = target.parent().find('span').index(target)
298
+ @viewDate.setMonth(month)
299
+ else
300
+ year = parseInt(target.text(), 10) || 0
301
+ @viewDate.setFullYear(year)
302
+ @showMode(-1)
303
+ @fill()
304
+ when 'td'
305
+ if target.is('.day')
306
+ day = parseInt(target.text(), 10) || 1
307
+ month = this.viewDate.getMonth()
308
+ if target.is('.old')
309
+ month -= 1
310
+ else if target.is('.new')
311
+ month += 1
312
+
313
+ year = this.viewDate.getFullYear()
314
+ @date = new Date(year, month, day,0,0,0,0);
315
+ @viewDate = new Date(year, month, day,0,0,0,0);
316
+ @fill()
317
+ @setValue()
318
+ @element.trigger {
319
+ type: 'changeDate'
320
+ date: @date
321
+ }
322
+
323
+ mousedown: (e)->
324
+ e.stopPropagation()
325
+ e.preventDefault()
326
+
327
+ showMode: (dir)->
328
+ @viewMode = Math.max(0, Math.min(2, this.viewMode + dir)) if dir
329
+ @picker.find('>div').hide().filter('.datepicker-'+DateTools.modes[this.viewMode].clsName).show()
330
+
331
+ nativePicker = false
332
+
333
+ convertToNative = ($input, options)->
334
+ value = $input.attr('value')
335
+ $input.prop("type", "date")
336
+ if value && value.length > 0
337
+ locale = options.locale || $input.data('date-locale') || DateTools.getLocale()
338
+ format = DateTools.parseFormat(options.format || $input.data('date-format') || Locales[locale].dates.format);
339
+ date = DateTools.parseDate(value, format)
340
+ value = DateTools.formatDate(date, {
341
+ separator: '-'
342
+ parts: ["yyyy", "mm", "dd"]
343
+ })
344
+ $input.prop('value', value)
345
+
346
+
347
+ $.fn.datepicker = (option) ->
348
+ @each ->
349
+ $this = $(this)
350
+ data = $this.data('datepicker')
351
+ options = typeof option == 'object' && option
352
+ if nativePicker
353
+ convertToNative($this, options)
354
+ else
355
+ if !data
356
+ $this.data('datepicker', (data = new Datepicker(this, $.extend({}, $.fn.datepicker.defaults,options))))
357
+ data[option]() if typeof option == 'string'
358
+
359
+ $.fn.datepicker.defaults = { }
360
+ $.fn.datepicker.Constructor = Datepicker
361
+
362
+ $ ->
363
+ input = document.createElement("input")
364
+ input.setAttribute("type", "date")
365
+ # Chrome has ugly native date picker so we show ours
366
+ nativePicker = input.type == "date" && !navigator.userAgent.match(/chrome/i)
367
+
368
+ $("input[data-widget=datepicker]").datepicker()
369
+