chr 0.1.5 → 0.2.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 (41) hide show
  1. checksums.yaml +4 -4
  2. data/Gruntfile.coffee +6 -3
  3. data/LICENSE.md +1 -1
  4. data/README.md +286 -7
  5. data/app/assets/javascripts/chr-dist.js +1031 -580
  6. data/app/assets/javascripts/chr.coffee +7 -4
  7. data/app/assets/javascripts/chr/core/chr.coffee +88 -37
  8. data/app/assets/javascripts/chr/core/item.coffee +57 -35
  9. data/app/assets/javascripts/chr/core/{list-scroll.coffee → list-pagination.coffee} +6 -3
  10. data/app/assets/javascripts/chr/core/list-reorder.coffee +3 -3
  11. data/app/assets/javascripts/chr/core/list-search.coffee +20 -11
  12. data/app/assets/javascripts/chr/core/list.coffee +163 -89
  13. data/app/assets/javascripts/chr/core/module.coffee +75 -35
  14. data/app/assets/javascripts/chr/core/view.coffee +117 -61
  15. data/app/assets/javascripts/chr/store/{store.coffee → _array-store.coffee} +53 -106
  16. data/app/assets/javascripts/chr/store/_object-store.coffee +28 -0
  17. data/app/assets/javascripts/chr/store/mongosteen-array-store.coffee +199 -0
  18. data/app/assets/javascripts/chr/store/mongosteen-object-store.coffee +52 -0
  19. data/app/assets/javascripts/chr/store/rest-array-store.coffee +142 -0
  20. data/app/assets/javascripts/chr/store/rest-object-store.coffee +79 -0
  21. data/app/assets/stylesheets/core/_list.scss +20 -25
  22. data/app/assets/stylesheets/core/_main.scss +3 -4
  23. data/app/assets/stylesheets/core/_mixins.scss +33 -2
  24. data/app/assets/stylesheets/core/_responsive.scss +30 -9
  25. data/app/assets/stylesheets/form/_input_checkbox.scss +18 -14
  26. data/bower.json +3 -2
  27. data/chr.gemspec +1 -1
  28. data/docs/assets.md +0 -0
  29. data/docs/basics.md +0 -0
  30. data/docs/bootstrap-data.md +0 -0
  31. data/docs/custom-inputs.md +0 -0
  32. data/docs/form.md +0 -0
  33. data/docs/internals.md +0 -0
  34. data/docs/nested-forms.md +0 -0
  35. data/docs/redactor-js.md +0 -0
  36. data/docs/scopes.md +0 -0
  37. data/lib/chr/version.rb +1 -1
  38. data/package.json +1 -1
  39. metadata +19 -7
  40. data/app/assets/javascripts/chr/store/store-mongosteen.coffee +0 -111
  41. data/app/assets/javascripts/chr/store/store-rest.coffee +0 -90
@@ -1,5 +1,18 @@
1
+ # -----------------------------------------------------------------------------
2
+ # Author: Alexander Kravets <alex@slatestudio.com>,
3
+ # Slate Studio (http://www.slatestudio.com)
4
+ #
5
+ # Coding Guide:
6
+ # https://github.com/thoughtbot/guides/tree/master/style/coffeescript
7
+ # -----------------------------------------------------------------------------
8
+
1
9
  # -----------------------------------------------------------------------------
2
10
  # MODULE
11
+ #
12
+ # configuration options:
13
+ # title - title used for menu and root list header
14
+ # showNestedListsAside - show module root list on the left and all nested
15
+ # lists on the right side for desktop
3
16
  # -----------------------------------------------------------------------------
4
17
  class @Module
5
18
  constructor: (@chr, @name, @config) ->
@@ -8,57 +21,79 @@ class @Module
8
21
  @$el = $("<section class='module #{ @name }' style='display: none;'>")
9
22
  @chr.$el.append @$el
10
23
 
24
+ # root list
25
+ @activeList = @rootList = new List(this, @name, @config)
26
+
27
+ # menu item + layout
11
28
  menuTitle = @config.menuTitle ? @config.title
12
29
  menuTitle ?= @name.titleize()
13
- @chr.addMenuItem(@name, menuTitle)
30
+ menuPath = @name
14
31
 
15
- @activeList = @rootList = new List(this, @name, @config)
32
+ # do not hide root list layout, nested lists are shown on aside
33
+ if @config.showNestedListsAside
34
+ @$el.addClass 'first-list-aside'
35
+ # jump to first nested list on menu click
36
+ firstNestedList = _firstNonEmptyValue(@nestedLists)
37
+ if ! _isMobile() && firstNestedList
38
+ menuPath += "/#{ firstNestedList.name }"
39
+
40
+ @chr.addMenuItem(menuPath, menuTitle)
16
41
 
42
+ @config.onModuleInit?(this)
17
43
 
18
- _updateActiveListItems: ->
19
- # NOTE: update list data if it's not visible, e.g. for update action we do not
20
- # update whole list, this function should be called before active list got shown.
44
+
45
+ # update list data if it's not visible, e.g. for update action we do not
46
+ # update whole list, this method is called before active list is shown.
47
+ _update_active_list_items: ->
21
48
  if not @activeList.isVisible()
22
49
  @activeList.updateItems()
23
50
 
51
+
52
+ # returns path for the current list
53
+ _view_path: ->
54
+ currentList = @visibleNestedListShownWithParent() ? @activeList
55
+ currentList.path
56
+
57
+
24
58
  addNestedList: (listName, config, parentList) ->
25
59
  @nestedLists[listName] = new List(this, listName, config, parentList)
26
60
 
27
- selectActiveListItem: (href) ->
28
- @unselectActiveListItem()
29
- @activeList.selectItem(href)
30
-
31
- unselectActiveListItem: ->
32
- @activeList?.unselectItems()
33
61
 
34
62
  hideActiveList: (animate=false)->
35
63
  if animate then @activeList.$el.fadeOut() else @activeList.$el.hide()
36
64
  @activeList = @activeList.parentList
37
- @unselectActiveListItem()
65
+
38
66
 
39
67
  showView: (object, config, title, animate=false) ->
40
- newView = new View(this, config, @activeList.path, object, title)
68
+ newView = new View(this, config, @_view_path(), object, title)
41
69
  @chr.$el.append(newView.$el)
42
70
 
43
- @selectActiveListItem(location.hash)
44
-
45
71
  newView.show animate, =>
46
72
  @destroyView()
47
73
  @view = newView
48
74
 
75
+
76
+ showViewByObjectId: (objectId, config, title, animate=false) ->
77
+ onSuccess = (object) => @showView(object, config, title, animate)
78
+ onError = -> chr.showError("can\'t show view for requested object")
79
+
80
+ if objectId == ''
81
+ config.objectStore.loadObject({ onSuccess: onSuccess, onError: onError })
82
+ else
83
+ config.arrayStore.loadObject(objectId, { onSuccess: onSuccess, onError: onError })
84
+
85
+
49
86
  destroyView: ->
50
87
  @view?.destroy()
51
88
 
52
- show: ->
53
- @chr.selectMenuItem(@name)
54
- @unselectActiveListItem()
55
89
 
56
- @_updateActiveListItems()
90
+ show: ->
91
+ @_update_active_list_items()
57
92
  @$el.show()
58
93
  @activeList.show(false)
59
94
 
95
+
60
96
  hide: (animate=false) ->
61
- @unselectActiveListItem()
62
97
  @hideNestedLists()
63
98
 
64
99
  if animate
@@ -69,29 +104,34 @@ class @Module
69
104
  @destroyView()
70
105
  @$el.hide()
71
106
 
107
+
108
+ # shows one of nested lists, with or without animation
72
109
  showNestedList: (listName, animate=false) ->
73
- @selectActiveListItem(location.hash)
74
- @activeList = @nestedLists[listName]
110
+ listToShow = @nestedLists[listName]
75
111
 
76
- @_updateActiveListItems()
112
+ if listToShow.showWithParent
113
+ # list works as view, never becomes active
114
+ listToShow.updateItems()
115
+ listToShow.show animate, => @hideNestedLists(exceptList=listName)
77
116
 
78
- @activeList.show(animate)
79
- if animate and @view then @view.$el.fadeOut $.fx.speeds._default, => @destroyView()
117
+ else
118
+ @activeList = listToShow
119
+ @_update_active_list_items()
120
+ @activeList.show(animate)
80
121
 
81
- hideNestedLists: ->
82
- @activeList = @rootList
83
- list.hide() for key, list of @nestedLists
122
+ # hide view
123
+ if animate and @view then @view.$el.fadeOut $.fx.speeds._default, => @destroyView()
84
124
 
85
- showViewWhenObjectsAreReady: (objectId, config) ->
86
- object = config.arrayStore.get(objectId)
87
- if object then return @showView(object, config)
88
125
 
89
- $(config.arrayStore).one 'objects_added', (e, data) =>
90
- object = config.arrayStore.get(objectId)
91
- if object then return @showView(object, config)
126
+ hideNestedLists: (exceptList) ->
127
+ @activeList = @rootList
128
+ list.hide() for key, list of @nestedLists when key isnt exceptList
92
129
 
93
- console.log "object #{objectId} is not in the list"
94
130
 
131
+ # returns visible nested list that acts as view
132
+ visibleNestedListShownWithParent: ->
133
+ for key, list of @nestedLists
134
+ if list.isVisible() && list.showWithParent then return list
95
135
 
96
136
 
97
137
 
@@ -1,109 +1,154 @@
1
+ # -----------------------------------------------------------------------------
2
+ # Author: Alexander Kravets <alex@slatestudio.com>,
3
+ # Slate Studio (http://www.slatestudio.com)
4
+ #
5
+ # Coding Guide:
6
+ # https://github.com/thoughtbot/guides/tree/master/style/coffeescript
7
+ # -----------------------------------------------------------------------------
8
+
1
9
  # -----------------------------------------------------------------------------
2
10
  # VIEW
11
+ #
12
+ # configuration options:
13
+ # formSchema - form schema for object, autogenerated if missing
14
+ # disableDelete - do not add delete button below the form
15
+ # disableSave - do not add save button in header
16
+ # fullsizeView — use fullsize layout in desktop mode
17
+ #
18
+ # public methods:
19
+ # show(animate, callback)
20
+ # destroy()
21
+ #
3
22
  # -----------------------------------------------------------------------------
4
23
  class @View
5
- _renderForm: ->
6
- @form?.destroy()
7
- @form = new Form(@object, @config)
24
+ constructor: (@module, @config, @closePath, @object, @title) ->
25
+ @store = @config.arrayStore ? @config.objectStore
8
26
 
9
- unless @config.disableDelete or @config.objectStore or @_isNew()
10
- @$deleteBtn =$ "<a href='#' class='delete'>Delete</a>"
11
- @$deleteBtn.on 'click', (e) => @onDelete(e)
12
- @form.$el.append @$deleteBtn
27
+ @$el =$ "<section class='view #{ @module.name }'>"
28
+ @$el.hide()
29
+
30
+ if @config.fullsizeView
31
+ @$el.addClass 'fullsize'
32
+
33
+ # header
34
+ @$header =$ "<header></header>"
35
+ @$el.append @$header
36
+
37
+ @$title =$ "<div class='title'></div>"
38
+ @$header.append @$title
39
+
40
+ # close button
41
+ @$closeBtn =$ "<a href='#/#{ @closePath }' class='close silent'>Close</a>"
42
+ @$closeBtn.on 'click', (e) => @_on_close(e)
43
+ @$header.append @$closeBtn
44
+
45
+ # save button
46
+ unless @config.disableSave
47
+ @$saveBtn =$ "<a href='#' class='save'>Save</a>"
48
+ @$saveBtn.on 'click', (e) => @_on_save(e)
49
+ @$header.append @$saveBtn
50
+
51
+ @_render()
13
52
 
14
- @$el.append @form.$el
15
53
 
16
54
  _render: ->
55
+ @_update_title()
56
+ @_render_form()
57
+
58
+
59
+ _update_title: ->
17
60
  title = @title
18
61
  title ?= @object[@config.itemTitleField] if @config.itemTitleField
19
62
  title ?= _firstNonEmptyValue(@object)
63
+
20
64
  if title == "" then title = "No Title"
21
65
 
22
- # NOTE: remove html tags from title to do not break layout
66
+ # remove html tags from title to do not break layout
23
67
  titleText = $("<div>#{ title }</div>").text()
24
68
  @$title.html(titleText)
25
69
 
26
- @_renderForm()
27
70
 
28
- _initializeFormPlugins: ->
29
- # NOTE: we might need a callback here to workaround plugins blink issue, by setting
30
- # form opacity to 0 and then fading to 1 after plugins are ready.
31
- @form.initializePlugins()
32
- @config.onViewShow?(@)
71
+ _render_form: ->
72
+ @form?.destroy()
73
+ @form = new Form(@object, @config)
33
74
 
34
- _updateObject: (value) ->
35
- @$el.addClass('view-saving')
75
+ # delete button
76
+ unless @config.disableDelete or @config.objectStore or @_is_new()
77
+ @$deleteBtn =$ "<a href='#' class='delete'>Delete</a>"
78
+ @$deleteBtn.on 'click', (e) => @_on_delete(e)
79
+ @form.$el.append @$deleteBtn
80
+
81
+ @$el.append @form.$el
82
+
83
+
84
+ _update_object: (value) ->
85
+ @_start_saving()
36
86
  @store.update @object._id, value,
37
- onSuccess: (object) =>
38
- # TODO: add a note here for this line, it's not obvious why it's here,
39
- # looks like some logic related to title update
87
+ onSuccess: (@object) =>
88
+ # add a note here for this line, it's not obvious why it's here,
89
+ # looks like some logic related to title update
40
90
  if @config.arrayStore then @title = null
41
91
 
42
92
  formScrollPosition = @form.$el.scrollTop()
43
93
  @_render()
44
- @_initializeFormPlugins()
94
+ @_initialize_form_plugins()
45
95
  @form.$el.scrollTop(formScrollPosition)
46
96
 
47
- setTimeout ( => @$el.removeClass('view-saving') ), 250
97
+ @_stop_saving()
98
+
48
99
  onError: (errors) =>
49
- @validationErrors(errors)
50
- setTimeout ( => @$el.removeClass('view-saving') ), 250
100
+ @_validation_errors('Changes were not saved.', errors)
101
+ @_stop_saving()
51
102
 
52
- _createObject: (value) ->
53
- @$el.addClass('view-saving')
103
+
104
+ _create_object: (value) ->
105
+ @_start_saving()
106
+ # refactor this to subscribe to list event: item_added
54
107
  @store.push value,
55
108
  onSuccess: (object) =>
56
- # NOTE: jump to the newely created item, added to the top of the list by default
109
+ # we need to know when list item is added
57
110
  location.hash = "#/#{ @closePath }/view/#{ object._id }"
58
111
  onError: (errors) =>
59
- @validationErrors(errors)
60
- setTimeout ( => @$el.removeClass('view-saving') ), 250
112
+ @_validation_errors('Item were not created.', errors)
113
+ @_stop_saving()
61
114
 
62
- _isNew: -> not @object
115
+ _start_saving: ->
116
+ @$el.addClass('view-saving')
63
117
 
64
- constructor: (@module, @config, @closePath, @object, @title) ->
65
- @store = @config.arrayStore ? @config.objectStore
66
118
 
67
- @$el =$ "<section class='view #{ @module.name }'>"
68
- @$el.hide()
119
+ _stop_saving: ->
120
+ setTimeout ( => @$el.removeClass('view-saving') ), 250
69
121
 
70
- @$header =$ "<header></header>"
71
- @$title =$ "<div class='title'></div>"
72
- @$header.append @$title
73
122
 
74
- @$closeBtn =$ "<a href='#/#{ @closePath }' class='close silent'>Close</a>"
75
- @$closeBtn.on 'click', (e) => @onClose(e)
76
- @$header.append @$closeBtn
123
+ _initialize_form_plugins: ->
124
+ @form.initializePlugins()
125
+ @config.onViewShow?(@)
77
126
 
78
- unless @config.disableSave
79
- @$saveBtn =$ "<a href='#' class='save'>Save</a>"
80
- @$saveBtn.on 'click', (e) => @onSave(e)
81
- @$header.append @$saveBtn
82
127
 
83
- @$el.append @$header
128
+ _validation_errors: (message, errors) ->
129
+ chr.showError(message)
130
+ @form.showValidationErrors(errors)
84
131
 
85
- @_render()
86
132
 
87
- show: (animate, callback) ->
88
- if animate
89
- @$el.fadeIn($.fx.speeds._default, => @_initializeFormPlugins() ; callback?())
90
- else
91
- @$el.show 0, => @_initializeFormPlugins() ; callback?()
133
+ _is_new: ->
134
+ ! @object
92
135
 
93
- destroy: ->
94
- @form?.destroy()
95
- @$el.remove()
96
136
 
97
- onClose: (e) ->
98
- @module.unselectActiveListItem()
137
+ _on_close: (e) ->
99
138
  @$el.fadeOut $.fx.speeds._default, => @destroy()
100
139
 
101
- onSave: (e) ->
140
+
141
+ _on_save: (e) ->
102
142
  e.preventDefault()
103
143
  serializedFormObj = @form.serialize()
104
- if @object then @_updateObject(serializedFormObj) else @_createObject(serializedFormObj)
105
144
 
106
- onDelete: (e) ->
145
+ if @object
146
+ @_update_object(serializedFormObj)
147
+ else
148
+ @_create_object(serializedFormObj)
149
+
150
+
151
+ _on_delete: (e) ->
107
152
  e.preventDefault()
108
153
  if confirm("Are you sure?")
109
154
  @store.remove(@object._id)
@@ -112,8 +157,19 @@ class @View
112
157
  location.hash = "#/#{ @closePath }"
113
158
  @destroy()
114
159
 
115
- validationErrors: (errors) ->
116
- @form.showValidationErrors(errors)
160
+
161
+ show: (animate, callback) ->
162
+ if animate
163
+ @$el.fadeIn($.fx.speeds._default, =>
164
+ @_initialize_form_plugins()
165
+ callback?())
166
+ else
167
+ @$el.show 0, => @_initialize_form_plugins() ; callback?()
168
+
169
+
170
+ destroy: ->
171
+ @form?.destroy()
172
+ @$el.remove()
117
173
 
118
174
 
119
175
 
@@ -1,34 +1,3 @@
1
- # -----------------------------------------------------------------------------
2
- # Author: Alexander Kravets <alex@slatestudio.com>,
3
- # Slate Studio (http://www.slatestudio.com)
4
- #
5
- # Coding Guide:
6
- # https://github.com/thoughtbot/guides/tree/master/style/coffeescript
7
- # -----------------------------------------------------------------------------
8
-
9
- # -----------------------------------------------------------------------------
10
- # OBJECT STORE
11
- # -----------------------------------------------------------------------------
12
- class @ObjectStore
13
- constructor: (@config={}) ->
14
- @_initialize_database()
15
-
16
- _update_data_object: (value, callback) ->
17
- callback?($.extend(@_data, value))
18
-
19
- _fetch_data: ->
20
- @_data = @config.data
21
-
22
- _initialize_database: ->
23
- @_fetch_data()
24
-
25
- get: ->
26
- @_data
27
-
28
- update: (id, value, callback) ->
29
- @_update_data_object(value, callback)
30
-
31
-
32
1
  # -----------------------------------------------------------------------------
33
2
  # ARRAY STORE
34
3
  # javascript object storage implementation that stores/loads objects in memory,
@@ -38,26 +7,27 @@ class @ObjectStore
38
7
  # - reordering
39
8
  #
40
9
  # configuration options:
41
- # @config.data — initial array of objects, default: []
42
- # @config.sortBy — objects field name which is used for sorting, does
43
- # not sort when parameter is not provided, default: nil
44
- # @config.sortReverse — reverse objects sorting (descending order),
45
- # default: false
46
- # @config.newItemOnTop add new item to the top of the list, default: true,
47
- # if @config.sortBy is not set, otherwise: false
48
- # @config.reorderable — list items reordering configuration hash, should
49
- # have two fields:
50
- # { positionFieldName: '',
51
- # sortReverse: false }
10
+ # data — initial array of objects, default: []
11
+ # sortBy — objects field name which is used for sorting, does not sort
12
+ # when parameter is not provided, default: nil
13
+ # sortReverse — reverse objects sorting (descending order), default: false
14
+ # reorderable — list items reordering configuration hash, should have two
15
+ # fields: { positionFieldName: '', sortReverse: false }
52
16
  #
53
17
  # public methods:
54
18
  # - on(eventType, callback)
19
+ # object_added
20
+ # object_changed
21
+ # object_removed
22
+ # objects_added
55
23
  # - off(eventType)
56
24
  # - get(id)
57
25
  # - push(serializedFormObject, callbacks)
58
26
  # - update(serializedFormObject, callbacks)
59
27
  # - remove(id)
60
28
  # - reset(callback)
29
+ # - addObjects(objects)
30
+ # - data()
61
31
  #
62
32
  # todo:
63
33
  # - support for lists, files, nested objects
@@ -71,11 +41,6 @@ class @ArrayStore
71
41
  @sortReverse = @config.sortReverse ? false
72
42
  @reorderable = @config.reorderable ? false
73
43
 
74
- if @sortBy == false
75
- @newItemOnTop = @config.newItemOnTop ? true
76
- else
77
- @newItemOnTop = @config.newItemOnTop ? false
78
-
79
44
  @_initialize_reorderable()
80
45
  @_initialize_database()
81
46
 
@@ -97,15 +62,6 @@ class @ArrayStore
97
62
  ;
98
63
 
99
64
 
100
- # add objects from @config.data,
101
- # trigger 'objects_added' event
102
- _fetch_data: ->
103
- if @config.data
104
- @_add_data_object(o) for o in @config.data
105
-
106
- $(this).trigger('objects_added')
107
-
108
-
109
65
  # sort object in _data array based on sortBy and sortReverse parameters
110
66
  # implementatin details:
111
67
  # http://stackoverflow.com/questions/9796764/how-do-i-sort-an-array-with-coffeescript
@@ -141,40 +97,33 @@ class @ArrayStore
141
97
 
142
98
  # normalize objects id, add object to _data and _map, sort objects,
143
99
  # trigger 'object_added' event
144
- _add_data_object: (object, callback)->
145
- object = @_normalize_object_id(object)
146
-
147
- @_map[object._id] = object
148
- @_data.push(object)
149
-
150
- @_sort_data()
151
- position = @_get_data_object_position(object._id)
152
-
153
- $(this).trigger('object_added', { object: object, position: position, callback: callback })
154
-
155
-
156
- # add object to the top of the _data neglecting ordering,
157
- # trigger 'object_added' event
158
- _add_data_object_on_top: (object, callback) ->
100
+ _add_data_object: (object) ->
159
101
  object = @_normalize_object_id(object)
160
102
 
161
- @_map[object._id] = object
162
- @_data.unshift(object)
103
+ # if object with same id already in the store, update it's parameters,
104
+ # otherwise add new object (this is used while pagination sync)
105
+ if ! @_map[object._id]
106
+ @_map[object._id] = object
107
+ @_data.push(object)
108
+ @_sort_data()
163
109
 
164
- position = 0
110
+ position = @_get_data_object_position(object._id)
165
111
 
166
- $(this).trigger('object_added', { object: object, position: position, callback: callback })
112
+ $(this).trigger('object_added', { object: object, position: position })
113
+ else
114
+ @_update_data_object(object.id, object)
167
115
 
168
116
 
169
117
  # get object by id, update it's attributes, sort objects,
170
118
  # trigger 'object_changed' event
171
- _update_data_object: (id, value, callback) ->
119
+ _update_data_object: (id, value) ->
172
120
  object = $.extend(@get(id), value)
173
121
 
174
122
  @_sort_data()
123
+
175
124
  position = @_get_data_object_position(id)
176
125
 
177
- $(this).trigger('object_changed', { object: object, position: position, callback: callback })
126
+ $(this).trigger('object_changed', { object: object, position: position })
178
127
 
179
128
 
180
129
  # delete object by id from _data and _map,
@@ -182,7 +131,7 @@ class @ArrayStore
182
131
  _remove_data_object: (id) ->
183
132
  position = @_get_data_object_position(id)
184
133
  if position >= 0
185
- delete @_data[position]
134
+ @_data.splice(position, 1)
186
135
 
187
136
  delete @_map[id]
188
137
 
@@ -214,23 +163,14 @@ class @ArrayStore
214
163
  return object
215
164
 
216
165
 
217
- # unsubscribe from store event, simple jQuery wrapper
218
- off: (eventType) ->
219
- if eventType then $(this).off(eventType) else $(this).off()
220
-
221
-
222
- # subsribe to store event, subscribing to 'object_added' fetches data,
223
- # available event types:
224
- # - object_added
225
- # - object_changed
226
- # - object_removed
227
- # - objects_added
166
+ # subsribe to store event
228
167
  on: (eventType, callback) ->
229
168
  $(this).on eventType, (e, data) -> callback(e, data)
230
169
 
231
- #! make sure this run only for first subscribe
232
- if eventType == 'object_added'
233
- @_fetch_data()
170
+
171
+ # unsubscribe from store event, simple jQuery wrapper
172
+ off: (eventType) ->
173
+ if eventType then $(this).off(eventType) else $(this).off()
234
174
 
235
175
 
236
176
  # get object by id
@@ -239,36 +179,43 @@ class @ArrayStore
239
179
 
240
180
 
241
181
  # add new object
242
- push: (serializedFormObject, callbacks) ->
182
+ push: (serializedFormObject, callbacks={}) ->
243
183
  object = @_parse_form_object(serializedFormObject)
184
+
185
+ # generate id for new object
244
186
  if ! object._id then object._id = Date.now()
245
187
 
246
- if @newItemOnTop
247
- @_add_data_object_on_top(object, callbacks.onSuccess)
248
- else
249
- @_add_data_object(object, callbacks.onSuccess)
188
+ @_add_data_object(object)
189
+ callbacks.onSuccess?()
250
190
 
251
191
 
252
192
  # update objects attributes
253
- update: (id, serializedFormObject, callbacks) ->
193
+ update: (id, serializedFormObject, callbacks={}) ->
254
194
  object = @_parse_form_object(serializedFormObject)
255
- @_update_data_object(id, object, callbacks.onSuccess)
195
+ @_update_data_object(id, object)
196
+ callbacks.onSuccess?()
256
197
 
257
198
 
258
199
  # delete object
259
- remove: (id) ->
200
+ remove: (id, callbacks={}) ->
260
201
  @_remove_data_object(id)
202
+ callbacks.onSuccess?()
261
203
 
262
204
 
263
- # reset all data and load it again
264
- reset: (callback) ->
265
- # do nothing here as data is stored in memory, this method
266
- # resets database data, syncing latest changes
267
- @_sort_data()
205
+ # do nothing for in memory data store
206
+ reset: ->
207
+ $(this).trigger('objects_added')
208
+
268
209
 
210
+ # add objects, this is a kind of workaround that helps to initialize
211
+ # store data without request
212
+ addObjects: (objects) ->
213
+ @_add_data_object(o) for o in objects
269
214
  $(this).trigger('objects_added')
270
- callback?()
271
215
 
272
216
 
217
+ # returns stored objects array
218
+ data: ->
219
+ return @_data
273
220
 
274
221