event_cal 1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/MIT-LICENSE +20 -0
- data/Rakefile +21 -0
- data/app/views/event_calendar/_calendar.html.haml +9 -0
- data/app/views/event_calendar/_date.html.haml +10 -0
- data/app/views/event_calendar/_event_details.html.haml +4 -0
- data/lib/event_calendar/calendar.rb +50 -0
- data/lib/event_calendar/calendar_helper.rb +45 -0
- data/lib/event_calendar/engine.rb +15 -0
- data/lib/event_calendar/event.rb +16 -0
- data/lib/event_calendar/version.rb +3 -0
- data/lib/event_calendar.rb +4 -0
- data/lib/tasks/event_calendar_tasks.rake +4 -0
- data/vendor/assets/images/calendar_next.png +0 -0
- data/vendor/assets/images/calendar_prev.png +0 -0
- data/vendor/assets/images/icon_config.png +0 -0
- data/vendor/assets/javascripts/calendarApplication.js.coffee +11 -0
- data/vendor/assets/javascripts/controllers/calendarDatesController.js.coffee +32 -0
- data/vendor/assets/javascripts/controllers/calendarEventsController.js.coffee +19 -0
- data/vendor/assets/javascripts/event_calendar.js +1117 -0
- data/vendor/assets/javascripts/event_calendar_no_libs.js +191 -0
- data/vendor/assets/javascripts/lib/moment.js +1 -0
- data/vendor/assets/javascripts/lib/spine.js.coffee +535 -0
- data/vendor/assets/javascripts/lib/spinelib/ajax.js.coffee +223 -0
- data/vendor/assets/javascripts/lib/spinelib/list.js.coffee +43 -0
- data/vendor/assets/javascripts/lib/spinelib/local.js.coffee +16 -0
- data/vendor/assets/javascripts/lib/spinelib/manager.js.coffee +83 -0
- data/vendor/assets/javascripts/lib/spinelib/relation.js.coffee +144 -0
- data/vendor/assets/javascripts/lib/spinelib/route.js.coffee +151 -0
- data/vendor/assets/javascripts/models/calendarDate.js.coffee +7 -0
- data/vendor/assets/javascripts/models/calendarEvent.js.coffee +11 -0
- data/vendor/assets/stylesheets/event_calendar.css.scss +251 -0
- metadata +274 -0
@@ -0,0 +1,535 @@
|
|
1
|
+
Events =
|
2
|
+
bind: (ev, callback) ->
|
3
|
+
evs = ev.split(' ')
|
4
|
+
calls = @hasOwnProperty('_callbacks') and @_callbacks or= {}
|
5
|
+
|
6
|
+
for name in evs
|
7
|
+
calls[name] or= []
|
8
|
+
calls[name].push(callback)
|
9
|
+
this
|
10
|
+
|
11
|
+
one: (ev, callback) ->
|
12
|
+
@bind ev, ->
|
13
|
+
@unbind(ev, arguments.callee)
|
14
|
+
callback.apply(this, arguments)
|
15
|
+
|
16
|
+
trigger: (args...) ->
|
17
|
+
ev = args.shift()
|
18
|
+
|
19
|
+
list = @hasOwnProperty('_callbacks') and @_callbacks?[ev]
|
20
|
+
return unless list
|
21
|
+
|
22
|
+
for callback in list
|
23
|
+
if callback.apply(this, args) is false
|
24
|
+
break
|
25
|
+
true
|
26
|
+
|
27
|
+
unbind: (ev, callback) ->
|
28
|
+
unless ev
|
29
|
+
@_callbacks = {}
|
30
|
+
return this
|
31
|
+
|
32
|
+
list = @_callbacks?[ev]
|
33
|
+
return this unless list
|
34
|
+
|
35
|
+
unless callback
|
36
|
+
delete @_callbacks[ev]
|
37
|
+
return this
|
38
|
+
|
39
|
+
for cb, i in list when cb is callback
|
40
|
+
list = list.slice()
|
41
|
+
list.splice(i, 1)
|
42
|
+
@_callbacks[ev] = list
|
43
|
+
break
|
44
|
+
this
|
45
|
+
|
46
|
+
Log =
|
47
|
+
trace: true
|
48
|
+
|
49
|
+
logPrefix: '(App)'
|
50
|
+
|
51
|
+
log: (args...) ->
|
52
|
+
return unless @trace
|
53
|
+
if @logPrefix then args.unshift(@logPrefix)
|
54
|
+
console?.log?(args...)
|
55
|
+
this
|
56
|
+
|
57
|
+
moduleKeywords = ['included', 'extended']
|
58
|
+
|
59
|
+
class Module
|
60
|
+
@include: (obj) ->
|
61
|
+
throw new Error('include(obj) requires obj') unless obj
|
62
|
+
for key, value of obj when key not in moduleKeywords
|
63
|
+
@::[key] = value
|
64
|
+
obj.included?.apply(this)
|
65
|
+
this
|
66
|
+
|
67
|
+
@extend: (obj) ->
|
68
|
+
throw new Error('extend(obj) requires obj') unless obj
|
69
|
+
for key, value of obj when key not in moduleKeywords
|
70
|
+
@[key] = value
|
71
|
+
obj.extended?.apply(this)
|
72
|
+
this
|
73
|
+
|
74
|
+
@proxy: (func) ->
|
75
|
+
=> func.apply(this, arguments)
|
76
|
+
|
77
|
+
proxy: (func) ->
|
78
|
+
=> func.apply(this, arguments)
|
79
|
+
|
80
|
+
constructor: ->
|
81
|
+
@init?(arguments...)
|
82
|
+
|
83
|
+
class Model extends Module
|
84
|
+
@extend Events
|
85
|
+
|
86
|
+
@records: {}
|
87
|
+
@crecords: {}
|
88
|
+
@attributes: []
|
89
|
+
|
90
|
+
@configure: (name, attributes...) ->
|
91
|
+
@className = name
|
92
|
+
@records = {}
|
93
|
+
@crecords = {}
|
94
|
+
@attributes = attributes if attributes.length
|
95
|
+
@attributes and= makeArray(@attributes)
|
96
|
+
@attributes or= []
|
97
|
+
@unbind()
|
98
|
+
this
|
99
|
+
|
100
|
+
@toString: -> "#{@className}(#{@attributes.join(", ")})"
|
101
|
+
|
102
|
+
@find: (id) ->
|
103
|
+
record = @records[id]
|
104
|
+
if !record and ("#{id}").match(/c-\d+/)
|
105
|
+
return @findCID(id)
|
106
|
+
throw new Error('Unknown record') unless record
|
107
|
+
record.clone()
|
108
|
+
|
109
|
+
@findCID: (cid) ->
|
110
|
+
record = @crecords[cid]
|
111
|
+
throw new Error('Unknown record') unless record
|
112
|
+
record.clone()
|
113
|
+
|
114
|
+
@exists: (id) ->
|
115
|
+
try
|
116
|
+
return @find(id)
|
117
|
+
catch e
|
118
|
+
return false
|
119
|
+
|
120
|
+
@refresh: (values, options = {}) ->
|
121
|
+
if options.clear
|
122
|
+
@records = {}
|
123
|
+
@crecords = {}
|
124
|
+
|
125
|
+
records = @fromJSON(values)
|
126
|
+
records = [records] unless isArray(records)
|
127
|
+
|
128
|
+
for record in records
|
129
|
+
record.id or= record.cid
|
130
|
+
@records[record.id] = record
|
131
|
+
@crecords[record.cid] = record
|
132
|
+
|
133
|
+
@trigger('refresh', @cloneArray(records))
|
134
|
+
this
|
135
|
+
|
136
|
+
@select: (callback) ->
|
137
|
+
result = (record for id, record of @records when callback(record))
|
138
|
+
@cloneArray(result)
|
139
|
+
|
140
|
+
@findByAttribute: (name, value) ->
|
141
|
+
for id, record of @records
|
142
|
+
if record[name] is value
|
143
|
+
return record.clone()
|
144
|
+
null
|
145
|
+
|
146
|
+
@findAllByAttribute: (name, value) ->
|
147
|
+
@select (item) ->
|
148
|
+
item[name] is value
|
149
|
+
|
150
|
+
@each: (callback) ->
|
151
|
+
for key, value of @records
|
152
|
+
callback(value.clone())
|
153
|
+
|
154
|
+
@all: ->
|
155
|
+
@cloneArray(@recordsValues())
|
156
|
+
|
157
|
+
@first: ->
|
158
|
+
record = @recordsValues()[0]
|
159
|
+
record?.clone()
|
160
|
+
|
161
|
+
@last: ->
|
162
|
+
values = @recordsValues()
|
163
|
+
record = values[values.length - 1]
|
164
|
+
record?.clone()
|
165
|
+
|
166
|
+
@count: ->
|
167
|
+
@recordsValues().length
|
168
|
+
|
169
|
+
@deleteAll: ->
|
170
|
+
for key, value of @records
|
171
|
+
delete @records[key]
|
172
|
+
|
173
|
+
@destroyAll: ->
|
174
|
+
for key, value of @records
|
175
|
+
@records[key].destroy()
|
176
|
+
|
177
|
+
@update: (id, atts, options) ->
|
178
|
+
@find(id).updateAttributes(atts, options)
|
179
|
+
|
180
|
+
@create: (atts, options) ->
|
181
|
+
record = new @(atts)
|
182
|
+
record.save(options)
|
183
|
+
|
184
|
+
@destroy: (id, options) ->
|
185
|
+
@find(id).destroy(options)
|
186
|
+
|
187
|
+
@change: (callbackOrParams) ->
|
188
|
+
if typeof callbackOrParams is 'function'
|
189
|
+
@bind('change', callbackOrParams)
|
190
|
+
else
|
191
|
+
@trigger('change', callbackOrParams)
|
192
|
+
|
193
|
+
@fetch: (callbackOrParams) ->
|
194
|
+
if typeof callbackOrParams is 'function'
|
195
|
+
@bind('fetch', callbackOrParams)
|
196
|
+
else
|
197
|
+
@trigger('fetch', callbackOrParams)
|
198
|
+
|
199
|
+
@toJSON: ->
|
200
|
+
@recordsValues()
|
201
|
+
|
202
|
+
@fromJSON: (objects) ->
|
203
|
+
return unless objects
|
204
|
+
if typeof objects is 'string'
|
205
|
+
objects = JSON.parse(objects)
|
206
|
+
if isArray(objects)
|
207
|
+
(new @(value) for value in objects)
|
208
|
+
else
|
209
|
+
new @(objects)
|
210
|
+
|
211
|
+
@fromForm: ->
|
212
|
+
(new this).fromForm(arguments...)
|
213
|
+
|
214
|
+
# Private
|
215
|
+
|
216
|
+
@recordsValues: ->
|
217
|
+
result = []
|
218
|
+
for key, value of @records
|
219
|
+
result.push(value)
|
220
|
+
result
|
221
|
+
|
222
|
+
@cloneArray: (array) ->
|
223
|
+
(value.clone() for value in array)
|
224
|
+
|
225
|
+
@idCounter: 0
|
226
|
+
|
227
|
+
@uid: (prefix = '') ->
|
228
|
+
uid = prefix + @idCounter++
|
229
|
+
uid = @uid(prefix) if @exists(uid)
|
230
|
+
uid
|
231
|
+
|
232
|
+
# Instance
|
233
|
+
|
234
|
+
constructor: (atts) ->
|
235
|
+
super
|
236
|
+
@load atts if atts
|
237
|
+
@cid = @constructor.uid('c-')
|
238
|
+
|
239
|
+
isNew: ->
|
240
|
+
not @exists()
|
241
|
+
|
242
|
+
isValid: ->
|
243
|
+
not @validate()
|
244
|
+
|
245
|
+
validate: ->
|
246
|
+
|
247
|
+
load: (atts) ->
|
248
|
+
for key, value of atts
|
249
|
+
if typeof @[key] is 'function'
|
250
|
+
@[key](value)
|
251
|
+
else
|
252
|
+
@[key] = value
|
253
|
+
this
|
254
|
+
|
255
|
+
attributes: ->
|
256
|
+
result = {}
|
257
|
+
for key in @constructor.attributes when key of this
|
258
|
+
if typeof @[key] is 'function'
|
259
|
+
result[key] = @[key]()
|
260
|
+
else
|
261
|
+
result[key] = @[key]
|
262
|
+
result.id = @id if @id
|
263
|
+
result
|
264
|
+
|
265
|
+
eql: (rec) ->
|
266
|
+
!!(rec and rec.constructor is @constructor and
|
267
|
+
(rec.cid is @cid) or (rec.id and rec.id is @id))
|
268
|
+
|
269
|
+
save: (options = {}) ->
|
270
|
+
unless options.validate is false
|
271
|
+
error = @validate()
|
272
|
+
if error
|
273
|
+
@trigger('error', error)
|
274
|
+
return false
|
275
|
+
|
276
|
+
@trigger('beforeSave', options)
|
277
|
+
record = if @isNew() then @create(options) else @update(options)
|
278
|
+
@trigger('save', options)
|
279
|
+
record
|
280
|
+
|
281
|
+
updateAttribute: (name, value, options) ->
|
282
|
+
@[name] = value
|
283
|
+
@save(options)
|
284
|
+
|
285
|
+
updateAttributes: (atts, options) ->
|
286
|
+
@load(atts)
|
287
|
+
@save(options)
|
288
|
+
|
289
|
+
changeID: (id) ->
|
290
|
+
records = @constructor.records
|
291
|
+
records[id] = records[@id]
|
292
|
+
delete records[@id]
|
293
|
+
@id = id
|
294
|
+
@save()
|
295
|
+
|
296
|
+
destroy: (options = {}) ->
|
297
|
+
@trigger('beforeDestroy', options)
|
298
|
+
delete @constructor.records[@id]
|
299
|
+
delete @constructor.crecords[@cid]
|
300
|
+
@destroyed = true
|
301
|
+
@trigger('destroy', options)
|
302
|
+
@trigger('change', 'destroy', options)
|
303
|
+
@unbind()
|
304
|
+
this
|
305
|
+
|
306
|
+
dup: (newRecord) ->
|
307
|
+
result = new @constructor(@attributes())
|
308
|
+
if newRecord is false
|
309
|
+
result.cid = @cid
|
310
|
+
else
|
311
|
+
delete result.id
|
312
|
+
result
|
313
|
+
|
314
|
+
clone: ->
|
315
|
+
createObject(this)
|
316
|
+
|
317
|
+
reload: ->
|
318
|
+
return this if @isNew()
|
319
|
+
original = @constructor.find(@id)
|
320
|
+
@load(original.attributes())
|
321
|
+
original
|
322
|
+
|
323
|
+
toJSON: ->
|
324
|
+
@attributes()
|
325
|
+
|
326
|
+
toString: ->
|
327
|
+
"<#{@constructor.className} (#{JSON.stringify(this)})>"
|
328
|
+
|
329
|
+
fromForm: (form) ->
|
330
|
+
result = {}
|
331
|
+
for key in $(form).serializeArray()
|
332
|
+
result[key.name] = key.value
|
333
|
+
@load(result)
|
334
|
+
|
335
|
+
exists: ->
|
336
|
+
@id && @id of @constructor.records
|
337
|
+
|
338
|
+
# Private
|
339
|
+
|
340
|
+
update: (options) ->
|
341
|
+
@trigger('beforeUpdate', options)
|
342
|
+
records = @constructor.records
|
343
|
+
records[@id].load @attributes()
|
344
|
+
clone = records[@id].clone()
|
345
|
+
clone.trigger('update', options)
|
346
|
+
clone.trigger('change', 'update', options)
|
347
|
+
clone
|
348
|
+
|
349
|
+
create: (options) ->
|
350
|
+
@trigger('beforeCreate', options)
|
351
|
+
@id = @cid unless @id
|
352
|
+
|
353
|
+
record = @dup(false)
|
354
|
+
@constructor.records[@id] = record
|
355
|
+
@constructor.crecords[@cid] = record
|
356
|
+
|
357
|
+
clone = record.clone()
|
358
|
+
clone.trigger('create', options)
|
359
|
+
clone.trigger('change', 'create', options)
|
360
|
+
clone
|
361
|
+
|
362
|
+
bind: (events, callback) ->
|
363
|
+
@constructor.bind events, binder = (record) =>
|
364
|
+
if record && @eql(record)
|
365
|
+
callback.apply(this, arguments)
|
366
|
+
@constructor.bind 'unbind', unbinder = (record) =>
|
367
|
+
if record && @eql(record)
|
368
|
+
@constructor.unbind(events, binder)
|
369
|
+
@constructor.unbind('unbind', unbinder)
|
370
|
+
binder
|
371
|
+
|
372
|
+
one: (events, callback) ->
|
373
|
+
binder = @bind events, =>
|
374
|
+
@constructor.unbind(events, binder)
|
375
|
+
callback.apply(this, arguments)
|
376
|
+
|
377
|
+
trigger: (args...) ->
|
378
|
+
args.splice(1, 0, this)
|
379
|
+
@constructor.trigger(args...)
|
380
|
+
|
381
|
+
unbind: ->
|
382
|
+
@trigger('unbind')
|
383
|
+
|
384
|
+
class Controller extends Module
|
385
|
+
@include Events
|
386
|
+
@include Log
|
387
|
+
|
388
|
+
eventSplitter: /^(\S+)\s*(.*)$/
|
389
|
+
tag: 'div'
|
390
|
+
|
391
|
+
constructor: (options) ->
|
392
|
+
@options = options
|
393
|
+
|
394
|
+
for key, value of @options
|
395
|
+
@[key] = value
|
396
|
+
|
397
|
+
@el = document.createElement(@tag) unless @el
|
398
|
+
@el = $(@el)
|
399
|
+
@$el = @el
|
400
|
+
|
401
|
+
@el.addClass(@className) if @className
|
402
|
+
@el.attr(@attributes) if @attributes
|
403
|
+
|
404
|
+
@events = @constructor.events unless @events
|
405
|
+
@elements = @constructor.elements unless @elements
|
406
|
+
|
407
|
+
@delegateEvents(@events) if @events
|
408
|
+
@refreshElements() if @elements
|
409
|
+
|
410
|
+
super
|
411
|
+
|
412
|
+
release: =>
|
413
|
+
@trigger 'release'
|
414
|
+
@el.remove()
|
415
|
+
@unbind()
|
416
|
+
|
417
|
+
$: (selector) -> $(selector, @el)
|
418
|
+
|
419
|
+
delegateEvents: (events) ->
|
420
|
+
for key, method of events
|
421
|
+
|
422
|
+
if typeof(method) is 'function'
|
423
|
+
# Always return true from event handlers
|
424
|
+
method = do (method) => =>
|
425
|
+
method.apply(this, arguments)
|
426
|
+
true
|
427
|
+
else
|
428
|
+
unless @[method]
|
429
|
+
throw new Error("#{method} doesn't exist")
|
430
|
+
|
431
|
+
method = do (method) => =>
|
432
|
+
@[method].apply(this, arguments)
|
433
|
+
true
|
434
|
+
|
435
|
+
match = key.match(@eventSplitter)
|
436
|
+
eventName = match[1]
|
437
|
+
selector = match[2]
|
438
|
+
|
439
|
+
if selector is ''
|
440
|
+
@el.bind(eventName, method)
|
441
|
+
else
|
442
|
+
@el.delegate(selector, eventName, method)
|
443
|
+
|
444
|
+
refreshElements: ->
|
445
|
+
for key, value of @elements
|
446
|
+
@[value] = @$(key)
|
447
|
+
|
448
|
+
delay: (func, timeout) ->
|
449
|
+
setTimeout(@proxy(func), timeout || 0)
|
450
|
+
|
451
|
+
html: (element) ->
|
452
|
+
@el.html(element.el or element)
|
453
|
+
@refreshElements()
|
454
|
+
@el
|
455
|
+
|
456
|
+
append: (elements...) ->
|
457
|
+
elements = (e.el or e for e in elements)
|
458
|
+
@el.append(elements...)
|
459
|
+
@refreshElements()
|
460
|
+
@el
|
461
|
+
|
462
|
+
appendTo: (element) ->
|
463
|
+
@el.appendTo(element.el or element)
|
464
|
+
@refreshElements()
|
465
|
+
@el
|
466
|
+
|
467
|
+
prepend: (elements...) ->
|
468
|
+
elements = (e.el or e for e in elements)
|
469
|
+
@el.prepend(elements...)
|
470
|
+
@refreshElements()
|
471
|
+
@el
|
472
|
+
|
473
|
+
replace: (element) ->
|
474
|
+
[previous, @el] = [@el, $(element.el or element)]
|
475
|
+
previous.replaceWith(@el)
|
476
|
+
@delegateEvents(@events)
|
477
|
+
@refreshElements()
|
478
|
+
@el
|
479
|
+
|
480
|
+
# Utilities & Shims
|
481
|
+
|
482
|
+
$ = window?.jQuery or window?.Zepto or (element) -> element
|
483
|
+
|
484
|
+
createObject = Object.create or (o) ->
|
485
|
+
Func = ->
|
486
|
+
Func.prototype = o
|
487
|
+
new Func()
|
488
|
+
|
489
|
+
isArray = (value) ->
|
490
|
+
Object::toString.call(value) is '[object Array]'
|
491
|
+
|
492
|
+
isBlank = (value) ->
|
493
|
+
return true unless value
|
494
|
+
return false for key of value
|
495
|
+
true
|
496
|
+
|
497
|
+
makeArray = (args) ->
|
498
|
+
Array::slice.call(args, 0)
|
499
|
+
|
500
|
+
# Globals
|
501
|
+
|
502
|
+
Spine = @Spine = {}
|
503
|
+
module?.exports = Spine
|
504
|
+
|
505
|
+
Spine.version = '1.0.8'
|
506
|
+
Spine.isArray = isArray
|
507
|
+
Spine.isBlank = isBlank
|
508
|
+
Spine.$ = $
|
509
|
+
Spine.Events = Events
|
510
|
+
Spine.Log = Log
|
511
|
+
Spine.Module = Module
|
512
|
+
Spine.Controller = Controller
|
513
|
+
Spine.Model = Model
|
514
|
+
|
515
|
+
# Global events
|
516
|
+
|
517
|
+
Module.extend.call(Spine, Events)
|
518
|
+
|
519
|
+
# JavaScript compatability
|
520
|
+
|
521
|
+
Module.create = Module.sub =
|
522
|
+
Controller.create = Controller.sub =
|
523
|
+
Model.sub = (instances, statics) ->
|
524
|
+
class Result extends this
|
525
|
+
Result.include(instances) if instances
|
526
|
+
Result.extend(statics) if statics
|
527
|
+
Result.unbind?()
|
528
|
+
Result
|
529
|
+
|
530
|
+
Model.setup = (name, attributes = []) ->
|
531
|
+
class Instance extends this
|
532
|
+
Instance.configure(name, attributes...)
|
533
|
+
Instance
|
534
|
+
|
535
|
+
Spine.Class = Module
|