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,124 @@
1
+ class TextileDecorator {
2
+ blockquote(str) { return ["bq. ", str, ""]; }
3
+ bold(str) { return ["<b>", str, "</b>"]; }
4
+ emphasis(str) { return ["<i>", str, "</i>"]; }
5
+ h1(str) { return ["h1. ", str, ""]; }
6
+ h2(str) { return ["h2. ", str, ""]; }
7
+ h3(str) { return ["h3. ", str, ""]; }
8
+ h4(str) { return ["h4. ", str, ""]; }
9
+ h5(str) { return ["h5. ", str, ""]; }
10
+ h6(str) { return ["h6. ", str, ""]; }
11
+ link(url, name) { return ["\"", name, `\":${url}`]; }
12
+ email(address, name) { return ["\"", name, `\":mailto:${address}`]; }
13
+
14
+ list(str) {
15
+ return ["", str.split("\n").map(l => "* " + l).join("\n"), ""];
16
+ }
17
+
18
+ orderedList(str) {
19
+ return ["", str.split("\n").map(l => "# " + l).join("\n"), ""];
20
+ }
21
+ }
22
+
23
+ class RichTextArea {
24
+ constructor(textarea) {
25
+ this.textarea = textarea;
26
+ this.decorator = new TextileDecorator();
27
+ this.toolbar = $("<ul class=\"rich-text-toolbar\"></ul>")
28
+ .insertBefore(this.textarea);
29
+ this.addButtons();
30
+ }
31
+
32
+ adjustSelection(callback) {
33
+ let length = this.getSelection().length;
34
+ let [start, end] = this.getSelectionRange();
35
+ let [replacementLength, prefixLength] = callback();
36
+ let newEnd = (end + (replacementLength - length) + prefixLength);
37
+ let newStart = start === end ? newEnd : (start + prefixLength);
38
+ return this.setSelectionRange(newStart, newEnd);
39
+ };
40
+
41
+ getSelection() {
42
+ return $(this.textarea).getSelection().text;
43
+ }
44
+
45
+ getSelectionRange() {
46
+ if (typeof this.textarea.selectionStart !== "undefined") {
47
+ return [this.textarea.selectionStart, this.textarea.selectionEnd];
48
+ } else {
49
+ return [0, 0];
50
+ }
51
+ };
52
+
53
+ replaceSelection(prefix, replacement, postfix) {
54
+ return this.adjustSelection(() => {
55
+ $(this.textarea).replaceSelection(prefix + replacement + postfix);
56
+ $(this.textarea).focus();
57
+ return [replacement.length, prefix.length];
58
+ });
59
+ };
60
+
61
+ // Sets a new selection range for object
62
+ setSelectionRange(start, end) {
63
+ if (typeof this.textarea.setSelectionRange !== "undefined") {
64
+ return this.textarea.setSelectionRange(start, end);
65
+ }
66
+ };
67
+
68
+ addButton(name, className, callback) {
69
+ var link = $(
70
+ `<a title=\"${name}\" class=\"${className}\">` +
71
+ `<i class=\"fa fa-${className}\"></i></a>`
72
+ );
73
+
74
+ link.click(() => {
75
+ let [prefix, replacement, postfix] = callback(this.getSelection());
76
+ this.replaceSelection(prefix, replacement, postfix);
77
+ });
78
+
79
+ $("<li class=\"button\"></li>").append(link).appendTo(this.toolbar);
80
+ };
81
+
82
+ addButtons() {
83
+ // Bold button
84
+ this.addButton("Bold", "bold", s => this.decorator.bold(s));
85
+
86
+ // Italic button
87
+ this.addButton("Italics", "italic", s => this.decorator.emphasis(s));
88
+
89
+ // Heading buttons
90
+ this.addButton("Heading 2", "header h2", s => this.decorator.h2(s));
91
+ this.addButton("Heading 3", "header h3", s => this.decorator.h3(s));
92
+ this.addButton("Heading 4", "header h4", s => this.decorator.h4(s));
93
+
94
+ // Block Quote
95
+ this.addButton("Block Quote", "quote-left", s => this.decorator.blockquote(s))
96
+
97
+ // List
98
+ this.addButton("List", "list-ul", s => this.decorator.list(s));
99
+
100
+ // Ordered list
101
+ this.addButton("Ordered list", "list-ol", s => this.decorator.orderedList(s));
102
+
103
+ // Link button
104
+ this.addButton("Link", "link", selection => {
105
+ let name = selection.length > 0 ? selection : "Link text";
106
+ var url = prompt("Enter link URL", "");
107
+ url = url.length > 0 ? url : "http://example.com/";
108
+ url = url.replace(/^(?!(f|ht)tps?:\/\/)/, 'http://');
109
+ return this.decorator.link(url, name);
110
+ });
111
+
112
+ // Email button
113
+ this.addButton("Email link", "envelope", selection => {
114
+ let name = selection.length > 0 ? selection : "Link text";
115
+ var address = prompt("Enter email address", "");
116
+ address = address.length > 0 ? address : "example@example.com";
117
+ return this.decorator.email(address, name);
118
+ });
119
+ }
120
+ }
121
+
122
+ $(function() {
123
+ $('textarea.rich').each(function() { new RichTextArea(this); });
124
+ });
@@ -0,0 +1,160 @@
1
+ var TagEditor = function(container) {
2
+ this.initialize(container);
3
+ };
4
+
5
+ $.extend(TagEditor.prototype, {
6
+ initialize: function(container) {
7
+ var tagEditor = this;
8
+ tagEditor.container = container;
9
+ tagEditor.tags = Array();
10
+ tagEditor.serializeField = $(tagEditor.container).find('.serialized_tags').get(0);
11
+ tagEditor.findTags(true);
12
+
13
+ tagEditor.inputField = $(tagEditor.container).find('.add-tag').get(0);
14
+ $(tagEditor.container).find('.add-tag-button').click(function() {
15
+ tagEditor.addTag();
16
+ $(tagEditor.container).find('.add-tag').blur();
17
+ return false;
18
+ });
19
+ $(tagEditor.container).find('.add-tag').keydown(function(event) {
20
+ if (event.which === 13) {
21
+ tagEditor.addTag();
22
+ return false;
23
+ }
24
+ });
25
+
26
+ $(tagEditor.container).find('.add-tag').each(function(){
27
+ var field = this;
28
+ field.exampleText = $(field).val();
29
+ $(field).addClass('example');
30
+ $(field).focus(function(event){
31
+ $(tagEditor.container).find('.add-tag-button').fadeIn('fast');
32
+ $(field).removeClass('example');
33
+ if ($(field).val() === field.exampleText) {
34
+ $(field).val('');
35
+ }
36
+ });
37
+ $(field).blur(function(event) {
38
+ $(tagEditor.container).find('.add-tag-button').fadeOut('fast');
39
+ if (!$(field).val() || $(field).val() === field.exampleText) {
40
+ $(field).addClass('example').val(field.exampleText);
41
+ }
42
+ });
43
+ });
44
+ $(tagEditor.container).find('.add-tag-button').hide();
45
+ },
46
+
47
+ addTag: function() {
48
+ var tagEditor = this;
49
+ var tagName = $(tagEditor.inputField).val().replace(/^\s\s*/, '').replace(/\s\s*$/, '');
50
+ if (tagName) {
51
+ if (this.hasTag(tagName)) {
52
+ this.enable(this.getTagByName(tagName));
53
+ } else {
54
+ $(tagEditor.container).find('.tags').append('<span class="tag"><input type="checkbox" name="tag-'+tagName+'" value="1" checked="checked"><span class="name">'+tagName+'</span></span>');
55
+ tagEditor.findTags();
56
+ }
57
+ }
58
+ $(tagEditor.inputField).val('');
59
+ },
60
+
61
+ findTags: function(permanentize) {
62
+ var tagEditor = this;
63
+ $(this.container).find('.tag').each(function () {
64
+ var tag = this;
65
+ if (!tag.tagEditorApplied) {
66
+ tag.checkBox = $(tag).find('input[type=checkbox]').get(0);
67
+ tag.name = $(tag).find('.name').text();
68
+ if(tagEditor.isChecked(tag)){
69
+ tag.enabled = true;
70
+ $(tag).addClass('enabled');
71
+ } else {
72
+ tag.enabled = false;
73
+ }
74
+ $(tag).click(function () {
75
+ tagEditor.toggle(tag);
76
+ });
77
+ tagEditor.tags[tagEditor.tags.length] = tag;
78
+ tag.tagEditorApplied = true;
79
+ }
80
+ });
81
+ tagEditor.serializeTags();
82
+ },
83
+
84
+ hasTag: function(tagName) {
85
+ var hasTag = false;
86
+ $(this.tags).each(function () {
87
+ if (tagName.toLowerCase() === this.name.toLowerCase()) {
88
+ hasTag = true;
89
+ }
90
+ });
91
+ return hasTag;
92
+ },
93
+
94
+ setEnabled: function(tag, enabled) {
95
+ tag.enabled = enabled;
96
+ if (tag.enabled) {
97
+ $(tag).addClass('enabled');
98
+ } else {
99
+ $(tag).removeClass('enabled');
100
+ }
101
+ $(tag.checkBox).attr('checked', tag.enabled);
102
+ this.serializeTags();
103
+ },
104
+
105
+ toggle: function(tag) {
106
+ if (tag.enabled) {
107
+ this.disable(tag);
108
+ } else {
109
+ this.enable(tag);
110
+ }
111
+ },
112
+
113
+ enable: function(tag) {
114
+ this.setEnabled(tag, true);
115
+ },
116
+
117
+ disable: function(tag) {
118
+ this.setEnabled(tag, false);
119
+ },
120
+
121
+ getTagByName: function(tagName) {
122
+ var tag = null;
123
+ $(this.tags).each(function(){
124
+ if (this.name.toLowerCase() === tagName.toLowerCase()) {
125
+ tag = this;
126
+ }
127
+ });
128
+ return tag;
129
+ },
130
+
131
+ isChecked: function(tag) {
132
+ return $(tag.checkBox).attr('checked');
133
+ },
134
+
135
+ enabledTags: function() {
136
+ var enabledTags = Array();
137
+ $(this.tags).each(function() {
138
+ if (this.enabled) {
139
+ enabledTags[enabledTags.length] = this;
140
+ }
141
+ });
142
+ return enabledTags;
143
+ },
144
+
145
+ serializeTags: function() {
146
+ var tagNames = Array();
147
+ $(this.enabledTags()).each(function() {
148
+ tagNames[tagNames.length] = '"' + this.name.replace('"', '\\"') + '"';
149
+ });
150
+ $(this.serializeField).val('['+tagNames.join(', ')+']');
151
+ $(this.container).find('.add-tag').attr('disabled', false);
152
+ }
153
+ });
154
+
155
+ // Apply the tag editor to each instance
156
+ $(function() {
157
+ $('.tag-editor').each(function() {
158
+ this.tagEditor = new TagEditor(this);
159
+ });
160
+ });
@@ -0,0 +1,21 @@
1
+ (function () {
2
+ let _ajax_request = function(url, data, callback, type, method) {
3
+ if ($.isFunction(data)) {
4
+ callback = data;
5
+ data = {};
6
+ }
7
+ return $.ajax({
8
+ type: method,
9
+ url: url,
10
+ data: data,
11
+ success: callback,
12
+ dataType: type
13
+ });
14
+ };
15
+
16
+ jQuery.extend({
17
+ put: function(url, data, callback, type) {
18
+ return _ajax_request(url, data, callback, type, "PUT");
19
+ }
20
+ });
21
+ })();
@@ -0,0 +1,22 @@
1
+ jQuery.fn.centerOnScreen = function() {
2
+ this.css("position", "absolute");
3
+ this.css("z-index", 1000 + (Math.round(Math.random() * 5000)));
4
+
5
+ var x = (($(window).width() / 2) - (this.width() / 2)) +
6
+ $(window).scrollLeft();
7
+
8
+ var y = (($(window).height() / 2) - (this.height() / 2)) +
9
+ $(window).scrollTop();
10
+
11
+ if (x < 0) {
12
+ x = 0;
13
+ }
14
+
15
+ if (y < 0) {
16
+ y = 0;
17
+ }
18
+
19
+ this.css({left: x + "px", top: y + "px"});
20
+
21
+ return this;
22
+ };
@@ -0,0 +1,294 @@
1
+ /*
2
+ Based on
3
+
4
+ js-tree by Wang Zuo
5
+ https://github.com/wangzuo/js-tree
6
+
7
+ react-ui-tree
8
+ https://github.com/pqx/react-ui-tree
9
+
10
+ The MIT License (MIT)
11
+
12
+ Copyright (c) 2015 Wang Zuo
13
+
14
+ Permission is hereby granted, free of charge, to any person obtaining a copy
15
+ of this software and associated documentation files (the "Software"), to deal
16
+ in the Software without restriction, including without limitation the rights
17
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18
+ copies of the Software, and to permit persons to whom the Software is
19
+ furnished to do so, subject to the following conditions:
20
+
21
+ The above copyright notice and this permission notice shall be included in
22
+ all copies or substantial portions of the Software.
23
+
24
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30
+ SOFTWARE.
31
+
32
+ Copyright (c) 2015 pqx Limited
33
+
34
+ Permission is hereby granted, free of charge, to any person obtaining a copy
35
+ of this software and associated documentation files (the "Software"), to deal
36
+ in the Software without restriction, including without limitation the rights
37
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
38
+ copies of the Software, and to permit persons to whom the Software is
39
+ furnished to do so, subject to the following conditions:
40
+
41
+ The above copyright notice and this permission notice shall be included in
42
+ all copies or substantial portions of the Software.
43
+
44
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
45
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
46
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
47
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
48
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
49
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
50
+ SOFTWARE.
51
+ */
52
+ class Tree {
53
+ constructor(obj) {
54
+ this.cnt = 1;
55
+ this.obj = obj || { children: [] };
56
+ this.indexes = {};
57
+ this.build(this.obj);
58
+ }
59
+
60
+ build(obj) {
61
+ var indexes = this.indexes;
62
+ var startId = this.cnt;
63
+ var self = this;
64
+
65
+ var index = { id: startId, node: obj };
66
+ indexes[this.cnt + ''] = index;
67
+ this.cnt++;
68
+
69
+ if (obj.children && obj.children.length) {
70
+ walk(obj.children, index);
71
+ }
72
+
73
+ function walk(objs, parent) {
74
+ var children = [];
75
+ objs.forEach(function(obj, i) {
76
+ var index = {};
77
+ index.id = self.cnt;
78
+ index.node = obj;
79
+
80
+ if (parent) {
81
+ index.parent = parent.id;
82
+ }
83
+
84
+ indexes[self.cnt + ''] = index;
85
+ children.push(self.cnt);
86
+ self.cnt++;
87
+
88
+ if (obj.children && obj.children.length) {
89
+ walk(obj.children, index);
90
+ }
91
+ });
92
+ parent.children = children;
93
+
94
+ children.forEach(function(id, i) {
95
+ var index = indexes[id + ''];
96
+ if (i > 0) {
97
+ index.prev = children[i - 1];
98
+ }
99
+ if (i < children.length-1) {
100
+ index.next = children[i+1];
101
+ }
102
+ });
103
+ }
104
+
105
+ return index;
106
+ }
107
+
108
+ getIndex(id) {
109
+ var index = this.indexes[id + ''];
110
+ if (index) {
111
+ return index;
112
+ }
113
+ }
114
+
115
+ removeIndex(index) {
116
+ var self = this;
117
+ del(index);
118
+
119
+ function del(index) {
120
+ delete self.indexes[index.id + ''];
121
+ if (index.children && index.children.length) {
122
+ index.children.forEach(function(child) {
123
+ del(self.getIndex(child));
124
+ });
125
+ }
126
+ }
127
+ }
128
+
129
+ get(id) {
130
+ var index = this.getIndex(id);
131
+ if (index && index.node) {
132
+ return index.node;
133
+ }
134
+ return null;
135
+ }
136
+
137
+ remove(id) {
138
+ var index = this.getIndex(id);
139
+ var node = this.get(id);
140
+ var parentIndex = this.getIndex(index.parent);
141
+ var parentNode = this.get(index.parent);
142
+ parentNode.children.splice(parentNode.children.indexOf(node), 1);
143
+ parentIndex.children.splice(parentIndex.children.indexOf(id), 1);
144
+ this.removeIndex(index);
145
+ this.updateChildren(parentIndex.children);
146
+
147
+ return node;
148
+ }
149
+
150
+ updateChildren(children) {
151
+ children.forEach(function(id, i) {
152
+ var index = this.getIndex(id);
153
+ index.prev = index.next = null;
154
+ if (i > 0) {
155
+ index.prev = children[i-1];
156
+ }
157
+ if (i < children.length-1) {
158
+ index.next = children[i+1];
159
+ }
160
+ }.bind(this));
161
+ }
162
+
163
+ insert(obj, parentId, i) {
164
+ var parentIndex = this.getIndex(parentId);
165
+ var parentNode = this.get(parentId);
166
+
167
+ var index = this.build(obj);
168
+ index.parent = parentId;
169
+
170
+ parentNode.children = parentNode.children || [];
171
+ parentIndex.children = parentIndex.children || [];
172
+
173
+ parentNode.children.splice(i, 0, obj);
174
+ parentIndex.children.splice(i, 0, index.id);
175
+
176
+ this.updateChildren(parentIndex.children);
177
+ if (parentIndex.parent) {
178
+ this.updateChildren(this.getIndex(parentIndex.parent).children);
179
+ }
180
+
181
+ return index;
182
+ }
183
+
184
+ insertBefore(obj, destId) {
185
+ var destIndex = this.getIndex(destId);
186
+ var parentId = destIndex.parent;
187
+ var i = this.getIndex(parentId).children.indexOf(destId);
188
+ return this.insert(obj, parentId, i);
189
+ }
190
+
191
+ insertAfter(obj, destId) {
192
+ var destIndex = this.getIndex(destId);
193
+ var parentId = destIndex.parent;
194
+ var i = this.getIndex(parentId).children.indexOf(destId);
195
+ return this.insert(obj, parentId, i+1);
196
+ }
197
+
198
+ prepend(obj, destId) {
199
+ return this.insert(obj, destId, 0);
200
+ }
201
+
202
+ append(obj, destId) {
203
+ var destIndex = this.getIndex(destId);
204
+ destIndex.children = destIndex.children || [];
205
+ return this.insert(obj, destId, destIndex.children.length);
206
+ }
207
+
208
+ // react-ui-tree methods
209
+
210
+ updateNodesPosition() {
211
+ var top = 1;
212
+ var left = 1;
213
+ var root = this.getIndex(1);
214
+ var self = this;
215
+
216
+ root.top = top++;
217
+ root.left = left++;
218
+
219
+ if (root.children && root.children.length) {
220
+ walk(root.children, root, left, root.node.collapsed);
221
+ }
222
+
223
+ function walk(children, parent, left, collapsed) {
224
+ var height = 1;
225
+ children.forEach(function(id) {
226
+ var node = self.getIndex(id);
227
+ if (collapsed) {
228
+ node.top = null;
229
+ node.left = null;
230
+ } else {
231
+ node.top = top++;
232
+ node.left = left;
233
+ }
234
+
235
+ if (node.children && node.children.length) {
236
+ height += walk(
237
+ node.children,
238
+ node,
239
+ left+1,
240
+ collapsed || node.node.collapsed
241
+ );
242
+ } else {
243
+ node.height = 1;
244
+ height += 1;
245
+ }
246
+ });
247
+
248
+ if(parent.node.collapsed) parent.height = 1;
249
+ else parent.height = height;
250
+ return parent.height;
251
+ }
252
+ }
253
+
254
+ move(fromId, toId, placement) {
255
+ if (fromId === toId || toId === 1) {
256
+ return;
257
+ }
258
+
259
+ var obj = this.remove(fromId);
260
+ var index = null;
261
+
262
+ if (placement === 'before') {
263
+ index = this.insertBefore(obj, toId);
264
+ } else if (placement === 'after') {
265
+ index = this.insertAfter(obj, toId);
266
+ } else if(placement === 'prepend') {
267
+ index = this.prepend(obj, toId);
268
+ } else if(placement === 'append') {
269
+ index = this.append(obj, toId);
270
+ }
271
+
272
+ // todo: perf
273
+ this.updateNodesPosition();
274
+ return index;
275
+ }
276
+
277
+ getParent(id) {
278
+ var indexes = this.indexes;
279
+ if (indexes.hasOwnProperty(id)) {
280
+ return this.getIndex(indexes[id].parent);
281
+ }
282
+ }
283
+
284
+ getNodeByTop(top) {
285
+ var indexes = this.indexes;
286
+ for(var id in indexes) {
287
+ if (indexes.hasOwnProperty(id)) {
288
+ if(indexes[id].top === top) {
289
+ return indexes[id];
290
+ }
291
+ }
292
+ }
293
+ }
294
+ }