pinkman 0.9.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 (46) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +5 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +41 -0
  8. data/Rakefile +28 -0
  9. data/app/assets/javascripts/pinkman.js +10 -0
  10. data/app/assets/javascripts/pinkman_base/ajax.coffee +90 -0
  11. data/app/assets/javascripts/pinkman_base/collection.coffee +387 -0
  12. data/app/assets/javascripts/pinkman_base/common.coffee +56 -0
  13. data/app/assets/javascripts/pinkman_base/controller.coffee +164 -0
  14. data/app/assets/javascripts/pinkman_base/glue.coffee +15 -0
  15. data/app/assets/javascripts/pinkman_base/handlebars.js +4608 -0
  16. data/app/assets/javascripts/pinkman_base/hogan.js +576 -0
  17. data/app/assets/javascripts/pinkman_base/markup.js +483 -0
  18. data/app/assets/javascripts/pinkman_base/mixins.coffee +37 -0
  19. data/app/assets/javascripts/pinkman_base/object.js.coffee.erb +195 -0
  20. data/app/assets/javascripts/pinkman_base/pinkman.coffee +131 -0
  21. data/app/assets/javascripts/pinkman_base/render.coffee.erb +80 -0
  22. data/app/assets/javascripts/pinkman_base/tools.coffee +4 -0
  23. data/app/helpers/pinkman_helper.rb +48 -0
  24. data/bin/console +14 -0
  25. data/bin/setup +8 -0
  26. data/lib/generators/pinkman/USAGE +16 -0
  27. data/lib/generators/pinkman/api_generator.rb +60 -0
  28. data/lib/generators/pinkman/install_generator.rb +25 -0
  29. data/lib/generators/pinkman/model_generator.rb +41 -0
  30. data/lib/generators/pinkman/resource_generator.rb +15 -0
  31. data/lib/generators/pinkman/serializer_generator.rb +33 -0
  32. data/lib/generators/pinkman/templates/api.rb.erb +87 -0
  33. data/lib/generators/pinkman/templates/api_controller.rb +2 -0
  34. data/lib/generators/pinkman/templates/collection.js.erb +5 -0
  35. data/lib/generators/pinkman/templates/object.js.erb +3 -0
  36. data/lib/generators/pinkman/templates/serializer.rb.erb +15 -0
  37. data/lib/pinkman.rb +57 -0
  38. data/lib/pinkman/serializer.rb +6 -0
  39. data/lib/pinkman/serializer/base.rb +42 -0
  40. data/lib/pinkman/serializer/scope.rb +48 -0
  41. data/lib/pinkman/version.rb +3 -0
  42. data/pinkman.gemspec +46 -0
  43. data/public/javascripts/pinkman.min.js +1 -0
  44. data/public/jquery.pinkman.min.js +0 -0
  45. data/public/pinkman.min.js +29 -0
  46. metadata +242 -0
@@ -0,0 +1,37 @@
1
+ window.Pinkman.mixin = (name,mix) ->
2
+ if name? and typeof name == 'string' and mix? and typeof mix == 'object'
3
+ Pinkman.mixins = new Pinkman.collection unless Pinkman.mixins?
4
+ mixin = new Pinkman.object
5
+ mixin.set 'mix', mix
6
+ mixin.set 'name',name
7
+ Pinkman.mixins.push mixin
8
+
9
+ window.Pinkman.mixit = (c,name) ->
10
+ mixin = Pinkman.mixins.getBy('name',name)
11
+ if mixin?
12
+ for n, method of mixin.mix
13
+ method['super'] = c.prototype[n]
14
+ c.prototype[n] = method
15
+ return(true)
16
+ else
17
+ false
18
+
19
+
20
+ # --- Mixins - Usage --- #
21
+
22
+ # Pinkman.mixin 'shitty',
23
+ # shit: (a) ->
24
+ # "#{a} is shit"
25
+
26
+
27
+ # class window.Foo
28
+ # Pinkman.mixit this, 'shitty'
29
+
30
+ # class window.Bar extends Pinkman.object
31
+ # @mixit 'shitty'
32
+
33
+ # a = new Foo
34
+ # a.shit(abc) -> 'abc is shit'
35
+
36
+ # a = new Bar
37
+ # a.shit(abc) -> 'abc is shit'
@@ -0,0 +1,195 @@
1
+ class window.PinkmanObject extends window.PinkmanCommon
2
+
3
+ @pinkmanType: 'object'
4
+
5
+ constructor: (attributesObject) ->
6
+
7
+ @isPink = true
8
+ @isObject = true
9
+ @pinkmanType = 'object'
10
+
11
+ @collections = new PinkmanCollection
12
+ @pinkey = Pinkman.all.length
13
+
14
+ Pinkman.objects.push(this)
15
+ Pinkman.all.push(this)
16
+
17
+ @initialize(attributesObject)
18
+
19
+ initialize: (attributesObject) ->
20
+ if typeof attributesObject == 'object'
21
+ for key, value of attributesObject
22
+ @set(key,value) if PinkmanObject.privateAttributes.indexOf(key) is -1
23
+
24
+ # Desc: assign attributes from a pure javascript object
25
+ # Usage: a.assign( {attribute: value} )
26
+ assign: (obj) ->
27
+ if typeof obj == 'object'
28
+ for k,v of obj
29
+ if typeof v == 'object' and this[k]? and this[k].isPink? and not v.isPink
30
+ this[k].assign(v)
31
+ else
32
+ this.set(k,v)
33
+ return true
34
+ else
35
+ return false
36
+
37
+ # Desc: returns a javascript object version of this
38
+ # Usage: a.attributes() #-> {key: value, key: value, ...}
39
+ attributes: () ->
40
+ a = new Object
41
+ for k,v of this
42
+ if PinkmanObject.privateAttributes.indexOf(k) == -1 and typeof v != 'function'
43
+ if v.isPink
44
+ a[k] = v.attributes()
45
+ else
46
+ a[k] = v
47
+ return a
48
+
49
+ # Desc: returns a array of attributes keys
50
+ # Usage:
51
+ # a.set('a','b'); a.set('x',value)
52
+ # a.attributesKeys() #-> ['a','x']
53
+ attributesKeys: ->
54
+ Object.keys(@attributes())
55
+
56
+ # Desc: Alias for attributesKeys
57
+ keys: () ->
58
+ @attributesKeys()
59
+
60
+ toString: () ->
61
+ array = []
62
+ array.push("(#{@className()})")
63
+ for a in @attributesKeys()
64
+ array.push "#{a}: #{this[a]};"
65
+ array.join(" ")
66
+
67
+ # --- Collection related functions --- #
68
+
69
+ # Desc: return the next obj (after this) in a collection
70
+ # Try to guess the collection if not provided
71
+ next: (collection='') ->
72
+ if collection.isPink and collection.pinkmanType == 'collection'
73
+ collection.next(this)
74
+ else if Pinkman.isNumber(collection)
75
+ c = @collections.get(collection)
76
+ c.next(this) if c?
77
+ else if not collection? or collection==''
78
+ @collections.first().next(this) if @collections.any()
79
+
80
+ # Desc: return the previous obj (before this) in a collection
81
+ # Try to guess the collection if not provided
82
+ prev: (collection='') ->
83
+ if collection.isPink and collection.pinkmanType == 'collection'
84
+ collection.prev(this)
85
+ else if Pinkman.isNumber(collection)
86
+ c = @collections.get(collection)
87
+ c.prev(this) if c?
88
+ else if not collection? or collection==''
89
+ @collections.first().prev(this) if @collections.any()
90
+
91
+ # Desc: remove this object from all collections
92
+ clearCollections: ->
93
+ c.remove(this) for c in @collections.collection
94
+
95
+ # alias for clearCollections
96
+ removeFromCollections: ->
97
+ @clearCollections()
98
+
99
+ # alias for clearCollections
100
+ removeFromAllCollections: ->
101
+ @clearCollections()
102
+
103
+ # alias for clearCollections
104
+ removeAllCollections: ->
105
+ @clearCollections()
106
+
107
+ # --- Error related --- #
108
+
109
+ # Desc: return first error message
110
+ firstError: ->
111
+ if @errors?
112
+ attr = Object.keys(@errors)[0]
113
+ "#{attr} #{@errors[attr][0]}"
114
+
115
+ # --- Ajax --- #
116
+
117
+ @find: (id, callback='') ->
118
+ obj = new this
119
+ Pinkman.ajax.get
120
+ url: obj.api() + id,
121
+ complete: (response) ->
122
+ obj.assign(response)
123
+ if obj.error? or obj.errors?
124
+ throw new Error(obj.firstError())
125
+ return false
126
+ else
127
+ callback(obj) if callback? and typeof callback == 'function'
128
+ return(obj)
129
+
130
+ create: (callback='') ->
131
+ unless @id?
132
+ Pinkman.ajax.post
133
+ url: @api()
134
+ data: { pink_obj: @attributes() }
135
+ complete: (response) =>
136
+ @assign(response)
137
+ delete @errors unless response.errors?
138
+ callback(this) if callback? and typeof callback=='function'
139
+ return(this)
140
+
141
+ update: (callback='') ->
142
+ console.log this
143
+ if @id?
144
+ Pinkman.ajax.patch
145
+ url: @api() + @id
146
+ data: { pink_obj: @attributes() }
147
+ complete: (response) =>
148
+ @assign(response)
149
+ delete @errors unless response.errors?
150
+ callback(this) if callback? and typeof callback=='function'
151
+ return(this)
152
+
153
+ reload: (callback) ->
154
+ Pinkman.ajax.get
155
+ url: @api() + @id,
156
+ complete: (response) =>
157
+ @assign(response)
158
+ if @error? or @errors?
159
+ throw new Error(@firstError())
160
+ return false
161
+ else
162
+ callback(this) if callback? and typeof callback == 'function'
163
+ return(this)
164
+
165
+ updateAttributes: (obj) ->
166
+ if this.assign(obj)
167
+ this.save (obj) ->
168
+ return(obj)
169
+ else
170
+ return false
171
+
172
+
173
+ save: (callback='') ->
174
+ if @id? and @id!='' then @update(callback) else @create(callback)
175
+
176
+
177
+ destroy: (callback='') ->
178
+ if @id?
179
+ Pinkman.ajax.delete
180
+ url: @api() + @id
181
+ complete: (response) =>
182
+ @assign(response)
183
+ delete @errors unless response.errors?
184
+ if @errors?
185
+ throw new Error(@firstError())
186
+ return(false)
187
+ else
188
+ @id = null
189
+ @removeFromAllCollections()
190
+ callback(this) if typeof callback=='function'
191
+ return(this)
192
+ else
193
+ return(false)
194
+
195
+ window.Pinkman.object = window.PinkmanObject
@@ -0,0 +1,131 @@
1
+ class window.Pinkman
2
+
3
+ # --- objects and collections manipulation
4
+
5
+ @collections = []
6
+ @objects = []
7
+ @all = []
8
+
9
+ @get: (pinkey) ->
10
+ this.all[pinkey]
11
+
12
+ @count: () ->
13
+ @all.length
14
+
15
+ # --- predicate
16
+
17
+ @isNumber: (n) ->
18
+ !isNaN(parseFloat(n)) && isFinite(n)
19
+
20
+ @isArray: (array) ->
21
+ array? and array.constructor is Array
22
+
23
+ @isString: (str) ->
24
+ str? and typeof str == 'string'
25
+
26
+ # --- tools and facilities
27
+
28
+ @doAfter: (ds, callback, timer = '_pinkman_doAfter') ->
29
+ window[timer] = window.setTimeout(callback, ds*100)
30
+
31
+ @clearTimeout: (timerName = '_pinkman_doAfter') ->
32
+ window.clearTimeout(window[timerName])
33
+
34
+ @defineGlobalVar: (variable,value) ->
35
+ window[variable] = value
36
+
37
+ @onlyOnce: (f,args...) ->
38
+ if typeof f == 'function'
39
+
40
+ func = new Object
41
+ func.f = f.toString()
42
+ func.args = args
43
+
44
+ if @calledFunctions.indexOf(func) == -1
45
+ @calledFunctions.push(func)
46
+ f(args...)
47
+
48
+ @calledFunctions = []
49
+
50
+ # --- Ajax
51
+
52
+ @ajax:
53
+
54
+ request: (options) ->
55
+ if options.url?
56
+ ajax = jQuery.ajax options.url,
57
+ beforeSend: (xhr) ->
58
+ xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'))
59
+ type: options.type
60
+ dataType: 'json'
61
+ data: options.data
62
+ ajax.done (response) =>
63
+ if response.errors?
64
+ options.error(this) if options.error? and typeof options.error == 'function'
65
+ return(false)
66
+ else
67
+ options.success(response) if options.success? and typeof options.success == 'function'
68
+ options.complete(response) if options.complete? and typeof options.complete == 'function'
69
+ return(true)
70
+ else
71
+ return false
72
+
73
+ get: (options) ->
74
+ options.type = 'GET'
75
+ @request(options)
76
+
77
+ post: (options) ->
78
+ options.type = 'POST'
79
+ @request(options)
80
+
81
+ put: (options) ->
82
+ options.type = 'PUT'
83
+ @request(options)
84
+
85
+ patch: (options) ->
86
+ options.type = 'PATCH'
87
+ @request(options)
88
+
89
+ delete: (options) ->
90
+ options.type = 'DELETE'
91
+ @request(options)
92
+
93
+ file: (options) ->
94
+ if options.url?
95
+ ajax = jQuery.ajax options.url,
96
+ beforeSend: (xhr) ->
97
+ xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'))
98
+ xhr: ->
99
+ myXhr = $.ajaxSettings.xhr()
100
+ myXhr.upload.addEventListener 'progress', (e) ->
101
+ if e.lengthComputable
102
+ options.progress e.loaded/e.total if options.progress?
103
+ , false
104
+ myXhr.addEventListener 'progress', (e) ->
105
+ if e.lengthComputable
106
+ options.progress e.loaded/e.total if options.progress?
107
+ , false
108
+ return myXhr
109
+ type: "POST"
110
+ dataType: 'json'
111
+ data: options.data
112
+ processData: false
113
+ contentType: false
114
+ ajax.done (response) =>
115
+ if response? and response.errors?
116
+ options.error(this) if options.error? and typeof options.error == 'function'
117
+ return false
118
+ else
119
+ options.success(response) if options.success? and typeof options.success == 'function'
120
+ options.complete(response) if options.complete? and typeof options.complete == 'function'
121
+ return this
122
+ else
123
+ return false
124
+
125
+ upload: (options...) ->
126
+ @file(options...)
127
+
128
+ $(document).ready ->
129
+ unless Pinkman.pathname?
130
+ Pinkman.pathname = window.location.pathname
131
+ Pinkman.pathname = Pinkman.pathname + '/' if Pinkman.pathname.charAt([Pinkman.pathname.length] - 1) != "/"
@@ -0,0 +1,80 @@
1
+ PinkmanCollection.prototype.renderQueue = new PinkmanCollection
2
+ PinkmanObject.prototype.renderQueue = new PinkmanCollection
3
+
4
+ Pinkman.templates = new Pinkman.collection
5
+
6
+ Pinkman.template_engine = '<%= Pinkman.configuration.js_template_engine %>'
7
+
8
+ Pinkman.template_engines =
9
+ handlebars: (options) ->
10
+ if options? and options.template? and $('#' + options.template).length
11
+ if Pinkman.templates.include(template: options.template, engine: Pinkman.template_engine)
12
+ template = Pinkman.templates.get(template: options.template, engine: Pinkman.template_engine)
13
+ else
14
+ template = new Pinkman.object(template: options.template, engine: Pinkman.template_engine)
15
+ template.handlebars = Handlebars.compile $('#' + options.template).html()
16
+ Pinkman.templates.push(template)
17
+
18
+ options.object = options.context if options.context?
19
+ content = template.handlebars(options.object)
20
+
21
+
22
+ if options.target?
23
+ $('#' + options.target).html(content)
24
+ $('#' + options.target).attr('data-pinkey',options.object.pinkey) if options.object? and typeof options.object == 'object' and options.object.isPink
25
+
26
+ options.callback(options.object,content) if options.callback? and typeof options.callback == 'function'
27
+ return(content)
28
+
29
+ hogan: (options) ->
30
+ if options? and options.template? and $('#' + options.template).length
31
+ if Pinkman.templates.include(template: options.template, engine: Pinkman.template_engine)
32
+ template = Pinkman.templates.get(template: options.template, engine: Pinkman.template_engine)
33
+ else
34
+ template = new Pinkman.object(template: options.template, engine: Pinkman.template_engine)
35
+ template.hogan = Hogan.compile $('#' + options.template).html()
36
+ Pinkman.templates.push(template)
37
+
38
+ options.object = options.context if options.context?
39
+ content = template.hogan.render(options.object)
40
+
41
+ if options.target?
42
+ $('#' + options.target).html(content)
43
+ $('#' + options.target).attr('data-pinkey',options.object.pinkey) if options.object? and typeof options.object == 'object' and options.object.isPink
44
+
45
+ options.callback(options.object,content) if options.callback? and typeof options.callback == 'function'
46
+ return(content)
47
+
48
+ markup: (options) ->
49
+ if options? and options.template? and $('#' + options.template).length
50
+ if Pinkman.templates.include(template: options.template, engine: Pinkman.template_engine)
51
+ template = Pinkman.templates.get(template: options.template, engine: Pinkman.template_engine)
52
+ else
53
+ template = new Pinkman.object(template: options.template, engine: Pinkman.template_engine)
54
+ template.markup = (args...) -> Mark.up(args...)
55
+ Pinkman.templates.push(template)
56
+
57
+ options.object = options.context if options.context?
58
+ content = template.markup($('#'+options.template).html(),options.object)
59
+
60
+ if options.target?
61
+ $('#' + options.target).html(content)
62
+ $('#' + options.target).attr('data-pinkey',options.object.pinkey) if options.object? and typeof options.object == 'object' and options.object.isPink
63
+
64
+ options.callback(options.object,content) if options.callback? and typeof options.callback == 'function'
65
+ return(content)
66
+
67
+ Pinkman.render = (options) ->
68
+ options.reRender = true unless options.reRender? and options.reRender == false
69
+ options.collectionReRender = true unless options.collectionReRender? and options.collectionReRender == false
70
+
71
+ engine = Pinkman.template_engines[Pinkman.template_engine]
72
+ content = engine(options)
73
+ options.object.renderQueue.directPush(options) if options.reRender and options.object? and options.object.isPink
74
+
75
+ Pinkman.reRender = (object) ->
76
+ engine = Pinkman.template_engines[Pinkman.template_engine]
77
+ engine(options) for options in object.renderQueue.collection
78
+ Pinkman.reRender(collection) for collection in object.collections.collection if object.collections? and options.collectionReRender
79
+ object.renderQueue.any()
80
+
@@ -0,0 +1,4 @@
1
+ window.sleep = (s,callback) ->
2
+ ms = s*1000
3
+ window['_sleeping'] = setTimeout(callback,ms)
4
+