pages_core 3.7.0 → 3.8.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -2
- data/Rakefile +37 -0
- data/app/assets/builds/pages_core/admin-dist.js +55 -0
- data/app/assets/stylesheets/pages/admin/components/image_editor.scss +1 -0
- data/app/assets/stylesheets/pages/admin/components/image_grid.scss +33 -5
- data/app/assets/stylesheets/pages/admin/components/layout.scss +2 -1
- data/app/assets/stylesheets/pages/admin/components/login.scss +6 -0
- data/app/assets/stylesheets/pages/admin/components/tabs.scss +5 -0
- data/app/assets/stylesheets/pages/admin/components/tag_editor.scss +13 -7
- data/app/assets/stylesheets/pages/admin/controllers/pages.scss +13 -5
- data/app/assets/stylesheets/pages/admin.scss +0 -1
- data/app/controller_dummies/admin/admin_controller.rb +1 -1
- data/app/controller_dummies/application_controller.rb +1 -1
- data/app/controller_dummies/attachments_controller.rb +1 -1
- data/app/controller_dummies/frontend_controller.rb +1 -1
- data/app/controller_dummies/images_controller.rb +1 -1
- data/app/controller_dummies/page_files_controller.rb +1 -1
- data/app/controller_dummies/pages_controller.rb +1 -1
- data/app/controller_dummies/sitemaps_controller.rb +1 -1
- data/app/controllers/admin/attachments_controller.rb +1 -1
- data/app/controllers/admin/images_controller.rb +11 -8
- data/app/controllers/concerns/pages_core/authentication.rb +9 -4
- data/app/controllers/concerns/pages_core/preview_pages_controller.rb +5 -0
- data/app/controllers/pages_core/frontend/pages_controller.rb +5 -2
- data/app/controllers/sessions_controller.rb +1 -1
- data/app/formatters/pages_core/link_renderer.rb +2 -2
- data/app/helpers/application_helper.rb +1 -1
- data/app/helpers/frontend_helper.rb +1 -1
- data/app/helpers/pages_core/admin/content_tabs_helper.rb +5 -2
- data/app/helpers/pages_core/admin/image_uploads_helper.rb +2 -3
- data/app/helpers/pages_core/admin/tag_editor_helper.rb +9 -39
- data/app/helpers/pages_core/head_tags_helper.rb +11 -20
- data/app/helpers/pages_core/open_graph_tags_helper.rb +1 -1
- data/app/javascript/admin-dist.js +2 -0
- data/app/javascript/components/Attachments/Attachment.jsx +121 -0
- data/app/javascript/components/Attachments/AttachmentEditor.jsx +116 -0
- data/app/javascript/components/Attachments/Placeholder.jsx +10 -0
- data/app/javascript/components/Attachments.jsx +165 -0
- data/app/{assets/javascripts/pages/admin/components/date_range_select.jsx → javascript/components/DateRangeSelect.jsx} +16 -5
- data/app/javascript/components/EditableImage.jsx +61 -0
- data/app/javascript/components/FileUploadButton.jsx +47 -0
- data/app/{assets/javascripts/pages/admin/components/focal_point.jsx → javascript/components/ImageCropper/FocalPoint.jsx} +12 -1
- data/app/javascript/components/ImageCropper/Image.jsx +65 -0
- data/app/javascript/components/ImageCropper/Toolbar.jsx +73 -0
- data/app/javascript/components/ImageCropper/useCrop.js +199 -0
- data/app/javascript/components/ImageCropper.jsx +90 -0
- data/app/javascript/components/ImageEditor/Form.jsx +98 -0
- data/app/javascript/components/ImageEditor.jsx +62 -0
- data/app/javascript/components/ImageGrid/DragElement.jsx +30 -0
- data/app/javascript/components/ImageGrid/FilePlaceholder.jsx +9 -0
- data/app/javascript/components/ImageGrid/GridImage.jsx +103 -0
- data/app/javascript/components/ImageGrid/Placeholder.jsx +23 -0
- data/app/javascript/components/ImageGrid.jsx +257 -0
- data/app/javascript/components/ImageUploader.jsx +171 -0
- data/app/{assets/javascripts/pages/admin/components/modal.jsx → javascript/components/Modal.jsx} +13 -2
- data/app/{assets/javascripts/pages/admin/components/page_dates.jsx → javascript/components/PageDates.jsx} +11 -1
- data/app/{assets/javascripts/pages/admin/components/page_files.jsx → javascript/components/PageFiles.jsx} +11 -2
- data/app/{assets/javascripts/pages/admin/components/page_images.jsx → javascript/components/PageImages.jsx} +11 -2
- data/app/{assets/javascripts/pages/admin/components/page_tree_store.jsx → javascript/components/PageTree.jsx} +127 -137
- data/app/{assets/javascripts/pages/admin/components/page_tree.jsx → javascript/components/PageTreeDraggable.jsx} +35 -29
- data/app/{assets/javascripts/pages/admin/components/page_tree_node.jsx → javascript/components/PageTreeNode.jsx} +35 -20
- data/app/javascript/components/RichTextArea.jsx +213 -0
- data/app/javascript/components/RichTextToolbarButton.jsx +20 -0
- data/app/javascript/components/TagEditor/AddTagForm.jsx +42 -0
- data/app/javascript/components/TagEditor/Tag.jsx +32 -0
- data/app/javascript/components/TagEditor.jsx +61 -0
- data/app/javascript/components/Toast.jsx +72 -0
- data/app/javascript/components/drag/draggedOrder.js +51 -0
- data/app/javascript/components/drag/useDragCollection.js +84 -0
- data/app/javascript/components/drag/useDragUploader.js +112 -0
- data/app/javascript/components/drag/useDraggable.js +17 -0
- data/app/javascript/components/drag.js +6 -0
- data/app/javascript/components.js +15 -0
- data/app/javascript/controllers/EditPageController.js +20 -0
- data/app/javascript/controllers/LoginController.js +29 -0
- data/app/javascript/controllers/MainController.js +65 -0
- data/app/javascript/controllers/PageOptionsController.js +62 -0
- data/app/javascript/features/RichText.jsx +34 -0
- data/app/javascript/hooks.js +2 -0
- data/app/javascript/index.js +38 -0
- data/app/{assets/javascripts/pages/admin/lib/tree.jsx → javascript/lib/Tree.js} +55 -54
- data/app/javascript/lib/copyToClipboard.js +13 -0
- data/app/javascript/lib/readyHandler.js +22 -0
- data/app/javascript/lib/request.js +36 -0
- data/app/javascript/stores/ModalStore.jsx +12 -0
- data/app/javascript/stores/ToastStore.jsx +14 -0
- data/app/javascript/stores.js +2 -0
- data/app/models/concerns/pages_core/page_model/images.rb +3 -1
- data/app/models/concerns/pages_core/page_model/searchable.rb +19 -0
- data/app/models/concerns/pages_core/searchable_document.rb +71 -0
- data/app/models/concerns/pages_core/taggable.rb +27 -12
- data/app/models/page.rb +2 -0
- data/app/models/page_exporter.rb +2 -2
- data/app/models/page_image.rb +0 -2
- data/app/models/role.rb +1 -1
- data/app/models/search_document.rb +72 -0
- data/app/models/tag.rb +1 -0
- data/app/models/user.rb +1 -1
- data/app/{serializers/admin/attachment_serializer.rb → resources/admin/attachment_resource.rb} +6 -5
- data/app/{serializers/admin/image_serializer.rb → resources/admin/image_resource.rb} +9 -9
- data/app/resources/admin/page_file_resource.rb +10 -0
- data/app/{serializers/admin/page_image_serializer.rb → resources/admin/page_image_resource.rb} +4 -2
- data/app/resources/export/attachment_resource.rb +10 -0
- data/app/resources/export/page_image_resource.rb +45 -0
- data/app/resources/export/page_resource.rb +42 -0
- data/app/{serializers/page_image_serializer.rb → resources/page_image_resource.rb} +8 -16
- data/app/resources/page_resource.rb +33 -0
- data/app/services/pages_core/destroy_invite_service.rb +2 -2
- data/app/services/pages_core/invite_service.rb +2 -2
- data/app/views/admin/pages/_edit_content.html.erb +1 -1
- data/app/views/admin/pages/_edit_files.html.erb +1 -5
- data/app/views/admin/pages/_edit_images.html.erb +1 -5
- data/app/views/admin/pages/_edit_options.html.erb +74 -55
- data/app/views/admin/pages/_form.html.erb +19 -0
- data/app/views/admin/pages/edit.html.erb +35 -61
- data/app/views/admin/pages/index.html.erb +0 -1
- data/app/views/admin/pages/new.html.erb +32 -32
- data/app/views/admin/users/_access_control.html.erb +5 -1
- data/app/views/admin/users/login.html.erb +12 -4
- data/app/views/feeds/pages.rss.builder +1 -2
- data/app/views/layouts/admin/_header.html.erb +1 -1
- data/app/views/layouts/admin/_page_header.html.erb +33 -0
- data/app/views/layouts/admin.html.erb +23 -42
- data/app/views/pages_core/_google_analytics.html.erb +8 -0
- data/db/migrate/20180625154059_enable_search_extensions.rb +10 -0
- data/db/migrate/20210209151400_create_search_configurations.rb +35 -0
- data/db/migrate/20210210235200_create_search_documents.rb +74 -0
- data/lib/pages_core/engine.rb +1 -5
- data/lib/pages_core/templates/block_configuration.rb +1 -1
- data/lib/pages_core/templates/configuration_handler.rb +1 -1
- data/lib/pages_core/version.rb +3 -1
- data/lib/pages_core.rb +3 -5
- data/lib/rails/generators/pages_core/frontend/frontend_generator.rb +0 -7
- data/lib/rails/generators/pages_core/install/templates/page_templates_initializer.rb +2 -2
- metadata +116 -115
- data/app/assets/javascripts/pages/admin/components/attachment.jsx +0 -130
- data/app/assets/javascripts/pages/admin/components/attachment_editor.jsx +0 -131
- data/app/assets/javascripts/pages/admin/components/attachments.jsx +0 -211
- data/app/assets/javascripts/pages/admin/components/drag_uploader.jsx +0 -174
- data/app/assets/javascripts/pages/admin/components/editable_image.jsx +0 -57
- data/app/assets/javascripts/pages/admin/components/file_upload_button.jsx +0 -44
- data/app/assets/javascripts/pages/admin/components/grid_image.jsx +0 -124
- data/app/assets/javascripts/pages/admin/components/image_editor.jsx +0 -496
- data/app/assets/javascripts/pages/admin/components/image_grid.jsx +0 -306
- data/app/assets/javascripts/pages/admin/components/image_uploader.jsx +0 -176
- data/app/assets/javascripts/pages/admin/components/modal_store.jsx +0 -20
- data/app/assets/javascripts/pages/admin/components/rich_text_area.jsx +0 -64
- data/app/assets/javascripts/pages/admin/components/rich_text_toolbar.jsx +0 -91
- data/app/assets/javascripts/pages/admin/components/toast.jsx +0 -34
- data/app/assets/javascripts/pages/admin/components/toast_store.jsx +0 -52
- data/app/assets/javascripts/pages/admin/components.jsx +0 -2
- data/app/assets/javascripts/pages/admin/features/content_tabs.jsx +0 -72
- data/app/assets/javascripts/pages/admin/features/edit_page.jsx +0 -97
- data/app/assets/javascripts/pages/admin/features/rich_text.jsx +0 -14
- data/app/assets/javascripts/pages/admin/features/tag_editor.jsx +0 -160
- data/app/assets/javascripts/pages/admin.jsx +0 -17
- data/app/assets/javascripts/pages/login_form.jsx +0 -21
- data/app/serializers/admin/page_file_serializer.rb +0 -8
- data/app/serializers/page_export_serializer.rb +0 -32
- data/app/serializers/page_file_export_serializer.rb +0 -6
- data/app/serializers/page_image_export_serializer.rb +0 -42
- data/app/serializers/page_serializer.rb +0 -23
- data/app/views/layouts/admin/_analytics.html.erb +0 -16
- data/lib/rails/generators/pages_core/frontend/templates/application.js.erb +0 -15
- data/vendor/assets/javascripts/ReactCrop.min.js +0 -1
- data/vendor/assets/javascripts/reflux.min.js +0 -1
@@ -0,0 +1,6 @@
|
|
1
|
+
export { default as useDragCollection,
|
2
|
+
createDraggable } from "./drag/useDragCollection";
|
3
|
+
export { default as useDragUploader } from "./drag/useDragUploader";
|
4
|
+
export { default as useDraggable } from "./drag/useDraggable";
|
5
|
+
export { default as draggedOrder,
|
6
|
+
collectionOrder } from "./drag/draggedOrder";
|
@@ -0,0 +1,15 @@
|
|
1
|
+
export { default as Attachments } from "./components/Attachments";
|
2
|
+
export { default as DateRangeSelect } from "./components/DateRangeSelect";
|
3
|
+
export { default as EditableImage } from "./components/EditableImage";
|
4
|
+
export { default as FileUploadButton } from "./components/FileUploadButton";
|
5
|
+
export { default as ImageCropper } from "./components/ImageCropper";
|
6
|
+
export { default as ImageGrid } from "./components/ImageGrid";
|
7
|
+
export { default as ImageUploader } from "./components/ImageUploader";
|
8
|
+
export { default as Modal } from "./components/Modal";
|
9
|
+
export { default as PageDates } from "./components/PageDates";
|
10
|
+
export { default as PageFiles } from "./components/PageFiles";
|
11
|
+
export { default as PageImages } from "./components/PageImages";
|
12
|
+
export { default as PageTree } from "./components/PageTree";
|
13
|
+
export { default as RichTextArea } from "./components/RichTextArea";
|
14
|
+
export { default as TagEditor } from "./components/TagEditor";
|
15
|
+
export { default as Toast } from "./components/Toast";
|
@@ -0,0 +1,20 @@
|
|
1
|
+
import { Controller } from "stimulus";
|
2
|
+
|
3
|
+
export default class EditPageController extends Controller {
|
4
|
+
static get targets() {
|
5
|
+
return ["form"];
|
6
|
+
}
|
7
|
+
|
8
|
+
preview() {
|
9
|
+
const form = this.formTarget;
|
10
|
+
const prevAction = form.action;
|
11
|
+
const prevTarget = form.target;
|
12
|
+
|
13
|
+
form.target = "_blank";
|
14
|
+
form.action = form.dataset.previewUrl;
|
15
|
+
form.submit();
|
16
|
+
|
17
|
+
form.action = prevAction;
|
18
|
+
form.target = prevTarget;
|
19
|
+
}
|
20
|
+
}
|
@@ -0,0 +1,29 @@
|
|
1
|
+
import { Controller } from "stimulus";
|
2
|
+
|
3
|
+
export default class LoginController extends Controller {
|
4
|
+
static get targets() {
|
5
|
+
return ["tab"];
|
6
|
+
}
|
7
|
+
|
8
|
+
connect() {
|
9
|
+
if (this.tabTargets.length > 0) {
|
10
|
+
this.showTab(this.tabTargets[0].dataset.tab);
|
11
|
+
}
|
12
|
+
}
|
13
|
+
|
14
|
+
|
15
|
+
changeTab(evt) {
|
16
|
+
evt.preventDefault();
|
17
|
+
this.showTab(evt.target.dataset.tab);
|
18
|
+
}
|
19
|
+
|
20
|
+
showTab(tab) {
|
21
|
+
this.tabTargets.forEach((t) => {
|
22
|
+
if (t.dataset.tab == tab) {
|
23
|
+
t.classList.remove("hidden");
|
24
|
+
} else {
|
25
|
+
t.classList.add("hidden");
|
26
|
+
}
|
27
|
+
});
|
28
|
+
}
|
29
|
+
}
|
@@ -0,0 +1,65 @@
|
|
1
|
+
import { Controller } from "stimulus";
|
2
|
+
|
3
|
+
export default class MainController extends Controller {
|
4
|
+
static get targets() {
|
5
|
+
return ["tab", "link"];
|
6
|
+
}
|
7
|
+
|
8
|
+
connect() {
|
9
|
+
let tabs = this.tabNames();
|
10
|
+
if (tabs.length > 0) {
|
11
|
+
let initTab = null;
|
12
|
+
const tabExpression = /#(.*)$/;
|
13
|
+
|
14
|
+
if (document.location.toString().match(tabExpression)) {
|
15
|
+
let id = document.location.toString().match(tabExpression)[1];
|
16
|
+
if (tabs.indexOf(id) !== -1) {
|
17
|
+
initTab = id;
|
18
|
+
}
|
19
|
+
}
|
20
|
+
|
21
|
+
this.showTab(initTab || tabs[0]);
|
22
|
+
}
|
23
|
+
|
24
|
+
window.addEventListener("popstate", this.stateHandler.bind(this));
|
25
|
+
}
|
26
|
+
|
27
|
+
disconnect() {
|
28
|
+
window.removeEventListener("popstate", this.stateHandler.bind(this));
|
29
|
+
}
|
30
|
+
|
31
|
+
stateHandler(evt) {
|
32
|
+
if (evt.state && evt.state.tabId) {
|
33
|
+
this.showTab(evt.state.tabId);
|
34
|
+
}
|
35
|
+
}
|
36
|
+
|
37
|
+
changeTab(evt) {
|
38
|
+
evt.preventDefault();
|
39
|
+
const tab = evt.target.dataset.tab;
|
40
|
+
this.showTab(tab);
|
41
|
+
history.pushState({ tabId: tab }, "", `${window.location.pathname}#${tab}`);
|
42
|
+
}
|
43
|
+
|
44
|
+
showTab(tab) {
|
45
|
+
this.linkTargets.forEach((l) => {
|
46
|
+
if (l.dataset.tab == tab) {
|
47
|
+
l.classList.add("current");
|
48
|
+
} else {
|
49
|
+
l.classList.remove("current");
|
50
|
+
}
|
51
|
+
});
|
52
|
+
|
53
|
+
this.tabTargets.forEach((t) => {
|
54
|
+
if (t.dataset.tab == tab) {
|
55
|
+
t.classList.remove("hidden");
|
56
|
+
} else {
|
57
|
+
t.classList.add("hidden");
|
58
|
+
}
|
59
|
+
});
|
60
|
+
}
|
61
|
+
|
62
|
+
tabNames () {
|
63
|
+
return this.linkTargets.map((l) => l.dataset.tab);
|
64
|
+
}
|
65
|
+
}
|
@@ -0,0 +1,62 @@
|
|
1
|
+
import { Controller } from "stimulus";
|
2
|
+
|
3
|
+
export default class PageOptionsController extends Controller {
|
4
|
+
static get targets() {
|
5
|
+
return ["advancedOptions", "autoPublishNotice", "published", "publishedDate"];
|
6
|
+
}
|
7
|
+
|
8
|
+
connect() {
|
9
|
+
this.checkAutoPublish();
|
10
|
+
this.checkPublishedDate();
|
11
|
+
}
|
12
|
+
|
13
|
+
checkAutoPublish() {
|
14
|
+
if (this.publishedDate() > new Date()) {
|
15
|
+
this.show(this.autoPublishNoticeTarget);
|
16
|
+
} else {
|
17
|
+
this.hide(this.autoPublishNoticeTarget);
|
18
|
+
}
|
19
|
+
}
|
20
|
+
|
21
|
+
checkPublishedDate() {
|
22
|
+
if (this.publishedTarget.value == 2) {
|
23
|
+
this.show(this.publishedDateTarget);
|
24
|
+
} else {
|
25
|
+
this.hide(this.publishedDateTarget);
|
26
|
+
}
|
27
|
+
}
|
28
|
+
|
29
|
+
publishedDate() {
|
30
|
+
const lookup = (name) => {
|
31
|
+
return this.publishedDateTarget.getElementsByClassName(name)[0].value;
|
32
|
+
};
|
33
|
+
return new Date(
|
34
|
+
lookup("year"),
|
35
|
+
(lookup("month") - 1),
|
36
|
+
lookup("day"),
|
37
|
+
lookup("hour"),
|
38
|
+
lookup("minute")
|
39
|
+
);
|
40
|
+
}
|
41
|
+
|
42
|
+
show(elem) {
|
43
|
+
elem.classList.add("show");
|
44
|
+
}
|
45
|
+
|
46
|
+
hide(elem) {
|
47
|
+
elem.classList.remove("show");
|
48
|
+
}
|
49
|
+
|
50
|
+
toggle(elem) {
|
51
|
+
if (elem.classList.contains("show")) {
|
52
|
+
this.hide(elem);
|
53
|
+
} else {
|
54
|
+
this.show(elem);
|
55
|
+
}
|
56
|
+
}
|
57
|
+
|
58
|
+
toggleAdvancedOptions(evt) {
|
59
|
+
evt.preventDefault();
|
60
|
+
this.toggle(this.advancedOptionsTarget);
|
61
|
+
}
|
62
|
+
}
|
@@ -0,0 +1,34 @@
|
|
1
|
+
import React from "react";
|
2
|
+
import ReactDOM from "react-dom";
|
3
|
+
import RichTextArea from "../components/RichTextArea";
|
4
|
+
import readyHandler from "../lib/readyHandler";
|
5
|
+
|
6
|
+
class RichText {
|
7
|
+
apply () {
|
8
|
+
const elems = document.querySelectorAll("textarea.rich");
|
9
|
+
elems.forEach((elem) => {
|
10
|
+
this.enhance(elem);
|
11
|
+
});
|
12
|
+
}
|
13
|
+
|
14
|
+
enhance (elem) {
|
15
|
+
const container = document.createElement("div");
|
16
|
+
elem.parentNode.appendChild(container);
|
17
|
+
ReactDOM.render(
|
18
|
+
<RichTextArea value={elem.value}
|
19
|
+
name={elem.name}
|
20
|
+
rows={elem.rows}
|
21
|
+
id={elem.id} />,
|
22
|
+
container
|
23
|
+
);
|
24
|
+
elem.parentNode.removeChild(elem);
|
25
|
+
}
|
26
|
+
|
27
|
+
start () {
|
28
|
+
readyHandler.ready(() => {
|
29
|
+
this.apply();
|
30
|
+
});
|
31
|
+
}
|
32
|
+
}
|
33
|
+
|
34
|
+
export default new RichText();
|
@@ -0,0 +1,38 @@
|
|
1
|
+
import Rails from "@rails/ujs";
|
2
|
+
import { Application } from "stimulus";
|
3
|
+
require("react_ujs");
|
4
|
+
|
5
|
+
import * as Components from "./components";
|
6
|
+
|
7
|
+
import EditPageController from "./controllers/EditPageController";
|
8
|
+
import MainController from "./controllers/MainController";
|
9
|
+
import LoginController from "./controllers/LoginController";
|
10
|
+
import PageOptionsController from "./controllers/PageOptionsController";
|
11
|
+
|
12
|
+
import RichText from "./features/RichText";
|
13
|
+
|
14
|
+
export function registerComponent(name, component) {
|
15
|
+
window[name] = component;
|
16
|
+
}
|
17
|
+
|
18
|
+
export default function startPages () {
|
19
|
+
Rails.start();
|
20
|
+
for (var name in Components) {
|
21
|
+
registerComponent(name, Components[name]);
|
22
|
+
}
|
23
|
+
RichText.start();
|
24
|
+
|
25
|
+
const application = Application.start();
|
26
|
+
application.register("edit-page", EditPageController);
|
27
|
+
application.register("main", MainController);
|
28
|
+
application.register("login", LoginController);
|
29
|
+
application.register("page-options", PageOptionsController);
|
30
|
+
}
|
31
|
+
|
32
|
+
export * from "./components";
|
33
|
+
export * from "./hooks";
|
34
|
+
export * from "./stores";
|
35
|
+
|
36
|
+
export * from "./lib/request.js";
|
37
|
+
export { default as copyToClipboard,
|
38
|
+
copySupported } from "./lib/copyToClipboard";
|
@@ -1,55 +1,56 @@
|
|
1
1
|
/*
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
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
|
+
|
53
|
+
export default class Tree {
|
53
54
|
constructor(obj) {
|
54
55
|
this.cnt = 1;
|
55
56
|
this.obj = obj || { children: [] };
|
@@ -72,7 +73,7 @@ class Tree {
|
|
72
73
|
|
73
74
|
function walk(objs, parent) {
|
74
75
|
var children = [];
|
75
|
-
objs.forEach(function(obj
|
76
|
+
objs.forEach(function(obj) {
|
76
77
|
var index = {};
|
77
78
|
index.id = self.cnt;
|
78
79
|
index.node = obj;
|
@@ -276,7 +277,7 @@ class Tree {
|
|
276
277
|
|
277
278
|
getParent(id) {
|
278
279
|
var indexes = this.indexes;
|
279
|
-
if (
|
280
|
+
if (Object.prototype.hasOwnProperty.call(indexes, id)) {
|
280
281
|
return this.getIndex(indexes[id].parent);
|
281
282
|
}
|
282
283
|
}
|
@@ -284,7 +285,7 @@ class Tree {
|
|
284
285
|
getNodeByTop(top) {
|
285
286
|
var indexes = this.indexes;
|
286
287
|
for(var id in indexes) {
|
287
|
-
if (
|
288
|
+
if (Object.prototype.hasOwnProperty.call(indexes, id)) {
|
288
289
|
if(indexes[id].top === top) {
|
289
290
|
return indexes[id];
|
290
291
|
}
|
@@ -0,0 +1,13 @@
|
|
1
|
+
export function copySupported () {
|
2
|
+
return document.queryCommandSupported &&
|
3
|
+
document.queryCommandSupported("copy");
|
4
|
+
}
|
5
|
+
|
6
|
+
export default function copyToClipboard (str) {
|
7
|
+
const el = document.createElement("textarea");
|
8
|
+
el.value = str;
|
9
|
+
document.body.appendChild(el);
|
10
|
+
el.select();
|
11
|
+
document.execCommand("copy");
|
12
|
+
document.body.removeChild(el);
|
13
|
+
}
|
@@ -0,0 +1,22 @@
|
|
1
|
+
let readyHandlers = [];
|
2
|
+
|
3
|
+
const handleState = () => {
|
4
|
+
if (["interactive", "complete"].indexOf(document.readyState) > -1) {
|
5
|
+
while(readyHandlers.length > 0) {
|
6
|
+
(readyHandlers.shift())();
|
7
|
+
}
|
8
|
+
}
|
9
|
+
};
|
10
|
+
|
11
|
+
class ReadyHandler {
|
12
|
+
constructor () {
|
13
|
+
document.onreadystatechange = handleState;
|
14
|
+
}
|
15
|
+
|
16
|
+
ready (handler) {
|
17
|
+
readyHandlers.push(handler);
|
18
|
+
handleState();
|
19
|
+
}
|
20
|
+
}
|
21
|
+
|
22
|
+
export default new ReadyHandler();
|
@@ -0,0 +1,36 @@
|
|
1
|
+
export function csrfToken() {
|
2
|
+
return document.querySelector("[name=csrf-token]").content;
|
3
|
+
}
|
4
|
+
|
5
|
+
function jsonFetchOptions() {
|
6
|
+
return({ method: "POST",
|
7
|
+
headers: { "Content-Type": "application/json; charset=utf-8",
|
8
|
+
"X-CSRF-Token": csrfToken() } });
|
9
|
+
}
|
10
|
+
|
11
|
+
export async function postJson(url, data) {
|
12
|
+
const options = { ...jsonFetchOptions(), method: "POST" };
|
13
|
+
if (data) {
|
14
|
+
options.body = JSON.stringify(data);
|
15
|
+
}
|
16
|
+
const response = await fetch(url, options);
|
17
|
+
return response.json();
|
18
|
+
}
|
19
|
+
|
20
|
+
export async function putJson(url, data) {
|
21
|
+
const options = { ...jsonFetchOptions(), method: "PUT" };
|
22
|
+
if (data) {
|
23
|
+
options.body = JSON.stringify(data);
|
24
|
+
}
|
25
|
+
const response = await fetch(url, options);
|
26
|
+
return response.json();
|
27
|
+
}
|
28
|
+
|
29
|
+
export async function post(url, data) {
|
30
|
+
const response = await fetch(url, {
|
31
|
+
method: "POST",
|
32
|
+
body: data,
|
33
|
+
headers: { "X-CSRF-Token": csrfToken() }
|
34
|
+
});
|
35
|
+
return response.json();
|
36
|
+
}
|
@@ -0,0 +1,12 @@
|
|
1
|
+
import { createStore } from "redux";
|
2
|
+
|
3
|
+
export default createStore((state = {}, action) => {
|
4
|
+
switch(action.type) {
|
5
|
+
case "OPEN":
|
6
|
+
return {...state, component: action.payload };
|
7
|
+
case "CLOSE":
|
8
|
+
return {...state, component: null };
|
9
|
+
default:
|
10
|
+
return state;
|
11
|
+
}
|
12
|
+
});
|
@@ -0,0 +1,14 @@
|
|
1
|
+
import { createStore } from "redux";
|
2
|
+
|
3
|
+
export default createStore((state = [], action) => {
|
4
|
+
switch(action.type) {
|
5
|
+
case "ERROR":
|
6
|
+
return [...state, { message: action.message, type: "error" }];
|
7
|
+
case "NOTICE":
|
8
|
+
return [...state, { message: action.message, type: "notice" }];
|
9
|
+
case "NEXT":
|
10
|
+
return state.slice(1);
|
11
|
+
default:
|
12
|
+
return state;
|
13
|
+
}
|
14
|
+
});
|
@@ -8,7 +8,9 @@ module PagesCore
|
|
8
8
|
included do
|
9
9
|
belongs_to_image :image, optional: true
|
10
10
|
belongs_to_image :meta_image, class_name: "Image", optional: true
|
11
|
-
has_many :page_images, -> { order("position") },
|
11
|
+
has_many :page_images, -> { order("position") },
|
12
|
+
inverse_of: :page,
|
13
|
+
dependent: :destroy
|
12
14
|
has_many(
|
13
15
|
:images,
|
14
16
|
-> { where(page_images: { primary: false }).order("position") },
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PagesCore
|
4
|
+
module PageModel
|
5
|
+
module Searchable
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
def search_document_attributes
|
9
|
+
super.merge(
|
10
|
+
published: published?,
|
11
|
+
name: name,
|
12
|
+
description: try(&:meta_description?) ? meta_description : excerpt,
|
13
|
+
# content: "",
|
14
|
+
tags: tag_names.join(" ")
|
15
|
+
)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PagesCore
|
4
|
+
module SearchableDocument
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
has_many :search_documents, as: :searchable, dependent: :destroy
|
9
|
+
after_save :update_search_documents!
|
10
|
+
end
|
11
|
+
|
12
|
+
class Indexer
|
13
|
+
attr_reader :record
|
14
|
+
|
15
|
+
def initialize(record)
|
16
|
+
@record = record
|
17
|
+
end
|
18
|
+
|
19
|
+
class << self
|
20
|
+
def index_all!(scope)
|
21
|
+
scope.all.find_each { |r| new(r).index! }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def index!
|
26
|
+
SearchDocument.transaction do
|
27
|
+
record.search_documents.where.not(locale: locales).destroy_all
|
28
|
+
locales.each do |locale|
|
29
|
+
update_index(
|
30
|
+
locale,
|
31
|
+
localized_record(locale).search_document_attributes
|
32
|
+
)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def locales
|
40
|
+
if record.respond_to?(:locales)
|
41
|
+
record.locales
|
42
|
+
elsif PagesCore.config.locales
|
43
|
+
PagesCore.config.locales.keys
|
44
|
+
else
|
45
|
+
[I18n.default_locale]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def localized_record(locale)
|
50
|
+
return record unless record.respond_to?(:localize)
|
51
|
+
|
52
|
+
record.localize(locale)
|
53
|
+
end
|
54
|
+
|
55
|
+
def update_index(locale, attrs)
|
56
|
+
record.search_documents.create_or_find_by!(locale: locale).update(attrs)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def search_document_attributes
|
61
|
+
return {} unless respond_to?(:localized_attributes)
|
62
|
+
|
63
|
+
content = localized_attributes.keys.map { |a| localizer.get(a) }.join(" ")
|
64
|
+
{ content: content }
|
65
|
+
end
|
66
|
+
|
67
|
+
def update_search_documents!
|
68
|
+
PagesCore::SearchableDocument::Indexer.new(self).index!
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|