pinkman 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
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
+