pages_core 3.12.4 → 3.12.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/app/assets/builds/fonts/2a3059ad.ttf +0 -0
- data/app/assets/builds/fonts/47262711.woff2 +0 -0
- data/app/assets/builds/fonts/500ddeb0.woff2 +0 -0
- data/app/assets/builds/fonts/81221036.ttf +0 -0
- data/app/assets/builds/pages_core/admin-dist.js +8 -43
- data/app/assets/builds/pages_core/admin-dist.js.map +4 -4
- data/app/assets/builds/pages_core/admin.css +270 -140
- data/app/assets/stylesheets/pages_core/admin/components/attachments.css +3 -4
- data/app/assets/stylesheets/pages_core/admin/components/forms.css +17 -16
- data/app/assets/stylesheets/pages_core/admin/components/image_editor.css +8 -4
- data/app/assets/stylesheets/pages_core/admin/components/image_grid.css +1 -1
- data/app/assets/stylesheets/pages_core/admin/components/list_table.css +11 -3
- data/app/assets/stylesheets/pages_core/admin/components/modal.css +9 -5
- data/app/assets/stylesheets/pages_core/admin/components/page_tree.css +5 -1
- data/app/assets/stylesheets/pages_core/admin/components/toast.css +2 -2
- data/app/assets/stylesheets/pages_core/admin/controllers/pages.css +4 -2
- data/app/assets/stylesheets/pages_core/admin/vars.css +2 -1
- data/app/controllers/admin/calendars_controller.rb +2 -2
- data/app/controllers/admin/categories_controller.rb +3 -3
- data/app/controllers/admin/news_controller.rb +6 -6
- data/app/controllers/admin/pages_controller.rb +12 -11
- data/app/controllers/admin/users_controller.rb +1 -1
- data/app/controllers/concerns/pages_core/preview_pages_controller.rb +15 -17
- data/app/controllers/pages_core/admin_controller.rb +2 -2
- data/app/controllers/pages_core/base_controller.rb +1 -8
- data/app/controllers/pages_core/frontend/pages_controller.rb +13 -5
- data/app/controllers/pages_core/frontend_controller.rb +12 -7
- data/app/helpers/admin/menu_helper.rb +2 -0
- data/app/helpers/admin/pages_helper.rb +1 -4
- data/app/helpers/pages_core/admin/admin_helper.rb +0 -1
- data/app/helpers/pages_core/admin/content_tabs_helper.rb +9 -2
- data/app/helpers/pages_core/application_helper.rb +2 -3
- data/app/helpers/pages_core/frontend_helper.rb +1 -1
- data/app/helpers/pages_core/head_tags_helper.rb +15 -46
- data/app/helpers/pages_core/images_helper.rb +76 -21
- data/app/helpers/pages_core/locales_helper.rb +9 -0
- data/app/helpers/pages_core/open_graph_tags_helper.rb +3 -5
- data/app/helpers/pages_core/page_path_helper.rb +1 -1
- data/app/javascript/components/Attachments/Attachment.tsx +55 -52
- data/app/javascript/components/Attachments/AttachmentEditor.tsx +45 -50
- data/app/javascript/components/Attachments/Placeholder.tsx +1 -2
- data/app/javascript/components/Attachments.jsx +69 -57
- data/app/javascript/components/DateRangeSelect.jsx +94 -54
- data/app/javascript/components/EditableImage.tsx +20 -16
- data/app/javascript/components/FileUploadButton.tsx +12 -12
- data/app/javascript/components/ImageCropper/FocalPoint.tsx +22 -20
- data/app/javascript/components/ImageCropper/Image.tsx +20 -16
- data/app/javascript/components/ImageCropper/Toolbar.tsx +35 -27
- data/app/javascript/components/ImageCropper/useCrop.ts +105 -91
- data/app/javascript/components/ImageCropper.tsx +34 -25
- data/app/javascript/components/ImageEditor/Form.tsx +32 -43
- data/app/javascript/components/ImageEditor.tsx +29 -21
- data/app/javascript/components/ImageGrid/DragElement.tsx +6 -4
- data/app/javascript/components/ImageGrid/GridImage.tsx +56 -52
- data/app/javascript/components/ImageGrid/Placeholder.tsx +1 -1
- data/app/javascript/components/ImageGrid.jsx +132 -101
- data/app/javascript/components/ImageUploader.tsx +59 -55
- data/app/javascript/components/Modal.tsx +2 -4
- data/app/javascript/components/PageDates.jsx +25 -20
- data/app/javascript/components/PageFiles.jsx +7 -5
- data/app/javascript/components/PageImages.tsx +9 -7
- data/app/javascript/components/PageTree/Draggable.tsx +46 -40
- data/app/javascript/components/PageTree/Node.tsx +111 -95
- data/app/javascript/components/PageTree/types.ts +9 -9
- data/app/javascript/components/PageTree.tsx +44 -29
- data/app/javascript/components/RichTextArea.jsx +51 -37
- data/app/javascript/components/RichTextToolbarButton.tsx +8 -5
- data/app/javascript/components/TagEditor/AddTagForm.tsx +11 -10
- data/app/javascript/components/TagEditor/Tag.tsx +10 -8
- data/app/javascript/components/TagEditor.tsx +15 -10
- data/app/javascript/components/Toast.tsx +3 -7
- data/app/javascript/components/drag/draggedOrder.ts +16 -15
- data/app/javascript/components/drag/types.ts +12 -12
- data/app/javascript/components/drag/useDragCollection.ts +36 -42
- data/app/javascript/components/drag/useDragUploader.ts +3 -2
- data/app/javascript/components/drag.ts +5 -4
- data/app/javascript/controllers/EditPageController.ts +1 -1
- data/app/javascript/controllers/LoginController.ts +1 -2
- data/app/javascript/controllers/MainController.ts +8 -4
- data/app/javascript/controllers/PageOptionsController.js +7 -2
- data/app/javascript/features/RichText.tsx +9 -7
- data/app/javascript/index.ts +5 -3
- data/app/javascript/lib/Tree.ts +27 -24
- data/app/javascript/lib/copyToClipboard.ts +5 -4
- data/app/javascript/lib/readyHandler.ts +4 -4
- data/app/javascript/lib/request.ts +7 -3
- data/app/javascript/stores/useModalStore.ts +3 -3
- data/app/javascript/stores/useToastStore.ts +14 -12
- data/app/javascript/types.ts +22 -22
- data/app/models/concerns/pages_core/page_model/templateable.rb +1 -1
- data/app/views/admin/calendars/show.html.erb +1 -1
- data/app/views/admin/news/index.html.erb +1 -1
- data/app/views/admin/pages/_edit_files.html.erb +1 -1
- data/app/views/admin/pages/_edit_images.html.erb +1 -1
- data/app/views/admin/pages/_list_item.html.erb +1 -1
- data/app/views/admin/pages/_search_bar.html.erb +1 -1
- data/app/views/admin/pages/deleted.html.erb +2 -2
- data/app/views/admin/pages/edit.html.erb +3 -3
- data/app/views/admin/pages/index.html.erb +4 -4
- data/app/views/admin/pages/new.html.erb +1 -1
- data/app/views/admin/pages/search.html.erb +3 -3
- data/app/views/feeds/pages.rss.builder +2 -2
- data/app/views/layouts/admin/_page_header.html.erb +4 -4
- data/app/views/layouts/admin.html.erb +1 -2
- data/config/locales/en.yml +1 -0
- data/lib/pages_core/pages_plugin.rb +5 -3
- data/lib/rails/generators/pages_core/frontend/templates/application.html.erb +15 -13
- data/lib/tasks/pages/reports.rake +26 -0
- metadata +36 -8
- data/app/assets/builds/fonts/661557ef.ttf +0 -0
- data/app/assets/builds/fonts/a18fc2d2.woff2 +0 -0
- data/app/assets/builds/fonts/b2c7b78f.woff2 +0 -0
- data/app/assets/builds/fonts/ceddc204.ttf +0 -0
- data/app/helpers/pages_core/admin/deprecated_admin_helper.rb +0 -40
- data/app/views/pages_core/_google_analytics.html.erb +0 -8
@@ -5,31 +5,36 @@ import { Attributes, PageNode } from "./PageTree/types";
|
|
5
5
|
import Draggable from "./PageTree/Draggable";
|
6
6
|
|
7
7
|
interface Page extends Record<string, unknown> {
|
8
|
-
parent_page_id: number | null
|
8
|
+
parent_page_id: number | null;
|
9
9
|
}
|
10
10
|
|
11
11
|
type CollapsedState = Record<number, boolean>;
|
12
12
|
|
13
13
|
interface ParentMap {
|
14
|
-
[index: number]: Page[]
|
14
|
+
[index: number]: Page[];
|
15
15
|
}
|
16
16
|
|
17
17
|
interface PageTreeProps {
|
18
|
-
dir: string
|
19
|
-
locale: string
|
20
|
-
pages: Page[]
|
21
|
-
permissions: string[]
|
18
|
+
dir: string;
|
19
|
+
locale: string;
|
20
|
+
pages: Page[];
|
21
|
+
permissions: string[];
|
22
22
|
}
|
23
23
|
|
24
24
|
interface PageTreeState {
|
25
|
-
tree: Tree<PageNode
|
25
|
+
tree: Tree<PageNode>;
|
26
26
|
}
|
27
27
|
|
28
28
|
function collapsedState(): CollapsedState {
|
29
|
-
if (
|
30
|
-
|
31
|
-
|
32
|
-
|
29
|
+
if (
|
30
|
+
window &&
|
31
|
+
window.localStorage &&
|
32
|
+
typeof window.localStorage.collapsedPages != "undefined"
|
33
|
+
) {
|
34
|
+
return JSON.parse(
|
35
|
+
window.localStorage.getItem("collapsedPages")
|
36
|
+
) as CollapsedState;
|
37
|
+
}
|
33
38
|
return {};
|
34
39
|
}
|
35
40
|
|
@@ -62,15 +67,16 @@ export default class PageTree extends Component<PageTreeProps, PageTreeState> {
|
|
62
67
|
node.collapsed = true;
|
63
68
|
}
|
64
69
|
if (index.children && index.children.length) {
|
65
|
-
index.children.forEach(c => walk(c));
|
70
|
+
index.children.forEach((c) => walk(c));
|
66
71
|
}
|
67
72
|
};
|
68
73
|
walk(1);
|
69
74
|
}
|
70
75
|
|
71
76
|
createPage(index: TreeIndex<PageNode>, attributes: Attributes) {
|
72
|
-
void postJson(`/admin/${index.node.locale}/pages.json`, {
|
73
|
-
|
77
|
+
void postJson(`/admin/${index.node.locale}/pages.json`, {
|
78
|
+
page: attributes
|
79
|
+
}).then((response: Attributes) => this.updateNode(index, response));
|
74
80
|
}
|
75
81
|
|
76
82
|
buildTree(pages: Page[]) {
|
@@ -81,7 +87,9 @@ export default class PageTree extends Component<PageTreeProps, PageTreeState> {
|
|
81
87
|
return m;
|
82
88
|
}, {});
|
83
89
|
|
84
|
-
pages.forEach((p: Page) => {
|
90
|
+
pages.forEach((p: Page) => {
|
91
|
+
p.children = parentMap[p.id] || [];
|
92
|
+
});
|
85
93
|
|
86
94
|
const tree = new Tree({
|
87
95
|
name: "All Pages",
|
@@ -95,7 +103,11 @@ export default class PageTree extends Component<PageTreeProps, PageTreeState> {
|
|
95
103
|
return tree;
|
96
104
|
}
|
97
105
|
|
98
|
-
movePage(
|
106
|
+
movePage(
|
107
|
+
index: TreeIndex<PageNode>,
|
108
|
+
parent: TreeIndex<PageNode>,
|
109
|
+
position: number
|
110
|
+
) {
|
99
111
|
const data = {
|
100
112
|
parent_id: parent.node.id,
|
101
113
|
position: position
|
@@ -105,8 +117,9 @@ export default class PageTree extends Component<PageTreeProps, PageTreeState> {
|
|
105
117
|
}
|
106
118
|
|
107
119
|
performUpdate(index: TreeIndex, url: string, data: Attributes) {
|
108
|
-
void putJson(url, data)
|
109
|
-
|
120
|
+
void putJson(url, data).then((response: Page) =>
|
121
|
+
this.updateNode(index, response)
|
122
|
+
);
|
110
123
|
}
|
111
124
|
|
112
125
|
render() {
|
@@ -116,7 +129,7 @@ export default class PageTree extends Component<PageTreeProps, PageTreeState> {
|
|
116
129
|
this.reorderChildren(id);
|
117
130
|
this.setCollapsed(id, false);
|
118
131
|
this.createPage(index, attributes);
|
119
|
-
this.setState({tree: tree});
|
132
|
+
this.setState({ tree: tree });
|
120
133
|
};
|
121
134
|
|
122
135
|
const movedPage = (id: TreeId) => {
|
@@ -135,7 +148,7 @@ export default class PageTree extends Component<PageTreeProps, PageTreeState> {
|
|
135
148
|
const tree = this.state.tree;
|
136
149
|
const node = tree.getIndex(id).node;
|
137
150
|
this.setCollapsed(id, !node.collapsed);
|
138
|
-
this.setState({tree: tree});
|
151
|
+
this.setState({ tree: tree });
|
139
152
|
};
|
140
153
|
|
141
154
|
const updatePage = (id: TreeId, attributes: Attributes) => {
|
@@ -150,15 +163,17 @@ export default class PageTree extends Component<PageTreeProps, PageTreeState> {
|
|
150
163
|
this.setState({ tree: tree });
|
151
164
|
};
|
152
165
|
|
153
|
-
return(
|
154
|
-
<Draggable
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
166
|
+
return (
|
167
|
+
<Draggable
|
168
|
+
tree={this.state.tree}
|
169
|
+
addChild={addChild}
|
170
|
+
movedPage={movedPage}
|
171
|
+
toggleCollapsed={toggleCollapsed}
|
172
|
+
updatePage={updatePage}
|
173
|
+
updateTree={updateTree}
|
174
|
+
locale={this.props.locale}
|
175
|
+
dir={this.props.dir}
|
176
|
+
/>
|
162
177
|
);
|
163
178
|
}
|
164
179
|
|
@@ -20,59 +20,60 @@ export default class RichTextArea extends React.Component {
|
|
20
20
|
actions() {
|
21
21
|
const simple = [
|
22
22
|
{
|
23
|
-
name:
|
23
|
+
name: "bold",
|
24
24
|
className: "bold",
|
25
|
-
hotkey:
|
26
|
-
fn:
|
25
|
+
hotkey: "b",
|
26
|
+
fn: (str) => ["<b>", str, "</b>"]
|
27
27
|
},
|
28
|
-
{
|
28
|
+
{
|
29
|
+
name: "italic",
|
29
30
|
className: "italic",
|
30
|
-
hotkey:
|
31
|
-
fn:
|
32
|
-
}
|
31
|
+
hotkey: "i",
|
32
|
+
fn: (str) => ["<i>", str, "</i>"]
|
33
|
+
}
|
33
34
|
];
|
34
35
|
|
35
36
|
const advanced = [
|
36
37
|
{
|
37
|
-
name:
|
38
|
+
name: "Heading 2",
|
38
39
|
className: "header h2",
|
39
|
-
fn:
|
40
|
+
fn: (str) => ["h2. ", str, ""]
|
40
41
|
},
|
41
42
|
{
|
42
|
-
name:
|
43
|
+
name: "Heading 3",
|
43
44
|
className: "header h3",
|
44
|
-
fn:
|
45
|
+
fn: (str) => ["h3. ", str, ""]
|
45
46
|
},
|
46
47
|
{
|
47
|
-
name:
|
48
|
+
name: "Heading 4",
|
48
49
|
className: "header h4",
|
49
|
-
fn:
|
50
|
+
fn: (str) => ["h4. ", str, ""]
|
50
51
|
},
|
51
52
|
{
|
52
|
-
name:
|
53
|
+
name: "Blockquote",
|
53
54
|
className: "quote-left",
|
54
|
-
fn:
|
55
|
+
fn: (str) => ["bq. ", str, ""]
|
55
56
|
},
|
56
57
|
{
|
57
|
-
name:
|
58
|
+
name: "List",
|
58
59
|
className: "list-ul",
|
59
|
-
fn:
|
60
|
+
fn: (str) => ["", this.strToList(str, "*"), ""]
|
60
61
|
},
|
61
62
|
{
|
62
|
-
name:
|
63
|
+
name: "Ordered list",
|
63
64
|
className: "list-ol",
|
64
|
-
fn:
|
65
|
+
fn: (str) => ["", this.strToList(str, "#"), ""]
|
65
66
|
},
|
66
67
|
{
|
67
|
-
name:
|
68
|
+
name: "Link",
|
68
69
|
className: "link",
|
69
|
-
fn:
|
70
|
+
fn: this.link
|
70
71
|
},
|
71
72
|
{
|
72
|
-
name:
|
73
|
+
name: "Email link",
|
73
74
|
className: "envelope",
|
74
|
-
fn:
|
75
|
-
}
|
75
|
+
fn: this.emailLink
|
76
|
+
}
|
76
77
|
];
|
77
78
|
|
78
79
|
return this.props.simple ? simple : [...simple, ...advanced];
|
@@ -86,12 +87,12 @@ export default class RichTextArea extends React.Component {
|
|
86
87
|
emailLink(selection) {
|
87
88
|
var address = prompt("Enter email address", "");
|
88
89
|
let name = selection.length > 0 ? selection : address;
|
89
|
-
return ["
|
90
|
+
return ['"', name, `":mailto:${address}`];
|
90
91
|
}
|
91
92
|
|
92
93
|
getSelection() {
|
93
94
|
let { selectionStart, selectionEnd, value } = this.inputRef.current;
|
94
|
-
return value.substr(selectionStart,
|
95
|
+
return value.substr(selectionStart, selectionEnd - selectionStart);
|
95
96
|
}
|
96
97
|
|
97
98
|
handleChange(evt) {
|
@@ -107,13 +108,16 @@ export default class RichTextArea extends React.Component {
|
|
107
108
|
}
|
108
109
|
|
109
110
|
let hotkeys = {};
|
110
|
-
this.actions().forEach(a => {
|
111
|
+
this.actions().forEach((a) => {
|
111
112
|
if (a.hotkey) {
|
112
113
|
hotkeys[a.hotkey] = a.fn;
|
113
114
|
}
|
114
115
|
});
|
115
116
|
|
116
|
-
if (
|
117
|
+
if (
|
118
|
+
(evt.metaKey || evt.ctrlKey) &&
|
119
|
+
Object.prototype.hasOwnProperty.call(hotkeys, key)
|
120
|
+
) {
|
117
121
|
evt.preventDefault();
|
118
122
|
this.applyAction(hotkeys[key]);
|
119
123
|
}
|
@@ -123,7 +127,7 @@ export default class RichTextArea extends React.Component {
|
|
123
127
|
let name = selection.length > 0 ? selection : "Link text";
|
124
128
|
var url = prompt("Enter link URL", "");
|
125
129
|
if (url) {
|
126
|
-
return ["
|
130
|
+
return ['"', name, `":${this.relativeUrl(url)}`];
|
127
131
|
} else {
|
128
132
|
return ["", name, ""];
|
129
133
|
}
|
@@ -156,9 +160,11 @@ export default class RichTextArea extends React.Component {
|
|
156
160
|
console.log("Error parsing URL: ", error);
|
157
161
|
}
|
158
162
|
|
159
|
-
if (
|
160
|
-
|
161
|
-
|
163
|
+
if (
|
164
|
+
url &&
|
165
|
+
url.hostname == document.location.hostname &&
|
166
|
+
(document.location.port || "80") == (url.port || "80")
|
167
|
+
) {
|
162
168
|
return url.pathname;
|
163
169
|
}
|
164
170
|
return str;
|
@@ -176,12 +182,14 @@ export default class RichTextArea extends React.Component {
|
|
176
182
|
return (
|
177
183
|
<div className="rich-text-area">
|
178
184
|
<div className="rich-text toolbar">
|
179
|
-
{this.actions().map(a =>
|
185
|
+
{this.actions().map((a) => (
|
180
186
|
<RichTextToolbarButton
|
181
187
|
key={a.name}
|
182
188
|
name={a.name}
|
183
189
|
className={a.className}
|
184
|
-
onClick={clickHandler(a.fn)}
|
190
|
+
onClick={clickHandler(a.fn)}
|
191
|
+
/>
|
192
|
+
))}
|
185
193
|
</div>
|
186
194
|
<textarea
|
187
195
|
className="rich"
|
@@ -192,7 +200,8 @@ export default class RichTextArea extends React.Component {
|
|
192
200
|
rows={rows}
|
193
201
|
onChange={this.handleChange}
|
194
202
|
onKeyDown={this.handleKeyPress}
|
195
|
-
{...this.localeOptions()}
|
203
|
+
{...this.localeOptions()}
|
204
|
+
/>
|
196
205
|
</div>
|
197
206
|
);
|
198
207
|
}
|
@@ -203,7 +212,9 @@ export default class RichTextArea extends React.Component {
|
|
203
212
|
|
204
213
|
textarea.value =
|
205
214
|
value.substr(0, selectionStart) +
|
206
|
-
prefix +
|
215
|
+
prefix +
|
216
|
+
replacement +
|
217
|
+
postfix +
|
207
218
|
value.substr(selectionEnd, value.length);
|
208
219
|
|
209
220
|
textarea.focus({ preventScroll: true });
|
@@ -215,7 +226,10 @@ export default class RichTextArea extends React.Component {
|
|
215
226
|
}
|
216
227
|
|
217
228
|
strToList(str, prefix) {
|
218
|
-
return str
|
229
|
+
return str
|
230
|
+
.split("\n")
|
231
|
+
.map((l) => prefix + " " + l)
|
232
|
+
.join("\n");
|
219
233
|
}
|
220
234
|
}
|
221
235
|
|
@@ -1,14 +1,17 @@
|
|
1
1
|
import React from "react";
|
2
2
|
|
3
3
|
interface RichTextToolbarButtonProps {
|
4
|
-
className: string
|
5
|
-
name: string
|
6
|
-
onClick: (evt: Event) => void
|
4
|
+
className: string;
|
5
|
+
name: string;
|
6
|
+
onClick: (evt: Event) => void;
|
7
7
|
}
|
8
8
|
|
9
|
-
export default function RichTextToolbarButton(
|
9
|
+
export default function RichTextToolbarButton(
|
10
|
+
props: RichTextToolbarButtonProps
|
11
|
+
) {
|
10
12
|
return (
|
11
|
-
<a
|
13
|
+
<a
|
14
|
+
title={props.name}
|
12
15
|
className={"button " + props.className}
|
13
16
|
onClick={props.onClick}>
|
14
17
|
<i className={"fa-solid fa-" + props.className} />
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import React, { ChangeEvent, useState } from "react";
|
2
2
|
|
3
3
|
interface AddTagFormProps {
|
4
|
-
addTag: (string) => void
|
4
|
+
addTag: (string) => void;
|
5
5
|
}
|
6
6
|
|
7
7
|
export default function AddTagForm(props: AddTagFormProps) {
|
@@ -25,15 +25,16 @@ export default function AddTagForm(props: AddTagFormProps) {
|
|
25
25
|
|
26
26
|
return (
|
27
27
|
<div className="add-tag-form">
|
28
|
-
<input
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
28
|
+
<input
|
29
|
+
name="add-tag"
|
30
|
+
type="text"
|
31
|
+
className="add-tag"
|
32
|
+
value={tag}
|
33
|
+
onKeyDown={handleKeyDown}
|
34
|
+
onChange={handleChange}
|
35
|
+
placeholder="Add tag..."
|
36
|
+
/>
|
37
|
+
<button onClick={submit} disabled={!tag}>
|
37
38
|
Add
|
38
39
|
</button>
|
39
40
|
</div>
|
@@ -1,9 +1,9 @@
|
|
1
1
|
import React from "react";
|
2
2
|
|
3
3
|
interface TagProps {
|
4
|
-
enabled: boolean
|
5
|
-
tag: string
|
6
|
-
toggleEnabled: (string) => void
|
4
|
+
enabled: boolean;
|
5
|
+
tag: string;
|
6
|
+
toggleEnabled: (string) => void;
|
7
7
|
}
|
8
8
|
|
9
9
|
export default function Tag(props: TagProps): JSX.Element {
|
@@ -19,11 +19,13 @@ export default function Tag(props: TagProps): JSX.Element {
|
|
19
19
|
return (
|
20
20
|
<span className={classes.join(" ")}>
|
21
21
|
<label className="check-box">
|
22
|
-
<input
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
22
|
+
<input
|
23
|
+
type="checkbox"
|
24
|
+
name={"tag-" + props.tag}
|
25
|
+
value="1"
|
26
|
+
checked={props.enabled}
|
27
|
+
onChange={handleChange}
|
28
|
+
/>
|
27
29
|
<span className="name">{props.tag}</span>
|
28
30
|
</label>
|
29
31
|
</span>
|
@@ -4,9 +4,9 @@ import AddTagForm from "./TagEditor/AddTagForm";
|
|
4
4
|
import Tag from "./TagEditor/Tag";
|
5
5
|
|
6
6
|
interface TagEditorProps {
|
7
|
-
name: string
|
8
|
-
enabled: string[]
|
9
|
-
tags: string[]
|
7
|
+
name: string;
|
8
|
+
enabled: string[];
|
9
|
+
tags: string[];
|
10
10
|
}
|
11
11
|
|
12
12
|
function onlyUnique(value: string, index: number, self: string[]): number {
|
@@ -21,12 +21,14 @@ export default function TagEditor(props: TagEditorProps) {
|
|
21
21
|
|
22
22
|
const normalize = (tag: string): string => {
|
23
23
|
return (
|
24
|
-
tagList.filter(t => t.toLowerCase() == tag.toLowerCase())[0] || tag
|
24
|
+
tagList.filter((t) => t.toLowerCase() == tag.toLowerCase())[0] || tag
|
25
25
|
);
|
26
26
|
};
|
27
27
|
|
28
28
|
const tagEnabled = (tag: string): boolean => {
|
29
|
-
return
|
29
|
+
return (
|
30
|
+
enabled.map((t) => t.toLowerCase()).indexOf(tag.toLowerCase()) !== -1
|
31
|
+
);
|
30
32
|
};
|
31
33
|
|
32
34
|
const toggleEnabled = (tag: string) => {
|
@@ -49,11 +51,14 @@ export default function TagEditor(props: TagEditorProps) {
|
|
49
51
|
return (
|
50
52
|
<div className="tag-editor clearfix">
|
51
53
|
<input type="hidden" name={props.name} value={JSON.stringify(enabled)} />
|
52
|
-
{tagList.map((t) =>
|
53
|
-
<Tag
|
54
|
-
|
55
|
-
|
56
|
-
|
54
|
+
{tagList.map((t) => (
|
55
|
+
<Tag
|
56
|
+
key={t}
|
57
|
+
tag={t}
|
58
|
+
enabled={tagEnabled(t)}
|
59
|
+
toggleEnabled={toggleEnabled}
|
60
|
+
/>
|
61
|
+
))}
|
57
62
|
<AddTagForm addTag={addTag} />
|
58
63
|
</div>
|
59
64
|
);
|
@@ -3,8 +3,8 @@ import React, { useEffect, useRef, useState } from "react";
|
|
3
3
|
import useToastStore from "../stores/useToastStore";
|
4
4
|
|
5
5
|
interface ToastProps {
|
6
|
-
error: string
|
7
|
-
notice: string
|
6
|
+
error: string;
|
7
|
+
notice: string;
|
8
8
|
}
|
9
9
|
|
10
10
|
export default function Toast(props: ToastProps) {
|
@@ -51,11 +51,7 @@ export default function Toast(props: ToastProps) {
|
|
51
51
|
|
52
52
|
return (
|
53
53
|
<div className="toast-wrapper" aria-live="polite">
|
54
|
-
{toast && (
|
55
|
-
<div className={classNames.join(" ")}>
|
56
|
-
{toast.message}
|
57
|
-
</div>
|
58
|
-
)}
|
54
|
+
{toast && <div className={classNames.join(" ")}>{toast.message}</div>}
|
59
55
|
</div>
|
60
56
|
);
|
61
57
|
}
|
@@ -13,12 +13,12 @@ function hovering(
|
|
13
13
|
} else {
|
14
14
|
return false;
|
15
15
|
}
|
16
|
-
return
|
17
|
-
y >= rect.top && y <= rect.bottom);
|
16
|
+
return x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom;
|
18
17
|
}
|
19
18
|
|
20
19
|
export function collectionOrder(
|
21
|
-
collection: DragCollection,
|
20
|
+
collection: DragCollection,
|
21
|
+
dragState: DragState
|
22
22
|
): Draggable[] {
|
23
23
|
const { draggables, ref } = collection;
|
24
24
|
const { dragging } = dragState;
|
@@ -27,14 +27,12 @@ export function collectionOrder(
|
|
27
27
|
return draggables;
|
28
28
|
}
|
29
29
|
|
30
|
-
let ordered = draggables.filter(d => d.handle !== dragging.handle);
|
30
|
+
let ordered = draggables.filter((d) => d.handle !== dragging.handle);
|
31
31
|
if (hovering(dragState, ref)) {
|
32
|
-
const hovered = ordered.filter(d => hovering(dragState, d))[0];
|
32
|
+
const hovered = ordered.filter((d) => hovering(dragState, d))[0];
|
33
33
|
if (hovered) {
|
34
34
|
const index = ordered.indexOf(hovered);
|
35
|
-
ordered = [...ordered.slice(0, index),
|
36
|
-
dragging,
|
37
|
-
...ordered.slice(index)];
|
35
|
+
ordered = [...ordered.slice(0, index), dragging, ...ordered.slice(index)];
|
38
36
|
} else {
|
39
37
|
ordered = [...ordered, dragging];
|
40
38
|
}
|
@@ -44,17 +42,20 @@ export function collectionOrder(
|
|
44
42
|
}
|
45
43
|
|
46
44
|
export default function draggedOrder(
|
47
|
-
collection: DragCollection,
|
45
|
+
collection: DragCollection,
|
46
|
+
dragState: DragState
|
48
47
|
): Draggable[] {
|
49
48
|
let ordered = collectionOrder(collection, dragState);
|
50
49
|
|
51
50
|
if (dragState.dragging && ordered.indexOf(dragState.dragging) === -1) {
|
52
|
-
if (
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
51
|
+
if (
|
52
|
+
collection.ref.current &&
|
53
|
+
dragState.y < collection.ref.current.getBoundingClientRect().top
|
54
|
+
) {
|
55
|
+
ordered = [dragState.dragging, ...ordered];
|
56
|
+
} else {
|
57
|
+
ordered.push(dragState.dragging);
|
58
|
+
}
|
58
59
|
}
|
59
60
|
|
60
61
|
return ordered;
|
@@ -1,28 +1,28 @@
|
|
1
1
|
export type DraggableRecord = Record<string, unknown>;
|
2
2
|
|
3
3
|
export interface Draggable {
|
4
|
-
record: DraggableRecord
|
5
|
-
ref: React.MutableRefObject<HTMLDivElement
|
6
|
-
rect: DOMRect | null
|
7
|
-
handle: string
|
4
|
+
record: DraggableRecord;
|
5
|
+
ref: React.MutableRefObject<HTMLDivElement>;
|
6
|
+
rect: DOMRect | null;
|
7
|
+
handle: string;
|
8
8
|
}
|
9
9
|
|
10
10
|
export interface DragCollectionAction {
|
11
|
-
type: string
|
12
|
-
payload?: Draggable[] | Draggable | null
|
11
|
+
type: string;
|
12
|
+
payload?: Draggable[] | Draggable | null;
|
13
13
|
}
|
14
14
|
|
15
15
|
export interface DragCollection {
|
16
|
-
ref: React.MutableRefObject<HTMLDivElement
|
17
|
-
draggables: Draggable[]
|
18
|
-
dispatch: (DragCollectionAction) => void
|
16
|
+
ref: React.MutableRefObject<HTMLDivElement>;
|
17
|
+
draggables: Draggable[];
|
18
|
+
dispatch: (DragCollectionAction) => void;
|
19
19
|
}
|
20
20
|
|
21
21
|
export interface Position {
|
22
|
-
x: number | null
|
23
|
-
y: number | null
|
22
|
+
x: number | null;
|
23
|
+
y: number | null;
|
24
24
|
}
|
25
25
|
|
26
26
|
export interface DragState extends Position {
|
27
|
-
dragging: Draggable | false
|
27
|
+
dragging: Draggable | false;
|
28
28
|
}
|