chr 0.2.8 → 0.3.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/Gruntfile.coffee +33 -27
  3. data/README.md +6 -1
  4. data/app/assets/javascripts/chr.coffee +18 -16
  5. data/app/assets/javascripts/chr/core/chr.coffee +41 -76
  6. data/app/assets/javascripts/chr/core/chr_router.coffee +141 -0
  7. data/app/assets/javascripts/chr/core/item.coffee +36 -49
  8. data/app/assets/javascripts/chr/core/list.coffee +26 -71
  9. data/app/assets/javascripts/chr/core/list_config.coffee +28 -13
  10. data/app/assets/javascripts/chr/core/list_pagination.coffee +56 -13
  11. data/app/assets/javascripts/chr/core/list_reorder.coffee +2 -2
  12. data/app/assets/javascripts/chr/core/list_search.coffee +2 -2
  13. data/app/assets/javascripts/chr/core/module.coffee +24 -93
  14. data/app/assets/javascripts/chr/core/utils.coffee +4 -0
  15. data/app/assets/javascripts/chr/core/view.coffee +123 -43
  16. data/app/assets/javascripts/chr/core/view_local-storage.coffee +58 -0
  17. data/app/assets/javascripts/chr/store/{_array-store.coffee → array-store.coffee} +3 -1
  18. data/app/assets/javascripts/chr/store/{_object-store.coffee → object-store.coffee} +0 -0
  19. data/app/assets/javascripts/chr/store/rails-array-store.coffee +39 -0
  20. data/app/assets/javascripts/chr/store/{mongosteen-object-store.coffee → rails-form-object-parser.coffee} +11 -20
  21. data/app/assets/javascripts/chr/store/rails-object-store.coffee +35 -0
  22. data/app/assets/javascripts/chr/store/rest-array-store.coffee +3 -5
  23. data/app/assets/javascripts/chr/store/rest-object-store.coffee +1 -1
  24. data/app/assets/javascripts/form/expandable-group.coffee +30 -0
  25. data/app/assets/javascripts/{chr/form → form}/form.coffee +3 -1
  26. data/app/assets/javascripts/{chr/form → form}/input-checkbox.coffee +1 -1
  27. data/app/assets/javascripts/{chr/form → form}/input-color.coffee +2 -0
  28. data/app/assets/javascripts/{chr/form → form}/input-date.coffee +0 -0
  29. data/app/assets/javascripts/{chr/form → form}/input-file.coffee +28 -1
  30. data/app/assets/javascripts/{chr/form → form}/input-form.coffee +14 -5
  31. data/app/assets/javascripts/{chr/form → form}/input-form_reorder.coffee +0 -0
  32. data/app/assets/javascripts/{chr/form → form}/input-hidden.coffee +9 -9
  33. data/app/assets/javascripts/{chr/form → form}/input-list.coffee +61 -53
  34. data/app/assets/javascripts/{chr/form → form}/input-list_reorder.coffee +2 -0
  35. data/app/assets/javascripts/form/input-list_typeahead.coffee +55 -0
  36. data/app/assets/javascripts/{chr/form → form}/input-password.coffee +1 -0
  37. data/app/assets/javascripts/{chr/form → form}/input-select.coffee +10 -11
  38. data/app/assets/javascripts/form/input-select2.coffee +33 -0
  39. data/app/assets/javascripts/{chr/form → form}/input-string.coffee +45 -2
  40. data/app/assets/javascripts/{chr/form → form}/input-text.coffee +6 -3
  41. data/app/assets/javascripts/input-html.coffee +8 -5
  42. data/app/assets/javascripts/input-markdown.coffee +10 -5
  43. data/app/assets/javascripts/input-redactor.coffee +1 -61
  44. data/app/assets/javascripts/redactor/input-redactor.coffee +53 -0
  45. data/app/assets/javascripts/redactor/input-redactor_character.coffee +83 -0
  46. data/app/assets/javascripts/redactor/input-redactor_images.coffee +166 -0
  47. data/app/assets/javascripts/{chr/vendor → vendor}/ace.js +0 -0
  48. data/app/assets/javascripts/{chr/vendor → vendor}/jquery.scrollparent.js +0 -0
  49. data/app/assets/javascripts/{chr/vendor → vendor}/jquery.textarea_autosize.js +0 -0
  50. data/app/assets/javascripts/{chr/vendor → vendor}/jquery.typeahead.js +0 -0
  51. data/app/assets/javascripts/{chr/vendor → vendor}/marked.js +0 -0
  52. data/app/assets/javascripts/{chr/vendor → vendor}/mode-html.js +0 -0
  53. data/app/assets/javascripts/{chr/vendor → vendor}/mode-markdown.js +0 -0
  54. data/app/assets/javascripts/{chr/vendor → vendor}/redactor.fixedtoolbar.js +1 -1
  55. data/app/assets/javascripts/vendor/select2.js +5274 -0
  56. data/app/assets/javascripts/{chr/vendor → vendor}/slip.js +0 -0
  57. data/app/assets/stylesheets/_chr.scss +11 -13
  58. data/app/assets/stylesheets/_input-redactor.scss +17 -16
  59. data/app/assets/stylesheets/{core → chr}/_icons.scss +1 -1
  60. data/app/assets/stylesheets/chr/_main.scss +110 -0
  61. data/app/assets/stylesheets/{core → chr}/_mixins.scss +58 -34
  62. data/app/assets/stylesheets/{core → chr}/_settings.scss +7 -1
  63. data/app/assets/stylesheets/form/_expandable-group.scss +16 -0
  64. data/app/assets/stylesheets/form/_input-select2.scss +94 -0
  65. data/app/assets/stylesheets/form/_main.scss +180 -0
  66. data/app/assets/stylesheets/vendor/select2.css +258 -0
  67. data/bower.json +2 -2
  68. data/dist/chr.js +2292 -2030
  69. data/dist/input-ace.js +18 -8
  70. data/dist/input-redactor.js +0 -156
  71. data/docs/bootstrap.md +1 -1
  72. data/docs/rails.md +10 -10
  73. data/lib/chr.rb +1 -8
  74. data/lib/chr/version.rb +1 -1
  75. data/lib/mongoid/character.rb +30 -0
  76. data/package.json +1 -1
  77. metadata +49 -43
  78. data/app/assets/javascripts/chr/store/mongosteen-array-store.coffee +0 -55
  79. data/app/assets/stylesheets/core/_list.scss +0 -39
  80. data/app/assets/stylesheets/core/_main.scss +0 -49
  81. data/app/assets/stylesheets/core/_responsive.scss +0 -62
  82. data/app/assets/stylesheets/form/_form.scss +0 -41
  83. data/app/assets/stylesheets/form/_input-checkbox.scss +0 -18
  84. data/app/assets/stylesheets/form/_input-color.scss +0 -10
  85. data/app/assets/stylesheets/form/_input-file.scss +0 -29
  86. data/app/assets/stylesheets/form/_input-form.scss +0 -26
  87. data/app/assets/stylesheets/form/_input-list.scss +0 -36
  88. data/app/assets/stylesheets/form/_input-string.scss +0 -8
@@ -3,7 +3,7 @@
3
3
  # -----------------------------------------------------------------------------
4
4
  #
5
5
  # Dependencies:
6
- #= require ../vendor/slip
6
+ #= require vendor/slip
7
7
  #
8
8
  # -----------------------------------------------------------------------------
9
9
 
@@ -59,7 +59,7 @@
59
59
  objectPositionValue = _getObjectNewPosition(e.target)
60
60
  objectId = $(e.target).attr('data-id')
61
61
  value = {}
62
- value["[#{arrayStore.sortBy}"] = "#{ objectPositionValue }"
62
+ value["[#{arrayStore.sortBy}]"] = "#{ objectPositionValue }"
63
63
 
64
64
  arrayStore.update objectId, value,
65
65
  # error handling
@@ -32,7 +32,7 @@
32
32
 
33
33
  _on_search: ->
34
34
  query = @$searchInput.val()
35
- @_show_spinner()
35
+ @showSpinner()
36
36
  @config.arrayStore.search(query)
37
37
 
38
38
 
@@ -45,7 +45,7 @@
45
45
  _on_search_cancel: ->
46
46
  @$el.removeClass('list-search')
47
47
  @$searchInput.val('')
48
- @_show_spinner()
48
+ @showSpinner()
49
49
  @config.arrayStore.reset()
50
50
 
51
51
 
@@ -11,16 +11,13 @@
11
11
  # -----------------------------------------------------------------------------
12
12
  # Config options:
13
13
  # title - title used for menu and root list header
14
+ # menuTitle - title used for the menu link
14
15
  # showNestedListsAside - show module root list on the left and all nested
15
16
  # lists on the right side for desktop
16
17
  #
17
18
  # Public methods:
18
19
  # addNestedList (listName, config, parentList)
19
- # showNestedList (listName)
20
- # hideNestedLists (exceptList)
21
- # visibleNestedListShownWithParent ()
22
- # showRootList ()
23
- # hideActiveList ()
20
+ # showList()
24
21
  # showView (object, config, title)
25
22
  # showViewByObjectId (objectId, config, title)
26
23
  # destroyView ()
@@ -36,119 +33,53 @@ class @Module
36
33
  @chr.$el.append @$el
37
34
 
38
35
  # root list
39
- @activeList = @rootList = new List(this, @name, @config)
36
+ @rootList = new List(this, "#/#{ @name }", @name, @config)
40
37
 
41
38
  # menu item + layout
42
- menuTitle = @config.menuTitle ? @config.title
43
- menuTitle ?= @name.titleize()
44
- menuPath = @name
45
-
46
- # do not hide root list layout, nested lists are shown on aside
47
- if @config.showNestedListsAside
48
- @$el.addClass 'first-list-aside'
49
- # jump to first nested list on menu click
50
- firstNestedList = _firstNonEmptyValue(@nestedLists)
51
- if ! @chr.isMobile() && firstNestedList
52
- menuPath += "/#{ firstNestedList.name }"
53
-
54
- @chr.addMenuItem(menuPath, menuTitle)
39
+ @menuTitle = @config.menuTitle ? @config.title
40
+ @menuTitle ?= @name.titleize()
55
41
 
56
42
  @config.onModuleInit?(this)
57
43
 
58
44
 
59
- # PRIVATE ===============================================
60
-
61
- # update list data if it's not visible, e.g. for update action we do not
62
- # update whole list, this method is called before active list is shown.
63
- _update_active_list_items: ->
64
- if not @activeList.isVisible()
65
- @activeList.updateItems()
66
-
67
-
68
- # returns path for the current list
69
- _view_path: ->
70
- currentList = @visibleNestedListShownWithParent() ? @activeList
71
- currentList.path
72
-
73
-
74
45
  # PUBLIC ================================================
75
46
 
76
- addNestedList: (listName, config, parentList) ->
77
- @nestedLists[listName] = new List(this, listName, config, parentList)
78
-
79
-
80
- # shows one of nested lists
81
- showNestedList: (listName) ->
82
- listToShow = @nestedLists[listName]
47
+ addNestedList: (name, config, parentList) ->
48
+ path = [ parentList.path, name ].join('/')
49
+ @nestedLists[name] = new List(this, path, name, config, parentList)
83
50
 
84
- if listToShow.showWithParent
85
- # list works as view, never becomes active
86
- listToShow.updateItems()
87
- listToShow.show => @hideNestedLists(exceptList=listName)
88
51
 
52
+ showList: (name) ->
53
+ if ! name # show root list, hide all nested
54
+ list.hide() for key, list of @nestedLists
55
+ @activeList = @rootList
89
56
  else
90
- @activeList = listToShow
91
- @_update_active_list_items()
92
- @activeList.show()
57
+ @activeList = @nestedLists[name]
93
58
 
94
- @destroyView()
59
+ @activeList.show()
95
60
 
96
61
 
97
- hideNestedLists: (exceptList) ->
98
- @activeList = @rootList
99
- list.hide() for key, list of @nestedLists when key isnt exceptList
62
+ showView: (objectId, config) ->
63
+ @view = new View(this, config, @activeList.path, @activeList.name)
64
+ @$el.append(@view.$el)
65
+ @view.show(objectId)
100
66
 
101
67
 
102
- visibleNestedListShownWithParent: ->
103
- for key, list of @nestedLists
104
- if list.isVisible() && list.showWithParent then return list
68
+ show: ->
69
+ @$el.show()
70
+ @showList()
105
71
 
106
72
 
107
- showRootList: ->
73
+ hide: ->
108
74
  @destroyView()
109
- while @activeList != @rootList
110
- @hideActiveList()
111
-
112
-
113
- hideActiveList: ->
114
- @activeList.$el.hide()
115
- @activeList = @activeList.parentList
116
-
117
-
118
- showView: (object, config, title) ->
119
- newView = new View(this, config, @_view_path(), object, title)
120
- @chr.$el.append(newView.$el)
121
-
122
- newView.show =>
123
- @destroyView()
124
- @view = newView
125
-
126
-
127
- showViewByObjectId: (objectId, config, title) ->
128
- onSuccess = (object) => @showView(object, config, title)
129
- onError = -> chr.showError("can\'t show view for requested object")
130
-
131
- if objectId == ''
132
- config.objectStore.loadObject({ onSuccess: onSuccess, onError: onError })
133
- else
134
- config.arrayStore.loadObject(objectId, { onSuccess: onSuccess, onError: onError })
75
+ @$el.hide()
135
76
 
136
77
 
137
78
  destroyView: ->
138
79
  @view?.destroy()
80
+ @view = null
139
81
 
140
82
 
141
- show: ->
142
- @_update_active_list_items()
143
- @$el.show()
144
- @activeList.show()
145
-
146
-
147
- hide: ->
148
- @hideNestedLists()
149
- @destroyView()
150
- @$el.hide()
151
-
152
83
 
153
84
 
154
85
 
@@ -10,6 +10,7 @@
10
10
  # UTILS
11
11
  # -----------------------------------------------------------------------------
12
12
  # Public methods:
13
+ # _any(array)
13
14
  # _last(array)
14
15
  # _first(array)
15
16
  # _firstNonEmptyValue(hash)
@@ -22,6 +23,9 @@
22
23
  # include(class, hash)
23
24
  # -----------------------------------------------------------------------------
24
25
 
26
+ # _any(array)
27
+ @_any = (array) -> array.length > 0
28
+
25
29
  # _last(array)
26
30
  @_last = (array) -> array[array.length - 1]
27
31
 
@@ -8,8 +8,9 @@
8
8
 
9
9
  # -----------------------------------------------------------------------------
10
10
  # VIEW
11
+ # -----------------------------------------------------------------------------
11
12
  #
12
- # config options:
13
+ # Config options:
13
14
  # formClass - custom form class to be used
14
15
  # formSchema - form schema for object, autogenerated if missing
15
16
  # disableDelete - do not add delete button below the form
@@ -17,78 +18,93 @@
17
18
  # fullsizeView — use fullsize layout in desktop mode
18
19
  # onViewShow - on show callback
19
20
  #
20
- # public methods:
21
- # show(callback)
21
+ # Public methods:
22
+ # show(objectId)
22
23
  # destroy()
24
+ # showSpinner()
25
+ # hideSpinner()
26
+ #
27
+ # Dependencies:
28
+ #= require ./view_local-storage
23
29
  #
24
30
  # -----------------------------------------------------------------------------
25
31
  class @View
26
- constructor: (@module, @config, @closePath, @object, @title) ->
32
+ constructor: (@module, @config, @closePath, @listName) ->
27
33
  @store = @config.arrayStore ? @config.objectStore
34
+ @path = window.location.hash
28
35
 
29
- @$el =$ "<section class='view #{ @module.name }' style='display:none;'>"
36
+ @$el =$ "<section class='view #{ @listName }'>"
30
37
 
31
38
  # fullsize
32
39
  if @config.fullsizeView
33
40
  @$el.addClass 'fullsize'
34
41
 
35
42
  # header
36
- @$header =$ "<header></header>"
37
- @$title =$ "<div class='title'></div>"
43
+ @$header =$ "<header class='header'></header>"
44
+ @$spinner =$ "<div class='spinner'></div>"
45
+ @$title =$ "<div class='title'></div>"
46
+ @$header.append @$spinner
38
47
  @$header.append @$title
39
48
  @$el.append @$header
40
- @_set_title()
41
49
 
42
50
  # close
43
- @$closeBtn =$ "<a href='#/#{ @closePath }' class='close silent'>Close</a>"
51
+ @$closeBtn =$ "<a href='#{ @closePath }' class='close'>Close</a>"
44
52
  @$closeBtn.on 'click', (e) => @_close(e)
45
53
  @$header.append @$closeBtn
46
54
 
47
- # save
48
- unless @config.disableSave
49
- @$saveBtn =$ "<a href='#' class='save'>Save</a>"
50
- @$saveBtn.on 'click', (e) => @_save(e)
51
- @$header.append @$saveBtn
52
-
53
- # form
54
- @form = new (@config.formClass ? Form)(@object, @config)
55
- @$el.append @form.$el
56
- @_add_form_delete_button()
55
+ # content
56
+ @$content =$ "<div class='content'></div>"
57
+ @$el.append @$content
57
58
 
58
59
 
59
60
  # PRIVATE ===============================================
60
61
 
61
- _set_title: (reset=false) ->
62
- if reset && @config.arrayStore then @title = null
63
- title = @title
64
- title ?= @object[@config.itemTitleField] if @config.itemTitleField
65
- title ?= _firstNonEmptyValue(@object)
62
+ _set_title: ->
63
+ if ! @object
64
+ title = "New"
65
+
66
+ else if @config.objectStore
67
+ title = @config.title
68
+ title ?= _firstNonEmptyValue(@object)
69
+
70
+ else
71
+ if @config.itemTitleField
72
+ title = @object[@config.itemTitleField]
73
+ title ?= @object['_list_item_title']
74
+ title ?= _firstNonEmptyValue(@object)
75
+
66
76
  @$title.html(title.plainText())
67
77
 
68
78
 
69
- _add_form_delete_button: ->
79
+ _add_delete_button: ->
70
80
  unless @config.disableDelete or @config.objectStore or (! @object)
71
- @$deleteBtn =$ "<a href='#' class='delete'>Delete</a>"
81
+ @$deleteBtn =$ "<a href='#' class='view-delete'>Delete</a>"
72
82
  @$deleteBtn.on 'click', (e) => @_delete(e)
73
- @form.$el.append @$deleteBtn
83
+ @$content.append @$deleteBtn
74
84
 
75
85
 
76
86
  _save_success: ->
77
87
  @$el.removeClass('view-saving')
78
- @_set_title(true)
88
+ @_set_title()
89
+ @form.hideValidationErrors()
79
90
  @form.updateValues(@object)
91
+ @_clear_local_storage_cache()
80
92
 
81
93
 
82
94
  _save_error: (message, validationErrors) ->
83
95
  @$el.removeClass('view-saving')
84
- chr.showError(message)
85
96
  @form.showValidationErrors(validationErrors)
97
+ chr.showError(message)
86
98
 
87
99
 
88
100
  # EVENTS ================================================
89
101
 
90
102
  _close: (e) ->
91
- @destroy()
103
+ if @_changes_not_saved()
104
+ if confirm('Your changes are not saved, still want to close?')
105
+ @_clear_local_storage_cache()
106
+ else
107
+ e.preventDefault()
92
108
 
93
109
 
94
110
  _save: (e) ->
@@ -99,39 +115,103 @@ class @View
99
115
 
100
116
  if @object
101
117
  @store.update @object._id, serializedFormObj,
102
- onSuccess: (@object) => @_save_success()
103
- onError: (errors) => @_save_error('Changes were not saved.', errors)
118
+ onSuccess: (@object) =>
119
+ @_save_success()
120
+ onError: (errors) => @_save_error('Changes are not saved.', errors)
104
121
  else
105
122
  @store.push serializedFormObj,
106
123
  onSuccess: (@object) =>
107
124
  @_save_success()
108
- @_add_form_delete_button()
109
- chr.updateHash("#/#{ @closePath }/view/#{ @object._id }", true)
110
- onError: (errors) => @_save_error('Item were not created.', errors)
125
+ @_add_delete_button()
126
+ chr.updateHash("#{ @closePath }/view/#{ @object._id }", true)
127
+ @path = window.location.hash
128
+ @config.onViewShow?(@)
129
+ onError: (errors) => @_save_error('Document is not created due to an error.', errors)
111
130
 
112
131
 
113
132
  _delete: (e) ->
114
133
  e.preventDefault()
115
134
  if confirm("Are you sure?")
116
135
  @store.remove @object._id,
117
- onSuccess: => chr.updateHash("#/#{ @closePath }", true) ; @destroy()
118
- onError: -> chr.showError('Can\'t delete object.')
136
+ onSuccess: =>
137
+ @_clear_local_storage_cache()
138
+ chr.updateHash("#{ @closePath }", true)
139
+ @destroy()
140
+ chr.mobileListLock(false)
141
+ onError: -> chr.showError('Can\'t delete document.')
142
+
143
+
144
+ _render_form: ->
145
+ @_set_title()
146
+
147
+ @hideSpinner()
148
+
149
+ # save
150
+ unless @config.disableSave
151
+ @$saveBtn =$ "<a href='#' class='save'>Save</a>"
152
+ @$saveBtn.on 'click', (e) => @_save(e)
153
+ @$header.append @$saveBtn
154
+
155
+ # sync with local storage cache
156
+ @_update_object_from_local_storage()
157
+
158
+ # form
159
+ @form = new (@config.formClass ? Form)(@object, @config)
160
+ @$content.append @form.$el
161
+ @form.initializePlugins()
162
+
163
+ @_add_delete_button()
164
+ @config.onViewShow?(@)
165
+
166
+ # enable local storage caching
167
+ @_bind_form_change()
168
+
169
+
170
+ _show_error: ->
171
+ @hideSpinner()
172
+ chr.showError("can\'t show view for requested object, application error 500")
119
173
 
120
174
 
121
175
  # PUBLIC ================================================
122
176
 
123
- show: (callback) ->
124
- @$el.show 0, =>
125
- callback?()
126
- @form.initializePlugins()
127
- @config.onViewShow?(@)
177
+
178
+ showSpinner: ->
179
+ @$el.addClass('show-spinner')
180
+
181
+
182
+ hideSpinner: ->
183
+ @$el.removeClass('show-spinner')
128
184
 
129
185
 
130
186
  destroy: ->
131
- @form.destroy()
187
+ @form?.destroy()
132
188
  @$el.remove()
133
189
 
134
190
 
191
+ show: (objectId) ->
192
+ callbacks =
193
+ onSuccess: (@object) => @_render_form()
194
+ onError: => @_show_error()
195
+
196
+ @showSpinner()
197
+
198
+ # new for array store
199
+ if objectId == null
200
+ @object = null
201
+ @_render_form()
202
+
203
+ # object store
204
+ else if objectId == ''
205
+ @_set_title()
206
+ @store.loadObject(callbacks)
207
+
208
+ # array store
209
+ else
210
+ @store.loadObject(objectId, callbacks)
211
+
212
+
213
+ include(View, viewLocalStorage)
214
+
135
215
 
136
216
 
137
217