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.
Files changed (32) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/Rakefile +21 -0
  3. data/app/views/event_calendar/_calendar.html.haml +9 -0
  4. data/app/views/event_calendar/_date.html.haml +10 -0
  5. data/app/views/event_calendar/_event_details.html.haml +4 -0
  6. data/lib/event_calendar/calendar.rb +50 -0
  7. data/lib/event_calendar/calendar_helper.rb +45 -0
  8. data/lib/event_calendar/engine.rb +15 -0
  9. data/lib/event_calendar/event.rb +16 -0
  10. data/lib/event_calendar/version.rb +3 -0
  11. data/lib/event_calendar.rb +4 -0
  12. data/lib/tasks/event_calendar_tasks.rake +4 -0
  13. data/vendor/assets/images/calendar_next.png +0 -0
  14. data/vendor/assets/images/calendar_prev.png +0 -0
  15. data/vendor/assets/images/icon_config.png +0 -0
  16. data/vendor/assets/javascripts/calendarApplication.js.coffee +11 -0
  17. data/vendor/assets/javascripts/controllers/calendarDatesController.js.coffee +32 -0
  18. data/vendor/assets/javascripts/controllers/calendarEventsController.js.coffee +19 -0
  19. data/vendor/assets/javascripts/event_calendar.js +1117 -0
  20. data/vendor/assets/javascripts/event_calendar_no_libs.js +191 -0
  21. data/vendor/assets/javascripts/lib/moment.js +1 -0
  22. data/vendor/assets/javascripts/lib/spine.js.coffee +535 -0
  23. data/vendor/assets/javascripts/lib/spinelib/ajax.js.coffee +223 -0
  24. data/vendor/assets/javascripts/lib/spinelib/list.js.coffee +43 -0
  25. data/vendor/assets/javascripts/lib/spinelib/local.js.coffee +16 -0
  26. data/vendor/assets/javascripts/lib/spinelib/manager.js.coffee +83 -0
  27. data/vendor/assets/javascripts/lib/spinelib/relation.js.coffee +144 -0
  28. data/vendor/assets/javascripts/lib/spinelib/route.js.coffee +151 -0
  29. data/vendor/assets/javascripts/models/calendarDate.js.coffee +7 -0
  30. data/vendor/assets/javascripts/models/calendarEvent.js.coffee +11 -0
  31. data/vendor/assets/stylesheets/event_calendar.css.scss +251 -0
  32. 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