pages_core 3.12.1 → 3.12.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/app/assets/builds/pages_core/admin-dist.js +59 -14
- data/app/assets/builds/pages_core/admin-dist.js.map +7 -0
- data/app/assets/builds/pages_core/admin.css +39 -0
- data/app/assets/stylesheets/pages_core/admin/components/search.css +27 -0
- data/app/assets/stylesheets/pages_core/admin/controllers/pages.css +6 -0
- data/app/controllers/admin/pages_controller.rb +12 -11
- data/app/controllers/concerns/pages_core/rss_controller.rb +17 -1
- data/app/controllers/pages_core/admin_controller.rb +6 -0
- data/app/controllers/pages_core/frontend/pages_controller.rb +9 -5
- data/app/controllers/pages_core/sitemaps_controller.rb +3 -5
- data/app/helpers/admin/pages_helper.rb +32 -0
- data/app/javascript/admin-dist.ts +2 -0
- data/app/javascript/components/Attachments/{Attachment.jsx → Attachment.tsx} +42 -33
- data/app/javascript/components/Attachments/{AttachmentEditor.jsx → AttachmentEditor.tsx} +23 -23
- data/app/javascript/components/{EditableImage.jsx → EditableImage.tsx} +27 -24
- data/app/javascript/components/{FileUploadButton.jsx → FileUploadButton.tsx} +15 -16
- data/app/javascript/components/ImageCropper/FocalPoint.tsx +94 -0
- data/app/javascript/components/ImageCropper/{Image.jsx → Image.tsx} +13 -14
- data/app/javascript/components/ImageCropper/{Toolbar.jsx → Toolbar.tsx} +16 -12
- data/app/javascript/components/ImageCropper/{useCrop.js → useCrop.ts} +80 -37
- data/app/javascript/components/{ImageCropper.jsx → ImageCropper.tsx} +17 -15
- data/app/javascript/components/ImageEditor/{Form.jsx → Form.tsx} +24 -23
- data/app/javascript/components/{ImageEditor.jsx → ImageEditor.tsx} +17 -15
- data/app/javascript/components/ImageGrid/{DragElement.jsx → DragElement.tsx} +12 -10
- data/app/javascript/components/ImageGrid/{GridImage.jsx → GridImage.tsx} +40 -30
- data/app/javascript/components/ImageGrid/{Placeholder.jsx → Placeholder.tsx} +5 -6
- data/app/javascript/components/ImageGrid.jsx +3 -4
- data/app/javascript/components/{ImageUploader.jsx → ImageUploader.tsx} +46 -41
- data/app/javascript/components/Modal.tsx +48 -0
- data/app/javascript/components/PageImages.tsx +28 -0
- data/app/javascript/components/{PageTreeDraggable.jsx → PageTree/Draggable.tsx} +79 -57
- data/app/javascript/components/{PageTreeNode.jsx → PageTree/Node.tsx} +79 -70
- data/app/javascript/components/PageTree/types.ts +15 -0
- data/app/javascript/components/PageTree.tsx +206 -0
- data/app/javascript/components/RichTextToolbarButton.tsx +17 -0
- data/app/javascript/components/TagEditor/{AddTagForm.jsx → AddTagForm.tsx} +9 -10
- data/app/javascript/components/TagEditor/{Tag.jsx → Tag.tsx} +8 -9
- data/app/javascript/components/{TagEditor.jsx → TagEditor.tsx} +12 -13
- data/app/javascript/components/Toast.tsx +61 -0
- data/app/javascript/components/drag/{draggedOrder.js → draggedOrder.ts} +22 -12
- data/app/javascript/components/drag/types.ts +28 -0
- data/app/javascript/components/drag/{useDragCollection.js → useDragCollection.ts} +40 -22
- data/app/javascript/components/drag/{useDragUploader.js → useDragUploader.ts} +34 -25
- data/app/javascript/components/drag/useDraggable.ts +21 -0
- data/app/javascript/components/{drag.js → drag.ts} +1 -0
- data/app/javascript/controllers/{EditPageController.js → EditPageController.ts} +3 -1
- data/app/javascript/controllers/{LoginController.js → LoginController.ts} +7 -3
- data/app/javascript/controllers/{MainController.js → MainController.ts} +19 -14
- data/app/javascript/{index.js → index.ts} +8 -7
- data/app/javascript/lib/{Tree.js → Tree.ts} +106 -85
- data/app/javascript/lib/{copyToClipboard.js → copyToClipboard.ts} +1 -1
- data/app/javascript/lib/{readyHandler.js → readyHandler.ts} +4 -2
- data/app/javascript/lib/{request.js → request.ts} +11 -5
- data/app/javascript/stores/useModalStore.ts +15 -0
- data/app/javascript/stores/useToastStore.ts +26 -0
- data/app/javascript/stores.ts +2 -0
- data/app/javascript/types.ts +30 -0
- data/app/policies/page_policy.rb +4 -0
- data/app/views/admin/calendars/_sidebar.html.erb +3 -0
- data/app/views/admin/news/_sidebar.html.erb +3 -0
- data/app/views/admin/pages/_list_item.html.erb +4 -22
- data/app/views/admin/pages/_search_bar.html.erb +12 -0
- data/app/views/admin/pages/index.html.erb +3 -0
- data/app/views/admin/pages/search.html.erb +54 -0
- data/app/views/feeds/pages.rss.builder +3 -9
- data/config/routes.rb +1 -0
- data/lib/pages_core/configuration/pages.rb +0 -1
- data/lib/rails/generators/pages_core/frontend/frontend_generator.rb +33 -17
- data/lib/rails/generators/pages_core/frontend/templates/application.html.erb +0 -1
- data/lib/rails/generators/pages_core/frontend/templates/javascript/lib/gridOverlay.ts +40 -0
- data/lib/rails/generators/pages_core/frontend/templates/javascript/lib/responsiveEmbeds.ts +68 -0
- data/lib/rails/generators/pages_core/frontend/templates/postcss.config.js +17 -0
- data/lib/rails/generators/pages_core/frontend/templates/stylesheets/application.postcss.css +4 -0
- data/lib/rails/generators/pages_core/frontend/templates/stylesheets/components/base.css +24 -0
- data/lib/rails/generators/pages_core/frontend/templates/stylesheets/components/layout.css +21 -0
- data/lib/rails/generators/pages_core/frontend/templates/stylesheets/config.css +5 -0
- data/lib/rails/generators/pages_core/frontend/templates/stylesheets/global/animation.css +5 -0
- data/lib/rails/generators/pages_core/frontend/templates/stylesheets/global/colors.css +18 -0
- data/lib/rails/generators/pages_core/frontend/templates/stylesheets/global/fonts.css +6 -0
- data/lib/rails/generators/pages_core/frontend/templates/stylesheets/global/grid.css +65 -0
- data/lib/rails/generators/pages_core/frontend/templates/stylesheets/global/typography.css +131 -0
- data/lib/rails/generators/pages_core/install/templates/pages_initializer.rb +0 -3
- metadata +68 -62
- data/app/javascript/admin-dist.js +0 -2
- data/app/javascript/components/ImageCropper/FocalPoint.jsx +0 -93
- data/app/javascript/components/Modal.jsx +0 -59
- data/app/javascript/components/PageImages.jsx +0 -25
- data/app/javascript/components/PageTree.jsx +0 -196
- data/app/javascript/components/RichTextToolbarButton.jsx +0 -20
- data/app/javascript/components/Toast.jsx +0 -72
- data/app/javascript/components/drag/useDraggable.js +0 -17
- data/app/javascript/stores/ModalStore.jsx +0 -12
- data/app/javascript/stores/ToastStore.jsx +0 -14
- data/app/javascript/stores.js +0 -2
- data/lib/rails/generators/pages_core/frontend/templates/javascript/lib/GridOverlay.js +0 -66
- data/lib/rails/generators/pages_core/frontend/templates/javascript/lib/ResponsiveEmbeds.js +0 -72
- data/lib/rails/generators/pages_core/frontend/templates/stylesheets/application.sass.scss +0 -15
- data/lib/rails/generators/pages_core/frontend/templates/stylesheets/components/base.scss +0 -12
- data/lib/rails/generators/pages_core/frontend/templates/stylesheets/config.scss +0 -26
- data/lib/rails/generators/pages_core/frontend/templates/stylesheets/framework/breakpoints.scss +0 -42
- data/lib/rails/generators/pages_core/frontend/templates/stylesheets/framework/clearfix.scss +0 -7
- data/lib/rails/generators/pages_core/frontend/templates/stylesheets/framework/fonts.scss +0 -32
- data/lib/rails/generators/pages_core/frontend/templates/stylesheets/framework/grid.scss +0 -168
- data/lib/rails/generators/pages_core/frontend/templates/stylesheets/framework/grid_overlay.scss +0 -44
- data/lib/rails/generators/pages_core/frontend/templates/stylesheets/global/colors.scss +0 -8
- data/lib/rails/generators/pages_core/frontend/templates/stylesheets/global/typography.scss +0 -90
- data/lib/rails/generators/pages_core/frontend/templates/stylesheets/vendor/normalize.css +0 -349
- /data/app/javascript/components/Attachments/{Placeholder.jsx → Placeholder.tsx} +0 -0
- /data/app/javascript/components/ImageGrid/{FilePlaceholder.jsx → FilePlaceholder.tsx} +0 -0
- /data/app/javascript/{components.js → components.ts} +0 -0
- /data/app/javascript/{hooks.js → hooks.ts} +0 -0
|
@@ -48,43 +48,65 @@
|
|
|
48
48
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
49
49
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
50
50
|
SOFTWARE.
|
|
51
|
-
*/
|
|
51
|
+
*/
|
|
52
52
|
|
|
53
|
-
export
|
|
54
|
-
|
|
53
|
+
export type TreeId = number | string;
|
|
54
|
+
type MovePlacement = "before" | "after" | "prepend" | "append";
|
|
55
|
+
|
|
56
|
+
export interface TreeNode {
|
|
57
|
+
children: TreeNode[],
|
|
58
|
+
collapsed: boolean
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface TreeIndex<T extends TreeNode = TreeNode> {
|
|
62
|
+
id: number,
|
|
63
|
+
node: T,
|
|
64
|
+
children: TreeIndex<T>[],
|
|
65
|
+
parent: TreeIndex<T>
|
|
66
|
+
next: TreeIndex<T> | null,
|
|
67
|
+
prev: TreeIndex<T> | null,
|
|
68
|
+
top: number,
|
|
69
|
+
height: number
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function indexName(id: number | string): string {
|
|
73
|
+
return `${id}`;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export default class Tree<N extends TreeNode = TreeNode> {
|
|
77
|
+
cnt: number;
|
|
78
|
+
obj: N;
|
|
79
|
+
indexes: Record<string, TreeIndex<N>>;
|
|
80
|
+
|
|
81
|
+
constructor(obj: N) {
|
|
55
82
|
this.cnt = 1;
|
|
56
83
|
this.obj = obj || { children: [] };
|
|
57
84
|
this.indexes = {};
|
|
58
85
|
this.build(this.obj);
|
|
59
86
|
}
|
|
60
87
|
|
|
61
|
-
build(obj) {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
var self = this;
|
|
88
|
+
build(obj: N): TreeIndex<N> {
|
|
89
|
+
const indexes = this.indexes;
|
|
90
|
+
const startId = this.cnt;
|
|
65
91
|
|
|
66
|
-
|
|
67
|
-
indexes[this.cnt
|
|
92
|
+
const index = { id: startId, node: obj };
|
|
93
|
+
indexes[indexName(this.cnt)] = index;
|
|
68
94
|
this.cnt++;
|
|
69
95
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
var children = [];
|
|
76
|
-
objs.forEach(function(obj) {
|
|
77
|
-
var index = {};
|
|
78
|
-
index.id = self.cnt;
|
|
96
|
+
const walk = (objs: TreeIndex<N>[], parent: TreeIndex<N>) => {
|
|
97
|
+
const children: TreeIndex<N>[] = [];
|
|
98
|
+
objs.forEach((obj) => {
|
|
99
|
+
const index: TreeIndex<N> = {};
|
|
100
|
+
index.id = this.cnt;
|
|
79
101
|
index.node = obj;
|
|
80
102
|
|
|
81
103
|
if (parent) {
|
|
82
104
|
index.parent = parent.id;
|
|
83
105
|
}
|
|
84
106
|
|
|
85
|
-
indexes[
|
|
86
|
-
children.push(
|
|
87
|
-
|
|
107
|
+
indexes[indexName(this.cnt)] = index;
|
|
108
|
+
children.push(this.cnt);
|
|
109
|
+
this.cnt++;
|
|
88
110
|
|
|
89
111
|
if (obj.children && obj.children.length) {
|
|
90
112
|
walk(obj.children, index);
|
|
@@ -93,7 +115,7 @@ export default class Tree {
|
|
|
93
115
|
parent.children = children;
|
|
94
116
|
|
|
95
117
|
children.forEach(function(id, i) {
|
|
96
|
-
|
|
118
|
+
const index = indexes[indexName(id)];
|
|
97
119
|
if (i > 0) {
|
|
98
120
|
index.prev = children[i - 1];
|
|
99
121
|
}
|
|
@@ -101,56 +123,54 @@ export default class Tree {
|
|
|
101
123
|
index.next = children[i+1];
|
|
102
124
|
}
|
|
103
125
|
});
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
if (obj.children && obj.children.length) {
|
|
129
|
+
walk(obj.children, index);
|
|
104
130
|
}
|
|
105
131
|
|
|
106
132
|
return index;
|
|
107
133
|
}
|
|
108
134
|
|
|
109
|
-
getIndex(id) {
|
|
110
|
-
|
|
111
|
-
if (index) {
|
|
112
|
-
return index;
|
|
113
|
-
}
|
|
135
|
+
getIndex(id: TreeId): TreeIndex<N> {
|
|
136
|
+
return this.indexes[indexName(id)];
|
|
114
137
|
}
|
|
115
138
|
|
|
116
|
-
removeIndex(index) {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
function del(index) {
|
|
121
|
-
delete self.indexes[index.id + ""];
|
|
139
|
+
removeIndex(index: TreeIndex<N>) {
|
|
140
|
+
const del = (index: TreeIndex<N>) => {
|
|
141
|
+
delete this.indexes[indexName(index.id)];
|
|
122
142
|
if (index.children && index.children.length) {
|
|
123
|
-
index.children.forEach(
|
|
124
|
-
del(
|
|
143
|
+
index.children.forEach((child) => {
|
|
144
|
+
del(this.getIndex(child));
|
|
125
145
|
});
|
|
126
146
|
}
|
|
127
|
-
}
|
|
147
|
+
};
|
|
148
|
+
del(index);
|
|
128
149
|
}
|
|
129
150
|
|
|
130
|
-
get(id) {
|
|
131
|
-
|
|
132
|
-
if (index && index.node) {
|
|
133
|
-
return index.node;
|
|
134
|
-
}
|
|
135
|
-
return null;
|
|
151
|
+
get(id: TreeId): N {
|
|
152
|
+
return this.getIndex(id).node;
|
|
136
153
|
}
|
|
137
154
|
|
|
138
|
-
remove(id) {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
155
|
+
remove(id: TreeId): N {
|
|
156
|
+
const index = this.getIndex(id);
|
|
157
|
+
const node = this.get(id);
|
|
158
|
+
|
|
159
|
+
const parentIndex = this.getIndex(index.parent);
|
|
160
|
+
const parentNode = this.get(index.parent);
|
|
161
|
+
|
|
143
162
|
parentNode.children.splice(parentNode.children.indexOf(node), 1);
|
|
144
163
|
parentIndex.children.splice(parentIndex.children.indexOf(id), 1);
|
|
164
|
+
|
|
145
165
|
this.removeIndex(index);
|
|
146
166
|
this.updateChildren(parentIndex.children);
|
|
147
167
|
|
|
148
168
|
return node;
|
|
149
169
|
}
|
|
150
170
|
|
|
151
|
-
updateChildren(children) {
|
|
152
|
-
children.forEach(
|
|
153
|
-
|
|
171
|
+
updateChildren(children: TreeIndex<N>[]) {
|
|
172
|
+
children.forEach((id, i) => {
|
|
173
|
+
const index = this.getIndex(id);
|
|
154
174
|
index.prev = index.next = null;
|
|
155
175
|
if (i > 0) {
|
|
156
176
|
index.prev = children[i-1];
|
|
@@ -158,14 +178,14 @@ export default class Tree {
|
|
|
158
178
|
if (i < children.length-1) {
|
|
159
179
|
index.next = children[i+1];
|
|
160
180
|
}
|
|
161
|
-
}
|
|
181
|
+
});
|
|
162
182
|
}
|
|
163
183
|
|
|
164
|
-
insert(obj, parentId, i) {
|
|
165
|
-
|
|
166
|
-
|
|
184
|
+
insert(obj: N, parentId: TreeId, i: number): TreeIndex<N> {
|
|
185
|
+
const parentIndex = this.getIndex(parentId);
|
|
186
|
+
const parentNode = this.get(parentId);
|
|
167
187
|
|
|
168
|
-
|
|
188
|
+
const index = this.build(obj);
|
|
169
189
|
index.parent = parentId;
|
|
170
190
|
|
|
171
191
|
parentNode.children = parentNode.children || [];
|
|
@@ -182,26 +202,26 @@ export default class Tree {
|
|
|
182
202
|
return index;
|
|
183
203
|
}
|
|
184
204
|
|
|
185
|
-
insertBefore(obj, destId) {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
205
|
+
insertBefore(obj: N, destId: TreeId): TreeIndex<N> {
|
|
206
|
+
const destIndex = this.getIndex(destId);
|
|
207
|
+
const parentId = destIndex.parent;
|
|
208
|
+
const i = this.getIndex(parentId).children.indexOf(destId);
|
|
189
209
|
return this.insert(obj, parentId, i);
|
|
190
210
|
}
|
|
191
211
|
|
|
192
|
-
insertAfter(obj, destId) {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
212
|
+
insertAfter(obj: N, destId: TreeId): TreeIndex<N> {
|
|
213
|
+
const destIndex = this.getIndex(destId);
|
|
214
|
+
const parentId = destIndex.parent;
|
|
215
|
+
const i = this.getIndex(parentId).children.indexOf(destId);
|
|
196
216
|
return this.insert(obj, parentId, i+1);
|
|
197
217
|
}
|
|
198
218
|
|
|
199
|
-
prepend(obj, destId) {
|
|
219
|
+
prepend(obj: N, destId: TreeId): TreeIndex<N> {
|
|
200
220
|
return this.insert(obj, destId, 0);
|
|
201
221
|
}
|
|
202
222
|
|
|
203
|
-
append(obj, destId) {
|
|
204
|
-
|
|
223
|
+
append(obj: N, destId: TreeId): TreeIndex<N> {
|
|
224
|
+
const destIndex = this.getIndex(destId);
|
|
205
225
|
destIndex.children = destIndex.children || [];
|
|
206
226
|
return this.insert(obj, destId, destIndex.children.length);
|
|
207
227
|
}
|
|
@@ -209,22 +229,19 @@ export default class Tree {
|
|
|
209
229
|
// react-ui-tree methods
|
|
210
230
|
|
|
211
231
|
updateNodesPosition() {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
var self = this;
|
|
232
|
+
let top = 1;
|
|
233
|
+
let left = 1;
|
|
234
|
+
const root = this.getIndex(1);
|
|
216
235
|
|
|
217
236
|
root.top = top++;
|
|
218
237
|
root.left = left++;
|
|
219
238
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
children.forEach(function(id) {
|
|
227
|
-
var node = self.getIndex(id);
|
|
239
|
+
const walk = (
|
|
240
|
+
children: TreeIndex<N>[], parent: TreeIndex<N>, left: number, collapsed: boolean
|
|
241
|
+
) => {
|
|
242
|
+
let height = 1;
|
|
243
|
+
children.forEach((id: TreeId) => {
|
|
244
|
+
const node = this.getIndex(id);
|
|
228
245
|
if (collapsed) {
|
|
229
246
|
node.top = null;
|
|
230
247
|
node.left = null;
|
|
@@ -249,16 +266,20 @@ export default class Tree {
|
|
|
249
266
|
if(parent.node.collapsed) parent.height = 1;
|
|
250
267
|
else parent.height = height;
|
|
251
268
|
return parent.height;
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
if (root.children && root.children.length) {
|
|
272
|
+
walk(root.children, root, left, root.node.collapsed);
|
|
252
273
|
}
|
|
253
274
|
}
|
|
254
275
|
|
|
255
|
-
move(fromId, toId, placement) {
|
|
276
|
+
move(fromId: TreeId, toId: TreeId, placement: MovePlacement): TreeIndex<N> {
|
|
256
277
|
if (fromId === toId || toId === 1) {
|
|
257
278
|
return;
|
|
258
279
|
}
|
|
259
280
|
|
|
260
|
-
|
|
261
|
-
|
|
281
|
+
const obj = this.remove(fromId);
|
|
282
|
+
let index: TreeIndex<N>;
|
|
262
283
|
|
|
263
284
|
if (placement === "before") {
|
|
264
285
|
index = this.insertBefore(obj, toId);
|
|
@@ -275,16 +296,16 @@ export default class Tree {
|
|
|
275
296
|
return index;
|
|
276
297
|
}
|
|
277
298
|
|
|
278
|
-
getParent(id) {
|
|
279
|
-
|
|
299
|
+
getParent(id: string) {
|
|
300
|
+
const indexes = this.indexes;
|
|
280
301
|
if (Object.prototype.hasOwnProperty.call(indexes, id)) {
|
|
281
302
|
return this.getIndex(indexes[id].parent);
|
|
282
303
|
}
|
|
283
304
|
}
|
|
284
305
|
|
|
285
306
|
getNodeByTop(top) {
|
|
286
|
-
|
|
287
|
-
for(
|
|
307
|
+
const indexes = this.indexes;
|
|
308
|
+
for(const id in indexes) {
|
|
288
309
|
if (Object.prototype.hasOwnProperty.call(indexes, id)) {
|
|
289
310
|
if(indexes[id].top === top) {
|
|
290
311
|
return indexes[id];
|
|
@@ -3,7 +3,7 @@ export function copySupported () {
|
|
|
3
3
|
document.queryCommandSupported("copy");
|
|
4
4
|
}
|
|
5
5
|
|
|
6
|
-
export default function copyToClipboard (str) {
|
|
6
|
+
export default function copyToClipboard (str: string) {
|
|
7
7
|
const el = document.createElement("textarea");
|
|
8
8
|
el.value = str;
|
|
9
9
|
document.body.appendChild(el);
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
type ReadyHandlerFunc = () => void;
|
|
2
|
+
|
|
3
|
+
const readyHandlers: ReadyHandlerFunc[] = [];
|
|
2
4
|
|
|
3
5
|
const handleState = () => {
|
|
4
6
|
if (["interactive", "complete"].indexOf(document.readyState) > -1) {
|
|
@@ -13,7 +15,7 @@ class ReadyHandler {
|
|
|
13
15
|
document.onreadystatechange = handleState;
|
|
14
16
|
}
|
|
15
17
|
|
|
16
|
-
ready (handler) {
|
|
18
|
+
ready (handler: ReadyHandlerFunc) {
|
|
17
19
|
readyHandlers.push(handler);
|
|
18
20
|
handleState();
|
|
19
21
|
}
|
|
@@ -1,5 +1,11 @@
|
|
|
1
|
-
export function csrfToken() {
|
|
2
|
-
|
|
1
|
+
export function csrfToken(): string {
|
|
2
|
+
const elem = document.querySelector("[name=csrf-token]");
|
|
3
|
+
|
|
4
|
+
if (!elem) {
|
|
5
|
+
return "";
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
return elem.getAttribute("content") || "";
|
|
3
9
|
}
|
|
4
10
|
|
|
5
11
|
function jsonFetchOptions() {
|
|
@@ -8,7 +14,7 @@ function jsonFetchOptions() {
|
|
|
8
14
|
"X-CSRF-Token": csrfToken() } });
|
|
9
15
|
}
|
|
10
16
|
|
|
11
|
-
export async function postJson(url, data) {
|
|
17
|
+
export async function postJson(url: string, data: Record<string, unknown>) {
|
|
12
18
|
const options = { ...jsonFetchOptions(), method: "POST" };
|
|
13
19
|
if (data) {
|
|
14
20
|
options.body = JSON.stringify(data);
|
|
@@ -17,7 +23,7 @@ export async function postJson(url, data) {
|
|
|
17
23
|
return response.json();
|
|
18
24
|
}
|
|
19
25
|
|
|
20
|
-
export async function putJson(url, data) {
|
|
26
|
+
export async function putJson(url: string, data: Record<string, unknown>) {
|
|
21
27
|
const options = { ...jsonFetchOptions(), method: "PUT" };
|
|
22
28
|
if (data) {
|
|
23
29
|
options.body = JSON.stringify(data);
|
|
@@ -26,7 +32,7 @@ export async function putJson(url, data) {
|
|
|
26
32
|
return response.json();
|
|
27
33
|
}
|
|
28
34
|
|
|
29
|
-
export async function post(url, data) {
|
|
35
|
+
export async function post(url: string, data: Record<string, unknown>) {
|
|
30
36
|
const response = await fetch(url, {
|
|
31
37
|
method: "POST",
|
|
32
38
|
body: data,
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { create } from "zustand";
|
|
2
|
+
|
|
3
|
+
interface ModalState {
|
|
4
|
+
component: JSX.Element | null,
|
|
5
|
+
open: (elem: JSX.Element) => void,
|
|
6
|
+
close: () => void
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const useModalStore = create<ModalState>((set) => ({
|
|
10
|
+
component: null,
|
|
11
|
+
open: (c: JSX.Element) => set({ component: c }),
|
|
12
|
+
close: () => set({ component: null })
|
|
13
|
+
}));
|
|
14
|
+
|
|
15
|
+
export default useModalStore;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { create } from "zustand";
|
|
2
|
+
|
|
3
|
+
export interface Toast {
|
|
4
|
+
type: string,
|
|
5
|
+
message: string
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
interface ToastState {
|
|
9
|
+
toasts: Toast[],
|
|
10
|
+
error: (msg: string) => void,
|
|
11
|
+
notice: (msg: string) => void,
|
|
12
|
+
next: () => void
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const useToastStore = create<ToastState>((set) => ({
|
|
16
|
+
toasts: [],
|
|
17
|
+
error: (msg: string) => set((state) => (
|
|
18
|
+
{ toasts: [...state.toasts, { message: msg, type: "error" }] }
|
|
19
|
+
)),
|
|
20
|
+
notice: (msg: string) => set((state) => (
|
|
21
|
+
{ toasts: [...state.toasts, { message: msg, type: "notice" }] }
|
|
22
|
+
)),
|
|
23
|
+
next: () => set((state) => ({ toasts: state.toasts.slice(1) }))
|
|
24
|
+
}));
|
|
25
|
+
|
|
26
|
+
export default useToastStore;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export interface Locale {
|
|
2
|
+
name: string,
|
|
3
|
+
dir: "ltr" | "rtl"
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export interface AttachmentResource {
|
|
7
|
+
id: number | null,
|
|
8
|
+
name: Record<string, string>,
|
|
9
|
+
description: Record<string, string>,
|
|
10
|
+
url: string
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface ImageResource {
|
|
14
|
+
id: number | null,
|
|
15
|
+
alternative: Record<string, string>,
|
|
16
|
+
caption: Record<string, string>,
|
|
17
|
+
content_type: string,
|
|
18
|
+
filename: string,
|
|
19
|
+
crop_start_x: number | null,
|
|
20
|
+
crop_start_y: number | null,
|
|
21
|
+
crop_width: number | null,
|
|
22
|
+
crop_height: number | null,
|
|
23
|
+
crop_gravity_x: number,
|
|
24
|
+
crop_gravity_y: number,
|
|
25
|
+
real_width: number,
|
|
26
|
+
real_height: number,
|
|
27
|
+
original_url: string,
|
|
28
|
+
thumbnail_url: string
|
|
29
|
+
uncropped_url: string
|
|
30
|
+
}
|
data/app/policies/page_policy.rb
CHANGED
|
@@ -4,19 +4,13 @@
|
|
|
4
4
|
section ||= false
|
|
5
5
|
sections ||= []
|
|
6
6
|
%>
|
|
7
|
-
|
|
7
|
+
<%= page_list_row(page) do %>
|
|
8
8
|
<td class="name">
|
|
9
9
|
<%= link_to_if(policy(page).edit?,
|
|
10
10
|
page_name(page),
|
|
11
11
|
edit_admin_page_url(@locale, page),
|
|
12
12
|
class: 'name_link') %>
|
|
13
|
-
|
|
14
|
-
<br />
|
|
15
|
-
<small>
|
|
16
|
-
This page will be published
|
|
17
|
-
<strong><%= publish_time(page.published_at) %></strong>
|
|
18
|
-
</small>
|
|
19
|
-
<% end %>
|
|
13
|
+
<%= autopublish_notice(page) %>
|
|
20
14
|
</td>
|
|
21
15
|
<% if date %>
|
|
22
16
|
<td class="date">
|
|
@@ -24,19 +18,7 @@
|
|
|
24
18
|
</td>
|
|
25
19
|
<% end %>
|
|
26
20
|
<td>
|
|
27
|
-
|
|
28
|
-
<% if page.published_at.year == Time.zone.now.year %>
|
|
29
|
-
<%= l(page.published_at, format: :pages_date) %>
|
|
30
|
-
<% else %>
|
|
31
|
-
<%= l(page.published_at, format: :pages_full) %>
|
|
32
|
-
<% end %>
|
|
33
|
-
<% else %>
|
|
34
|
-
<% if page.status_label == 'Published' %>
|
|
35
|
-
<em>Not published</em>
|
|
36
|
-
<% else %>
|
|
37
|
-
<em><%= page.status_label %></em>
|
|
38
|
-
<% end %>
|
|
39
|
-
<% end %>
|
|
21
|
+
<%= page_published_status(page) %>
|
|
40
22
|
</td>
|
|
41
23
|
<% if author %>
|
|
42
24
|
<td>
|
|
@@ -48,4 +30,4 @@
|
|
|
48
30
|
<%= news_section_name(page.parent, sections) %>
|
|
49
31
|
</td>
|
|
50
32
|
<% end %>
|
|
51
|
-
|
|
33
|
+
<% end %>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<% query ||= "" %>
|
|
2
|
+
<%= form_tag(search_admin_pages_path(@locale),
|
|
3
|
+
method: "get",
|
|
4
|
+
class: "search-bar") do %>
|
|
5
|
+
<%= text_field_tag(:q, query,
|
|
6
|
+
placeholder: "Search all pages",
|
|
7
|
+
aria: { label: "Search all pages" }) %>
|
|
8
|
+
<button type="submit">
|
|
9
|
+
<i class="fa-solid fa-magnifying-glass"></i>
|
|
10
|
+
Search
|
|
11
|
+
</button>
|
|
12
|
+
<% end %>
|
|
@@ -9,6 +9,9 @@
|
|
|
9
9
|
<%= locale_links { |l| admin_pages_path(l) } %>
|
|
10
10
|
<% end %>
|
|
11
11
|
|
|
12
|
+
<%= render(partial: "admin/pages/search_bar",
|
|
13
|
+
locals: { query: search_query }) %>
|
|
14
|
+
|
|
12
15
|
<div class="content">
|
|
13
16
|
<% cache Page.visible.roots.to_a + [current_user, @locale] do %>
|
|
14
17
|
<%= react_component(
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
<% content_for :page_title, "Search pages" %>
|
|
2
|
+
|
|
3
|
+
<% content_for :page_description do %>
|
|
4
|
+
Search pages
|
|
5
|
+
<% end %>
|
|
6
|
+
|
|
7
|
+
<% content_for :page_description_links do %>
|
|
8
|
+
<%= locale_links { |l| search_admin_pages_path(l, q: search_query) } %>
|
|
9
|
+
<% end %>
|
|
10
|
+
|
|
11
|
+
<%= render(partial: "admin/pages/search_bar",
|
|
12
|
+
locals: { query: search_query }) %>
|
|
13
|
+
|
|
14
|
+
<% if @search_documents.any? %>
|
|
15
|
+
<table class="list calendar-item-list">
|
|
16
|
+
<tr>
|
|
17
|
+
<th>Name</th>
|
|
18
|
+
<th>Published</th>
|
|
19
|
+
<th>Author</th>
|
|
20
|
+
<th>Location</th>
|
|
21
|
+
</tr>
|
|
22
|
+
<% @search_documents.results.each do |page| %>
|
|
23
|
+
<%= page_list_row(page) do %>
|
|
24
|
+
<td class="name">
|
|
25
|
+
<%= link_to_if(policy(page).edit?,
|
|
26
|
+
page_name(page),
|
|
27
|
+
edit_admin_page_url(@locale, page),
|
|
28
|
+
class: 'name_link') %>
|
|
29
|
+
<%= autopublish_notice(page) %>
|
|
30
|
+
</td>
|
|
31
|
+
<td>
|
|
32
|
+
<%= page_published_status(page) %>
|
|
33
|
+
</td>
|
|
34
|
+
<td>
|
|
35
|
+
<%= link_to(page.author.name, admin_user_path(page.author)) %>
|
|
36
|
+
</td>
|
|
37
|
+
<td>
|
|
38
|
+
<% if page.parent %>
|
|
39
|
+
<%= page_name(page.parent, include_parents: true) %>
|
|
40
|
+
<% else %>
|
|
41
|
+
Top level
|
|
42
|
+
<% end %>
|
|
43
|
+
</td>
|
|
44
|
+
<% end %>
|
|
45
|
+
<% end %>
|
|
46
|
+
</table>
|
|
47
|
+
<%= will_paginate(@search_documents, renderer: PagesCore::LinkRenderer) %>
|
|
48
|
+
<% else %>
|
|
49
|
+
<div class="content">
|
|
50
|
+
<p>
|
|
51
|
+
Found no results for your search query.
|
|
52
|
+
</p>
|
|
53
|
+
</div>
|
|
54
|
+
<% end %>
|
|
@@ -4,9 +4,7 @@ xml << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
|
|
4
4
|
xml.rss("version" => "2.0", "xmlns:dc" => "http://purl.org/dc/elements/1.1/") do
|
|
5
5
|
xml.channel do
|
|
6
6
|
xml.title(@title || PagesCore.config(:site_name))
|
|
7
|
-
xml.link(
|
|
8
|
-
url_for(controller: "pages", action: "index", only_path: false)
|
|
9
|
-
)
|
|
7
|
+
xml.link(root_url)
|
|
10
8
|
xml.description "Recent items"
|
|
11
9
|
xml.language locale
|
|
12
10
|
xml.generator "Pages"
|
|
@@ -15,12 +13,8 @@ xml.rss("version" => "2.0", "xmlns:dc" => "http://purl.org/dc/elements/1.1/") do
|
|
|
15
13
|
xml.item do
|
|
16
14
|
xml.title { xml.cdata! item.name.to_s }
|
|
17
15
|
xml.link page_url(@locale, item, only_path: false)
|
|
18
|
-
|
|
19
|
-
xml.
|
|
20
|
-
else
|
|
21
|
-
xml.description do
|
|
22
|
-
xml.cdata!((item.extended? ? item.excerpt : item.body).to_html)
|
|
23
|
-
end
|
|
16
|
+
xml.description do
|
|
17
|
+
xml.cdata! item.excerpt.to_html + item.body.to_html
|
|
24
18
|
end
|
|
25
19
|
xml.guid page_url(@locale, item, only_path: false)
|
|
26
20
|
xml.pubDate item.published_at.to_fs(:rfc822)
|
data/config/routes.rb
CHANGED
|
@@ -11,7 +11,6 @@ module PagesCore
|
|
|
11
11
|
setting :localizations, :boolean, false
|
|
12
12
|
setting :locales, :hash
|
|
13
13
|
setting :text_filter, :symbol, :textile
|
|
14
|
-
setting :rss_fulltext, :boolean, true
|
|
15
14
|
setting :image_fallback_url, :string
|
|
16
15
|
setting :default_author, :string
|
|
17
16
|
setting :error_404_layout, :string
|