pages_core 3.4.3 → 3.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (215) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +81 -15
  3. data/Rakefile +1 -1
  4. data/app/assets/javascripts/pages/admin.es6.jsx +19 -0
  5. data/app/assets/javascripts/pages/admin/components.es6.jsx +1 -0
  6. data/app/assets/javascripts/pages/admin/components/page_tree.es6.jsx +330 -0
  7. data/app/assets/javascripts/pages/admin/components/page_tree_actions.es6.jsx +8 -0
  8. data/app/assets/javascripts/pages/admin/components/page_tree_node.es6.jsx +374 -0
  9. data/app/assets/javascripts/pages/admin/components/page_tree_store.es6.jsx +161 -0
  10. data/app/assets/javascripts/pages/admin/features/content_tabs.es6.jsx +63 -0
  11. data/app/assets/javascripts/pages/admin/features/edit_page.es6.jsx +141 -0
  12. data/app/assets/javascripts/pages/admin/features/editable_image.es6.jsx +145 -0
  13. data/app/assets/javascripts/pages/admin/features/modal.es6.jsx +90 -0
  14. data/app/assets/javascripts/pages/admin/features/page_images.es6.jsx +338 -0
  15. data/app/assets/javascripts/pages/admin/features/rich_text.es6.jsx +124 -0
  16. data/app/assets/javascripts/pages/admin/features/tag_editor.es6.jsx +160 -0
  17. data/app/assets/javascripts/pages/admin/lib/ajax_extensions.es6.jsx +21 -0
  18. data/app/assets/javascripts/pages/admin/lib/center_on_screen.es6.jsx +22 -0
  19. data/app/assets/javascripts/pages/admin/lib/tree.es6.jsx +294 -0
  20. data/app/assets/javascripts/pages/login_form.es6.jsx +21 -0
  21. data/app/assets/stylesheets/pages/admin.scss +148 -0
  22. data/app/assets/stylesheets/pages/admin/components/buttons.scss +5 -0
  23. data/app/assets/stylesheets/pages/admin/{editable_image.css.erb → components/editable_image.scss} +7 -8
  24. data/app/assets/stylesheets/pages/admin/components/forms.scss +71 -0
  25. data/app/assets/stylesheets/pages/admin/components/header.scss +169 -0
  26. data/app/assets/stylesheets/pages/admin/{images.css.scss.erb → components/images.scss} +6 -11
  27. data/app/assets/stylesheets/pages/admin/components/layout.scss +44 -0
  28. data/app/assets/stylesheets/pages/admin/components/links.scss +43 -0
  29. data/app/assets/stylesheets/pages/admin/components/list_table.scss +58 -0
  30. data/app/assets/stylesheets/pages/admin/{login.css.scss.erb → components/login.scss} +1 -1
  31. data/app/assets/stylesheets/pages/admin/{modal.css.erb → components/modal.scss} +3 -2
  32. data/app/assets/stylesheets/pages/admin/components/page_tree.scss +173 -0
  33. data/app/assets/stylesheets/pages/admin/{pagination.css.scss → components/pagination.scss} +13 -4
  34. data/app/assets/stylesheets/pages/admin/components/sidebar.scss +25 -0
  35. data/app/assets/stylesheets/pages/admin/{tag_editor.css.scss.erb → components/tag_editor.scss} +6 -0
  36. data/app/assets/stylesheets/pages/admin/components/textarea.scss +76 -0
  37. data/app/assets/stylesheets/pages/admin/controllers/pages.scss +196 -0
  38. data/app/assets/stylesheets/pages/admin/controllers/{users.css.erb → users.scss} +0 -0
  39. data/app/assets/stylesheets/pages/admin/mixins/breakpoints.scss +21 -0
  40. data/app/assets/stylesheets/pages/admin/mixins/clearfix.scss +7 -0
  41. data/app/assets/stylesheets/pages/admin/mixins/gradients.scss +7 -0
  42. data/app/assets/stylesheets/pages/admin/{print.css.erb → print.scss} +0 -0
  43. data/app/assets/stylesheets/pages/admin/vars.scss +8 -0
  44. data/app/controllers/admin/invites_controller.rb +10 -6
  45. data/app/controllers/admin/page_files_controller.rb +6 -8
  46. data/app/controllers/admin/page_images_controller.rb +14 -19
  47. data/app/controllers/admin/pages_controller.rb +44 -97
  48. data/app/controllers/admin/password_resets_controller.rb +7 -2
  49. data/app/controllers/concerns/pages_core/add_comments_controller.rb +67 -0
  50. data/app/controllers/concerns/pages_core/admin/news_page_controller.rb +58 -0
  51. data/app/controllers/concerns/pages_core/authentication.rb +1 -1
  52. data/app/controllers/concerns/pages_core/exception_handler.rb +44 -21
  53. data/app/controllers/concerns/pages_core/policies_helper.rb +10 -6
  54. data/app/controllers/concerns/pages_core/preview_pages_controller.rb +43 -0
  55. data/app/controllers/concerns/pages_core/process_titler.rb +2 -2
  56. data/app/controllers/concerns/pages_core/rss_controller.rb +25 -0
  57. data/app/controllers/concerns/pages_core/search_pages_controller.rb +40 -0
  58. data/app/controllers/errors_controller.rb +14 -2
  59. data/app/controllers/pages_core/admin_controller.rb +7 -5
  60. data/app/controllers/pages_core/frontend/page_files_controller.rb +5 -7
  61. data/app/controllers/pages_core/frontend/pages_controller.rb +41 -219
  62. data/app/controllers/pages_core/frontend_controller.rb +8 -2
  63. data/app/controllers/pages_core/sitemaps_controller.rb +5 -4
  64. data/app/formatters/pages_core/html_formatter.rb +33 -23
  65. data/app/helpers/admin/menu_helper.rb +12 -9
  66. data/app/helpers/admin/pages_helper.rb +40 -28
  67. data/app/helpers/pages_core/admin/admin_helper.rb +58 -56
  68. data/app/helpers/pages_core/admin/labelled_field_helper.rb +6 -7
  69. data/app/helpers/pages_core/admin/tag_editor_helper.rb +11 -9
  70. data/app/helpers/pages_core/application_helper.rb +13 -26
  71. data/app/helpers/pages_core/form_builder.rb +71 -134
  72. data/app/helpers/pages_core/head_tags_helper.rb +26 -168
  73. data/app/helpers/pages_core/images_helper.rb +3 -3
  74. data/app/helpers/pages_core/meta_tags_helper.rb +96 -0
  75. data/app/helpers/pages_core/open_graph_tags_helper.rb +51 -0
  76. data/app/helpers/pages_core/page_path_helper.rb +40 -0
  77. data/app/mailers/admin_mailer.rb +14 -14
  78. data/app/models/autopublisher.rb +2 -2
  79. data/app/models/category.rb +8 -8
  80. data/app/models/concerns/pages_core/has_roles.rb +2 -2
  81. data/app/models/concerns/pages_core/humanizable_param.rb +5 -5
  82. data/app/models/concerns/pages_core/page_model/autopublishable.rb +25 -0
  83. data/app/models/concerns/pages_core/page_model/commentable.rb +29 -0
  84. data/app/models/concerns/pages_core/page_model/images.rb +50 -0
  85. data/app/models/concerns/pages_core/page_model/localizable.rb +29 -0
  86. data/app/models/concerns/pages_core/page_model/pathable.rb +115 -0
  87. data/app/models/concerns/pages_core/page_model/redirectable.rb +36 -0
  88. data/app/models/concerns/pages_core/page_model/searchable.rb +41 -0
  89. data/app/models/concerns/pages_core/page_model/sortable.rb +54 -0
  90. data/app/models/concerns/pages_core/page_model/status.rb +50 -0
  91. data/app/models/concerns/pages_core/page_model/templateable.rb +82 -0
  92. data/app/models/concerns/pages_core/page_model/tree.rb +108 -0
  93. data/app/models/page.rb +30 -212
  94. data/app/models/page_builder.rb +4 -6
  95. data/app/models/page_category.rb +7 -0
  96. data/app/models/page_comment.rb +1 -1
  97. data/app/models/page_file.rb +4 -6
  98. data/app/models/page_image.rb +6 -7
  99. data/app/models/page_path.rb +46 -0
  100. data/app/models/password_reset_token.rb +5 -5
  101. data/app/models/role.rb +1 -1
  102. data/app/models/tag.rb +14 -16
  103. data/app/models/tagging.rb +2 -1
  104. data/app/models/user.rb +6 -7
  105. data/app/policies/page_policy.rb +8 -4
  106. data/app/policies/user_policy.rb +1 -1
  107. data/app/serializers/page_tree_serializer.rb +15 -0
  108. data/app/views/admin/invites/new.html.erb +2 -1
  109. data/app/views/admin/invites/show.html.erb +3 -4
  110. data/app/views/admin/pages/_edit_comments.html.erb +22 -6
  111. data/app/views/admin/pages/_edit_content.html.erb +4 -2
  112. data/app/views/admin/pages/_edit_images.html.erb +86 -75
  113. data/app/views/admin/pages/_edit_metadata.html.erb +22 -0
  114. data/app/views/admin/pages/_edit_options.html.erb +23 -15
  115. data/app/views/admin/pages/_pagelisting.html.erb +6 -6
  116. data/app/views/admin/pages/edit.html.erb +11 -6
  117. data/app/views/admin/pages/index.html.erb +12 -53
  118. data/app/views/admin/pages/new.html.erb +3 -3
  119. data/app/views/admin/pages/news.html.erb +1 -1
  120. data/app/views/admin_mailer/invite.text.erb +1 -1
  121. data/app/views/admin_mailer/password_reset.text.erb +1 -1
  122. data/app/views/errors/422.html.erb +7 -0
  123. data/app/views/errors/500_critical.html.erb +1 -1
  124. data/app/views/layouts/admin.html.erb +36 -32
  125. data/app/views/layouts/admin/_header.html.erb +2 -2
  126. data/config/locales/en.yml +38 -1
  127. data/config/routes.rb +40 -23
  128. data/db/migrate/20111219033112_create_pages_tables.rb +25 -29
  129. data/db/migrate/20121010055412_drop_removed_tables.rb +3 -3
  130. data/db/migrate/20130823133208_update_page_redirect_to.rb +0 -13
  131. data/db/migrate/20140203183900_create_roles.rb +5 -2
  132. data/db/migrate/20140920231700_convert_images_to_dis.rb +4 -2
  133. data/db/migrate/20150401131300_localize_images.rb +7 -8
  134. data/db/migrate/20151002174800_create_page_paths.rb +10 -0
  135. data/db/migrate/20151021103400_drop_binaries_table.rb +7 -0
  136. data/db/migrate/20151204151000_remove_page_content_order.rb +5 -0
  137. data/db/migrate/20160330220900_rename_pages_categories.rb +6 -0
  138. data/db/migrate/20160405202700_change_localization_limit.rb +9 -0
  139. data/lib/pages_core.rb +22 -27
  140. data/lib/pages_core/admin_menu_item.rb +16 -3
  141. data/lib/pages_core/archive_finder.rb +40 -13
  142. data/lib/pages_core/cache_sweeper.rb +72 -45
  143. data/lib/pages_core/configuration.rb +2 -2
  144. data/lib/pages_core/configuration/base.rb +4 -8
  145. data/lib/pages_core/configuration/pages.rb +6 -3
  146. data/lib/pages_core/engine.rb +23 -1
  147. data/lib/pages_core/extensions.rb +2 -2
  148. data/lib/pages_core/file_embedder.rb +40 -0
  149. data/lib/pages_core/page_path_constraint.rb +23 -0
  150. data/lib/pages_core/pages_plugin.rb +11 -0
  151. data/lib/pages_core/paginates.rb +3 -3
  152. data/lib/pages_core/plugin.rb +14 -8
  153. data/lib/pages_core/templates.rb +6 -6
  154. data/lib/pages_core/templates/block_configuration.rb +1 -1
  155. data/lib/pages_core/templates/configuration.rb +23 -24
  156. data/lib/pages_core/templates/configuration_handler.rb +1 -1
  157. data/lib/pages_core/templates/configuration_proxy.rb +7 -11
  158. data/lib/pages_core/templates/template_configuration.rb +55 -61
  159. data/lib/pages_core/version.rb +1 -1
  160. data/lib/rails/generators/pages_core/install/install_generator.rb +22 -48
  161. data/lib/rails/generators/pages_core/install/templates/page_templates_initializer.rb +1 -1
  162. data/lib/rails/generators/pages_core/install/templates/pages_initializer.rb +6 -3
  163. data/lib/rails/generators/pages_core/rspec/rspec_generator.rb +4 -1
  164. data/lib/rails/generators/pages_core/rspec/templates/factories.rb +1 -1
  165. data/lib/tasks/pages.rake +4 -4
  166. data/lib/tasks/pages/page_paths.rake +12 -0
  167. data/template.rb +2 -2
  168. data/vendor/assets/javascripts/reflux.min.js +1 -0
  169. metadata +173 -85
  170. data/app/assets/images/pages/admin/description-bg.gif +0 -0
  171. data/app/assets/images/pages/admin/drag-handle.gif +0 -0
  172. data/app/assets/images/pages/admin/flash-error-bg.gif +0 -0
  173. data/app/assets/images/pages/admin/formelement-bg.gif +0 -0
  174. data/app/assets/images/pages/admin/header-tab-current-bg.gif +0 -0
  175. data/app/assets/images/pages/admin/list-table-td-bg.gif +0 -0
  176. data/app/assets/images/pages/admin/sidebar-bg.gif +0 -0
  177. data/app/assets/images/pages/admin/textarea_controls.gif +0 -0
  178. data/app/assets/javascripts/pages/admin.js.coffee +0 -54
  179. data/app/assets/javascripts/pages/admin/controllers/base.js.coffee +0 -4
  180. data/app/assets/javascripts/pages/admin/controllers/pages_controller.js.coffee +0 -139
  181. data/app/assets/javascripts/pages/admin/controllers/users_controller.js.coffee +0 -9
  182. data/app/assets/javascripts/pages/admin/features/content_tabs.js.coffee +0 -47
  183. data/app/assets/javascripts/pages/admin/features/editable_image.js.coffee.erb +0 -122
  184. data/app/assets/javascripts/pages/admin/features/modal.js.coffee +0 -66
  185. data/app/assets/javascripts/pages/admin/features/page_images.js +0 -329
  186. data/app/assets/javascripts/pages/admin/features/rich_text.js.coffee +0 -40
  187. data/app/assets/javascripts/pages/admin/features/tag_editor.js +0 -159
  188. data/app/assets/javascripts/pages/admin/lib/ajax_extensions.js.coffee +0 -17
  189. data/app/assets/javascripts/pages/admin/lib/center_on_screen.js.coffee +0 -21
  190. data/app/assets/javascripts/pages/admin/lib/jrichtextarea.js +0 -57
  191. data/app/assets/javascripts/pages/login_form.js.coffee +0 -17
  192. data/app/assets/stylesheets/pages/admin.css.erb +0 -404
  193. data/app/assets/stylesheets/pages/admin/buttons.css.erb +0 -5
  194. data/app/assets/stylesheets/pages/admin/controllers/artists.css.erb +0 -94
  195. data/app/assets/stylesheets/pages/admin/controllers/files.css.erb +0 -58
  196. data/app/assets/stylesheets/pages/admin/controllers/pages.css.scss.erb +0 -178
  197. data/app/assets/stylesheets/pages/admin/forms.css.scss.erb +0 -73
  198. data/app/assets/stylesheets/pages/admin/header.css.erb +0 -129
  199. data/app/assets/stylesheets/pages/admin/links.css.erb +0 -34
  200. data/app/assets/stylesheets/pages/admin/list_table.css.erb +0 -56
  201. data/app/assets/stylesheets/pages/admin/sidebar.css.erb +0 -39
  202. data/app/assets/stylesheets/pages/admin/sortable_images.css.erb +0 -18
  203. data/app/assets/stylesheets/pages/admin/textarea.css.erb +0 -55
  204. data/app/models/concerns/pages_core/page_tree.rb +0 -85
  205. data/app/models/concerns/pages_core/searchable_page.rb +0 -33
  206. data/app/models/concerns/pages_core/templateable.rb +0 -85
  207. data/app/models/localization.rb +0 -27
  208. data/db/migrate/20140515130100_remove_sphinx_deltas.rb +0 -15
  209. data/lib/pages_core/localizable.rb +0 -49
  210. data/lib/pages_core/localizable/active_record_extension.rb +0 -41
  211. data/lib/pages_core/localizable/class_methods.rb +0 -51
  212. data/lib/pages_core/localizable/configuration.rb +0 -50
  213. data/lib/pages_core/localizable/instance_methods.rb +0 -130
  214. data/lib/pages_core/localizable/localizer.rb +0 -72
  215. data/lib/pages_core/localizable/scope_extension.rb +0 -22
@@ -0,0 +1,8 @@
1
+ var PageTreeActions = Reflux.createActions([
2
+ "addChild",
3
+ "init",
4
+ "movedPage",
5
+ "toggleCollapsed",
6
+ "updatePage",
7
+ "updateTree"
8
+ ]);
@@ -0,0 +1,374 @@
1
+ /*
2
+ Based on react-ui-tree
3
+ https://github.com/pqx/react-ui-tree
4
+
5
+ The MIT License (MIT)
6
+
7
+ Copyright (c) 2015 pqx Limited
8
+
9
+ Permission is hereby granted, free of charge, to any person obtaining a copy
10
+ of this software and associated documentation files (the "Software"), to deal
11
+ in the Software without restriction, including without limitation the rights
12
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
+ copies of the Software, and to permit persons to whom the Software is
14
+ furnished to do so, subject to the following conditions:
15
+
16
+ The above copyright notice and this permission notice shall be included in all
17
+ copies or substantial portions of the Software.
18
+
19
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25
+ SOFTWARE.
26
+ */
27
+
28
+ class PageTreeNode extends React.Component {
29
+ constructor(props) {
30
+ super(props);
31
+ this.state = { newName: props.index.node.name };
32
+ }
33
+
34
+ actions() {
35
+ let statusLabel = (this.node().status != 2) ? "Publish" : "Hide";
36
+ let statusIcon = (this.node().status != 2) ? "check" : "ban";
37
+
38
+ if (this.node().editing) {
39
+ return null;
40
+ }
41
+
42
+ if (this.props.index.id === 1) {
43
+ return (
44
+ <span className="actions">
45
+ <button type="button"
46
+ className="add"
47
+ onClick={e => this.props.addChild(this.props.index)}>
48
+ <i className="fa fa-plus icon" />
49
+ Add child
50
+ </button>
51
+ </span>
52
+ );
53
+ } else {
54
+ return (
55
+ <span className="actions">
56
+ {this.button(statusLabel, {
57
+ className: "toggle-status",
58
+ icon: statusIcon,
59
+ onClick: e => this.toggleStatus()
60
+ })}
61
+
62
+ {this.button("Rename", {
63
+ className: "edit",
64
+ icon: "pencil",
65
+ onClick: e => this.edit()
66
+ })}
67
+
68
+ {this.button("Delete", {
69
+ className: "delete",
70
+ icon: "trash",
71
+ onClick: e => this.deletePage()
72
+ })}
73
+
74
+ {this.button("Add child", {
75
+ className: "add",
76
+ icon: "plus",
77
+ onClick: e => this.props.addChild(this.props.index)
78
+ })}
79
+ </span>
80
+ );
81
+ }
82
+ }
83
+
84
+ addButton() {
85
+ let self = this;
86
+ let node = this.node();
87
+ let handleClick = function (e) {
88
+ if (self.props.addChild) {
89
+ self.props.addChild(self.props.index);
90
+ }
91
+ }
92
+
93
+ if (!node.collapsed && this.visibleChildren().length > 0) {
94
+ return (
95
+ this.button("Add page here", {
96
+ className: "add add-inline",
97
+ icon: "plus",
98
+ onClick: handleClick
99
+ })
100
+ );
101
+ }
102
+ }
103
+
104
+ button(label, options) {
105
+ let icon = "fa fa-" + options.icon + " icon";
106
+ return (
107
+ <button type="button"
108
+ className={options.className}
109
+ onClick={options.onClick}>
110
+ <i className={icon} />
111
+ {label}
112
+ </button>
113
+ );
114
+ }
115
+
116
+ childNodes() {
117
+ let index = this.props.index;
118
+ let tree = this.props.tree;
119
+ let dragging = this.props.dragging;
120
+
121
+ if (index.children && index.children.length && !index.node.collapsed) {
122
+ var childrenStyles = {};
123
+ if (index.node.collapsed) {
124
+ childrenStyles.display = 'none';
125
+ }
126
+ childrenStyles['paddingLeft'] = this.props.paddingLeft + 'px';
127
+
128
+ return (
129
+ <div className="children" style={childrenStyles}>
130
+ {index.children.map((child) => {
131
+ var childIndex = tree.getIndex(child);
132
+ return (
133
+ <PageTreeNode
134
+ tree={tree}
135
+ index={childIndex}
136
+ key={childIndex.id}
137
+ dragging={dragging}
138
+ paddingLeft={this.props.paddingLeft}
139
+ addChild={this.props.addChild}
140
+ onCollapse={this.props.onCollapse}
141
+ onDragStart={this.props.onDragStart}
142
+ updatePage={this.props.updatePage}
143
+ />
144
+ );
145
+ })}
146
+ </div>
147
+ );
148
+ }
149
+
150
+ return null;
151
+ }
152
+
153
+ collapseArrow() {
154
+ let index = this.props.index;
155
+ let self = this;
156
+
157
+ // Don't collapse the root node
158
+ if (!index.parent) {
159
+ return null;
160
+ }
161
+
162
+ let handleCollapse = function (e) {
163
+ e.stopPropagation();
164
+ let nodeId = self.props.index.id;
165
+ if (self.props.onCollapse) {
166
+ self.props.onCollapse(nodeId);
167
+ }
168
+ }
169
+
170
+ if (this.visibleChildren().length > 0) {
171
+ let collapsed = index.node.collapsed;
172
+ var classnames = null;
173
+
174
+ if (collapsed) {
175
+ classnames = "collapse fa fa-caret-right";
176
+ } else {
177
+ classnames = "collapse fa fa-caret-down";
178
+ }
179
+
180
+ return (
181
+ <i className={classnames}
182
+ onMouseDown={function(e) {e.stopPropagation()}}
183
+ onClick={handleCollapse} />
184
+ );
185
+ }
186
+
187
+ return null;
188
+ }
189
+
190
+ collapsedLabel() {
191
+ if (this.node().collapsed && this.node().children.length > 0) {
192
+ let pluralized = (this.node().children.length == 1) ? "item" : "items";
193
+ return (
194
+ <span className="collapsed-label">
195
+ ({this.node().children.length} {pluralized})
196
+ </span>
197
+ );
198
+ } else {
199
+ return null;
200
+ }
201
+ }
202
+
203
+ deletePage() {
204
+ if (confirm("Are you sure you want to delete this page?")) {
205
+ this.updatePage({status: 4});
206
+ }
207
+ }
208
+
209
+ edit() {
210
+ this.updatePage({editing: true});
211
+ }
212
+
213
+ editUrl(page) {
214
+ return(`/admin/${page.locale}/pages/${page.param}/edit`)
215
+ }
216
+
217
+ node() {
218
+ return this.props.index.node;
219
+ }
220
+
221
+ pageName() {
222
+ if (this.node().name) {
223
+ return this.node().name;
224
+ } else {
225
+ return <i className="untitled">Untitled</i>;
226
+ }
227
+ }
228
+
229
+ render() {
230
+ let self = this;
231
+ let props = this.props;
232
+ let index = props.index;
233
+ let dragging = props.dragging;
234
+ var classnames = "node";
235
+
236
+ var node = this.node().editing ? this.renderEditNode() : this.renderNode();
237
+
238
+ if (index.id === dragging) {
239
+ classnames = "node placeholder";
240
+ }
241
+
242
+ let handleMouseDown = function (e) {
243
+ if (props.onDragStart) {
244
+ props.onDragStart(props.index.id, self.refs.inner, e);
245
+ }
246
+ }
247
+
248
+ if (this.node().status != 4) {
249
+ return (
250
+ <div className={classnames}>
251
+ <div className="inner" ref="inner" onMouseDown={handleMouseDown}>
252
+ {this.collapseArrow()}
253
+ {node}
254
+ </div>
255
+ {this.childNodes()}
256
+ {this.addButton()}
257
+ </div>
258
+ );
259
+ } else {
260
+ return null;
261
+ }
262
+ }
263
+
264
+ renderEditNode() {
265
+ let self = this;
266
+
267
+ let handleNameChange = function(event) {
268
+ self.setState({newName: event.target.value});
269
+ }
270
+
271
+ let performEdit = function(event) {
272
+ event.preventDefault();
273
+ self.updatePage({
274
+ name: self.state.newName,
275
+ editing: false
276
+ });
277
+ }
278
+
279
+ let cancelEdit = function(e) {
280
+ self.setState({newName: self.node().name});
281
+ self.updatePage({editing: false});
282
+ }
283
+
284
+ return (
285
+ <div className="page edit">
286
+ <i className="fa fa-file-o icon"></i>
287
+ <form onSubmit={performEdit}>
288
+ <input type="text"
289
+ value={this.state.newName}
290
+ autoFocus
291
+ ref="nameInput"
292
+ onChange={handleNameChange} />
293
+ <button className="save" type="submit">
294
+ <i className="fa fa-cloud icon"></i>
295
+ Save
296
+ </button>
297
+ {this.button("Cancel", {
298
+ className: "cancel",
299
+ icon: "ban",
300
+ onClick: cancelEdit
301
+ })}
302
+ </form>
303
+ </div>
304
+ );
305
+ }
306
+
307
+ renderNode() {
308
+ let self = this;
309
+ let index = this.props.index;
310
+ let node = index.node;
311
+
312
+ var pageName = <span className="name">{this.pageName()}</span>;
313
+ var className = "page";
314
+
315
+ var iconClass = "fa fa-file-o icon";
316
+
317
+ if (typeof(node.status) != "undefined") {
318
+ className = `page status-${this.node().status}`;
319
+ }
320
+
321
+ if (node.id && node.locale) {
322
+ pageName = <a href={this.editUrl(node)} className="name">
323
+ {this.pageName()}
324
+ </a>;
325
+ }
326
+
327
+ if (node.news_page) {
328
+ iconClass = "fa fa-newspaper-o icon";
329
+ } else if (node.pinned) {
330
+ iconClass = "fa fa-flag-o icon";
331
+ }
332
+
333
+ return (
334
+ <div className={className}>
335
+ <i className={iconClass}></i>
336
+ {pageName}
337
+ {this.statusLabel()}
338
+ {this.collapsedLabel()}
339
+ {this.actions()}
340
+ </div>
341
+ );
342
+ }
343
+
344
+ statusLabel() {
345
+ let labels = ["Draft", "Reviewed", "Published", "Hidden", "Deleted"];
346
+ if (typeof(this.node().status) != "undefined" && this.node().status != 2) {
347
+ return (
348
+ <span className="status-label">
349
+ ({labels[this.node().status]})
350
+ </span>
351
+ );
352
+ } else {
353
+ return "";
354
+ }
355
+ }
356
+
357
+ toggleStatus() {
358
+ if (this.node().status != 2) {
359
+ this.updatePage({status: 2});
360
+ } else {
361
+ this.updatePage({status: 3});
362
+ }
363
+ }
364
+
365
+ updatePage(attributes) {
366
+ if (this.props.updatePage) {
367
+ return this.props.updatePage(this.props.index, attributes);
368
+ }
369
+ }
370
+
371
+ visibleChildren() {
372
+ return this.node().children.filter(p => p.status != 4);
373
+ }
374
+ }
@@ -0,0 +1,161 @@
1
+ (function () {
2
+ var tree = null;
3
+
4
+ var PageTreeStore = Reflux.createStore({
5
+ listenables: [PageTreeActions],
6
+
7
+ init: function () {
8
+ if (!window.localStorage.collapsedPages) {
9
+ window.localStorage.collapsedPages = JSON.stringify({});
10
+ }
11
+ },
12
+
13
+ applyCollapsed: function () {
14
+ let store = this;
15
+ let collapsedState = JSON.parse(window.localStorage.collapsedPages);
16
+ let walk = function (id) {
17
+ var index = tree.getIndex(id);
18
+ var node = index.node;
19
+ if (collapsedState.hasOwnProperty(node.id)) {
20
+ node.collapsed = collapsedState[node.id];
21
+ } else if (node.news_page) {
22
+ node.collapsed = true;
23
+ } else if (store.depth(index) > 1) {
24
+ node.collapsed = true;
25
+ }
26
+ if (index.children && index.children.length) {
27
+ index.children.forEach(c => walk(c));
28
+ }
29
+ };
30
+ walk(1);
31
+ },
32
+
33
+ depth: function (index) {
34
+ var depth = 0;
35
+ var pointer = index;
36
+ while (pointer = tree.getIndex(pointer.parent)) {
37
+ depth += 1;
38
+ }
39
+ return depth;
40
+ },
41
+
42
+ createPage: function (index, attributes) {
43
+ let store = this;
44
+ let url = `/admin/${index.node.locale}/pages.json`;
45
+ $.post(url, { page: attributes }, function (response) {
46
+ store.updateNode(index, response.page_tree);
47
+ });
48
+ },
49
+
50
+ movePage: function (index, parent, position) {
51
+ let data = {
52
+ parent_id: parent.node.id,
53
+ position: position
54
+ };
55
+ let url = `/admin/${index.node.locale}/pages/${index.node.id}/move.json`;
56
+ this.performUpdate(index, url, data);
57
+ },
58
+
59
+ updatePage: function (index, attributes) {
60
+ let url = `/admin/${index.node.locale}/pages/${index.node.id}.json`;
61
+ this.performUpdate(index, url, { page: attributes });
62
+ },
63
+
64
+ performUpdate: function (index, url, data) {
65
+ let store = this;
66
+ $.put(url, data, function (response) {
67
+ store.updateNode(index, response.page_tree);
68
+ });
69
+ },
70
+
71
+ updateNode: function (index, attributes) {
72
+ for (var attr in attributes) {
73
+ if (attributes.hasOwnProperty(attr)) {
74
+ index.node[attr] = attributes[attr];
75
+ }
76
+ }
77
+ this.trigger(tree);
78
+ },
79
+
80
+ getInitialState: function () {
81
+ return tree;
82
+ },
83
+
84
+ setCollapsed: function (id, value) {
85
+ var node = tree.getIndex(id).node;
86
+ node.collapsed = value;
87
+ this.storeCollapsed(id, node.collapsed);
88
+ tree.updateNodesPosition();
89
+ },
90
+
91
+ storeCollapsed: function (id, state) {
92
+ let node = tree.getIndex(id).node;
93
+ var store = JSON.parse(window.localStorage.collapsedPages);
94
+ store[node.id] = state;
95
+ window.localStorage.collapsedPages = JSON.stringify(store);
96
+ },
97
+
98
+ reorderChildren: function (id) {
99
+ var index = tree.getIndex(id);
100
+ var node = index.node;
101
+ if (!node.news_page) {
102
+ return;
103
+ }
104
+ index.children = index.children.sort(function (a, b) {
105
+ var aNode = tree.getIndex(a).node;
106
+ var bNode = tree.getIndex(b).node;
107
+ if (aNode.pinned == bNode.pinned) {
108
+ return new Date(bNode.published_at) - new Date(aNode.published_at);
109
+ } else {
110
+ return aNode.pinned ? -1 : 1;
111
+ }
112
+ });
113
+ tree.updateNodesPosition();
114
+ },
115
+
116
+ onInit: function (newTree) {
117
+ tree = new Tree(newTree);
118
+ this.applyCollapsed();
119
+ tree.updateNodesPosition();
120
+ this.trigger(tree);
121
+ },
122
+
123
+ onMovedPage: function (id) {
124
+ let index = tree.getIndex(id);
125
+ this.reorderChildren(index.parent);
126
+
127
+ parent = tree.getIndex(index.parent);
128
+ position = parent.children.indexOf(id) + 1;
129
+
130
+ this.movePage(index, parent, position);
131
+ this.trigger(tree);
132
+ },
133
+
134
+ onAddChild: function (id, attributes) {
135
+ var index = tree.append(attributes, id);
136
+ this.reorderChildren(id);
137
+ this.setCollapsed(id, false);
138
+ this.createPage(index, attributes);
139
+ this.trigger(tree);
140
+ },
141
+
142
+ onToggleCollapsed: function (id) {
143
+ var node = tree.getIndex(id).node;
144
+ this.setCollapsed(id, !node.collapsed);
145
+ this.trigger(tree);
146
+ },
147
+
148
+ onUpdatePage: function (id, attributes) {
149
+ var index = tree.getIndex(id);
150
+ this.updateNode(index, attributes);
151
+ this.updatePage(index, attributes);
152
+ },
153
+
154
+ onUpdateTree: function (newTree) {
155
+ tree = newTree;
156
+ this.trigger(tree);
157
+ }
158
+ });
159
+
160
+ window.PageTreeStore = PageTreeStore;
161
+ })();