pages_core 3.12.4 → 3.12.5

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.
Files changed (108) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/app/assets/builds/pages_core/admin-dist.js +8 -43
  4. data/app/assets/builds/pages_core/admin-dist.js.map +4 -4
  5. data/app/assets/builds/pages_core/admin.css +264 -133
  6. data/app/assets/stylesheets/pages_core/admin/components/attachments.css +3 -4
  7. data/app/assets/stylesheets/pages_core/admin/components/forms.css +17 -16
  8. data/app/assets/stylesheets/pages_core/admin/components/image_editor.css +8 -4
  9. data/app/assets/stylesheets/pages_core/admin/components/image_grid.css +1 -1
  10. data/app/assets/stylesheets/pages_core/admin/components/list_table.css +11 -3
  11. data/app/assets/stylesheets/pages_core/admin/components/modal.css +9 -5
  12. data/app/assets/stylesheets/pages_core/admin/components/page_tree.css +5 -1
  13. data/app/assets/stylesheets/pages_core/admin/components/toast.css +2 -2
  14. data/app/assets/stylesheets/pages_core/admin/controllers/pages.css +4 -2
  15. data/app/assets/stylesheets/pages_core/admin/vars.css +2 -1
  16. data/app/controllers/admin/calendars_controller.rb +2 -2
  17. data/app/controllers/admin/categories_controller.rb +3 -3
  18. data/app/controllers/admin/news_controller.rb +6 -6
  19. data/app/controllers/admin/pages_controller.rb +12 -11
  20. data/app/controllers/admin/users_controller.rb +1 -1
  21. data/app/controllers/concerns/pages_core/preview_pages_controller.rb +15 -17
  22. data/app/controllers/pages_core/admin_controller.rb +2 -2
  23. data/app/controllers/pages_core/base_controller.rb +1 -8
  24. data/app/controllers/pages_core/frontend/pages_controller.rb +13 -5
  25. data/app/controllers/pages_core/frontend_controller.rb +12 -7
  26. data/app/helpers/admin/menu_helper.rb +2 -0
  27. data/app/helpers/admin/pages_helper.rb +1 -4
  28. data/app/helpers/pages_core/admin/admin_helper.rb +0 -1
  29. data/app/helpers/pages_core/admin/content_tabs_helper.rb +9 -2
  30. data/app/helpers/pages_core/application_helper.rb +2 -3
  31. data/app/helpers/pages_core/frontend_helper.rb +1 -1
  32. data/app/helpers/pages_core/head_tags_helper.rb +15 -46
  33. data/app/helpers/pages_core/images_helper.rb +76 -21
  34. data/app/helpers/pages_core/locales_helper.rb +9 -0
  35. data/app/helpers/pages_core/open_graph_tags_helper.rb +3 -5
  36. data/app/helpers/pages_core/page_path_helper.rb +1 -1
  37. data/app/javascript/components/Attachments/Attachment.tsx +55 -52
  38. data/app/javascript/components/Attachments/AttachmentEditor.tsx +45 -50
  39. data/app/javascript/components/Attachments/Placeholder.tsx +1 -2
  40. data/app/javascript/components/Attachments.jsx +69 -57
  41. data/app/javascript/components/DateRangeSelect.jsx +94 -54
  42. data/app/javascript/components/EditableImage.tsx +20 -16
  43. data/app/javascript/components/FileUploadButton.tsx +12 -12
  44. data/app/javascript/components/ImageCropper/FocalPoint.tsx +22 -20
  45. data/app/javascript/components/ImageCropper/Image.tsx +20 -16
  46. data/app/javascript/components/ImageCropper/Toolbar.tsx +35 -27
  47. data/app/javascript/components/ImageCropper/useCrop.ts +105 -91
  48. data/app/javascript/components/ImageCropper.tsx +34 -25
  49. data/app/javascript/components/ImageEditor/Form.tsx +32 -43
  50. data/app/javascript/components/ImageEditor.tsx +29 -21
  51. data/app/javascript/components/ImageGrid/DragElement.tsx +6 -4
  52. data/app/javascript/components/ImageGrid/GridImage.tsx +56 -52
  53. data/app/javascript/components/ImageGrid/Placeholder.tsx +1 -1
  54. data/app/javascript/components/ImageGrid.jsx +132 -101
  55. data/app/javascript/components/ImageUploader.tsx +59 -55
  56. data/app/javascript/components/Modal.tsx +2 -4
  57. data/app/javascript/components/PageDates.jsx +25 -20
  58. data/app/javascript/components/PageFiles.jsx +7 -5
  59. data/app/javascript/components/PageImages.tsx +9 -7
  60. data/app/javascript/components/PageTree/Draggable.tsx +46 -40
  61. data/app/javascript/components/PageTree/Node.tsx +111 -95
  62. data/app/javascript/components/PageTree/types.ts +9 -9
  63. data/app/javascript/components/PageTree.tsx +44 -29
  64. data/app/javascript/components/RichTextArea.jsx +51 -37
  65. data/app/javascript/components/RichTextToolbarButton.tsx +8 -5
  66. data/app/javascript/components/TagEditor/AddTagForm.tsx +11 -10
  67. data/app/javascript/components/TagEditor/Tag.tsx +10 -8
  68. data/app/javascript/components/TagEditor.tsx +15 -10
  69. data/app/javascript/components/Toast.tsx +3 -7
  70. data/app/javascript/components/drag/draggedOrder.ts +16 -15
  71. data/app/javascript/components/drag/types.ts +12 -12
  72. data/app/javascript/components/drag/useDragCollection.ts +36 -42
  73. data/app/javascript/components/drag/useDragUploader.ts +3 -2
  74. data/app/javascript/components/drag.ts +5 -4
  75. data/app/javascript/controllers/LoginController.ts +0 -1
  76. data/app/javascript/controllers/MainController.ts +6 -2
  77. data/app/javascript/controllers/PageOptionsController.js +7 -2
  78. data/app/javascript/features/RichText.tsx +9 -7
  79. data/app/javascript/index.ts +5 -3
  80. data/app/javascript/lib/Tree.ts +27 -24
  81. data/app/javascript/lib/copyToClipboard.ts +5 -4
  82. data/app/javascript/lib/readyHandler.ts +4 -4
  83. data/app/javascript/lib/request.ts +7 -3
  84. data/app/javascript/stores/useModalStore.ts +3 -3
  85. data/app/javascript/stores/useToastStore.ts +14 -12
  86. data/app/javascript/types.ts +22 -22
  87. data/app/models/concerns/pages_core/page_model/templateable.rb +1 -1
  88. data/app/views/admin/calendars/show.html.erb +1 -1
  89. data/app/views/admin/news/index.html.erb +1 -1
  90. data/app/views/admin/pages/_edit_files.html.erb +1 -1
  91. data/app/views/admin/pages/_edit_images.html.erb +1 -1
  92. data/app/views/admin/pages/_list_item.html.erb +1 -1
  93. data/app/views/admin/pages/_search_bar.html.erb +1 -1
  94. data/app/views/admin/pages/deleted.html.erb +2 -2
  95. data/app/views/admin/pages/edit.html.erb +3 -3
  96. data/app/views/admin/pages/index.html.erb +4 -4
  97. data/app/views/admin/pages/new.html.erb +1 -1
  98. data/app/views/admin/pages/search.html.erb +3 -3
  99. data/app/views/feeds/pages.rss.builder +2 -2
  100. data/app/views/layouts/admin/_page_header.html.erb +4 -4
  101. data/app/views/layouts/admin.html.erb +1 -2
  102. data/config/locales/en.yml +1 -0
  103. data/lib/pages_core/pages_plugin.rb +5 -3
  104. data/lib/rails/generators/pages_core/frontend/templates/application.html.erb +15 -13
  105. data/lib/tasks/pages/reports.rake +26 -0
  106. metadata +32 -4
  107. data/app/helpers/pages_core/admin/deprecated_admin_helper.rb +0 -40
  108. data/app/views/pages_core/_google_analytics.html.erb +0 -8
@@ -4,9 +4,9 @@ import { ImageResource } from "../../types";
4
4
  import { DragState } from "../drag";
5
5
 
6
6
  interface DragElementProps {
7
- container: RefObject<HTMLDivElement>,
8
- draggable: string | { record: { image: ImageResource, src?: string } },
9
- dragState: DragState
7
+ container: RefObject<HTMLDivElement>;
8
+ draggable: string | { record: { image: ImageResource; src?: string } };
9
+ dragState: DragState;
10
10
  }
11
11
 
12
12
  export default function DragElement(props: DragElementProps) {
@@ -24,7 +24,9 @@ export default function DragElement(props: DragElementProps) {
24
24
  return (
25
25
  <div className="drag-image" style={translateStyle}>
26
26
  {"record" in draggable && draggable.record.image && (
27
- <img src={draggable.record.src || draggable.record.image.thumbnail_url} />
27
+ <img
28
+ src={draggable.record.src || draggable.record.image.thumbnail_url}
29
+ />
28
30
  )}
29
31
  </div>
30
32
  );
@@ -8,25 +8,25 @@ import Placeholder from "./Placeholder";
8
8
  import { useDraggable } from "../drag";
9
9
 
10
10
  interface Record {
11
- id: number | null,
12
- image: ImageResource,
13
- src: string | null,
14
- file: File | null
11
+ id: number | null;
12
+ image: ImageResource;
13
+ src: string | null;
14
+ file: File | null;
15
15
  }
16
16
 
17
17
  interface GridImageProps {
18
- draggable: { handle: string, record: Record }
19
- attributeName: string,
20
- locale: string,
21
- locales: { [index: string]: Locale },
22
- placeholder: boolean,
23
- enablePrimary: boolean,
24
- showEmbed: boolean,
25
- primary: boolean,
26
- position: number,
27
- deleteImage: () => void,
28
- startDrag: (evt: Event, draggable: Draggable) => void,
29
- onUpdate: (newImage: ImageResource, src: string) => void
18
+ draggable: { handle: string; record: Record };
19
+ attributeName: string;
20
+ locale: string;
21
+ locales: { [index: string]: Locale };
22
+ placeholder: boolean;
23
+ enablePrimary: boolean;
24
+ showEmbed: boolean;
25
+ primary: boolean;
26
+ position: number;
27
+ deleteImage: () => void;
28
+ startDrag: (evt: Event, draggable: Draggable) => void;
29
+ onUpdate: (newImage: ImageResource, src: string) => void;
30
30
  }
31
31
 
32
32
  export default function GridImage(props: GridImageProps) {
@@ -70,44 +70,48 @@ export default function GridImage(props: GridImageProps) {
70
70
  }
71
71
 
72
72
  return (
73
- <div className={classes.join(" ")}
74
- {...dragAttrs}>
75
- <input name={`${attributeName}[id]`}
76
- type="hidden" value={record.id || ""} />
77
- <input name={`${attributeName}[image_id]`}
78
- type="hidden" value={(image && image.id) || ""} />
79
- <input name={`${attributeName}[position]`}
80
- type="hidden" value={props.position} />
73
+ <div className={classes.join(" ")} {...dragAttrs}>
74
+ <input
75
+ name={`${attributeName}[id]`}
76
+ type="hidden"
77
+ value={record.id || ""}
78
+ />
79
+ <input
80
+ name={`${attributeName}[image_id]`}
81
+ type="hidden"
82
+ value={(image && image.id) || ""}
83
+ />
84
+ <input
85
+ name={`${attributeName}[position]`}
86
+ type="hidden"
87
+ value={props.position}
88
+ />
81
89
  {props.enablePrimary && (
82
- <input name={`${attributeName}[primary]`}
83
- type="hidden" value={props.primary} />
90
+ <input
91
+ name={`${attributeName}[primary]`}
92
+ type="hidden"
93
+ value={props.primary}
94
+ />
95
+ )}
96
+ {!image && <Placeholder src={src} />}
97
+ {image && (
98
+ <>
99
+ <EditableImage
100
+ image={image}
101
+ key={props.placeholder ? "placeholder" : draggable.handle}
102
+ src={src || image.thumbnail_url}
103
+ width={250}
104
+ caption={true}
105
+ locale={props.locale}
106
+ locales={props.locales}
107
+ onUpdate={props.onUpdate}
108
+ />
109
+ <div className="actions">
110
+ {props.showEmbed && <button onClick={copyEmbed}>Embed</button>}
111
+ {props.deleteImage && <button onClick={deleteImage}>Remove</button>}
112
+ </div>
113
+ </>
84
114
  )}
85
- {!image &&
86
- <Placeholder src={src} />}
87
- {image &&
88
- <>
89
- <EditableImage
90
- image={image}
91
- key={props.placeholder ? "placeholder" : draggable.handle}
92
- src={src || image.thumbnail_url}
93
- width={250}
94
- caption={true}
95
- locale={props.locale}
96
- locales={props.locales}
97
- onUpdate={props.onUpdate} />
98
- <div className="actions">
99
- {props.showEmbed && (
100
- <button onClick={copyEmbed}>
101
- Embed
102
- </button>
103
- )}
104
- {props.deleteImage && (
105
- <button onClick={deleteImage}>
106
- Remove
107
- </button>
108
- )}
109
- </div>
110
- </>}
111
115
  </div>
112
116
  );
113
117
  }
@@ -1,7 +1,7 @@
1
1
  import React from "react";
2
2
 
3
3
  interface PlaceholderProps {
4
- src: string
4
+ src: string;
5
5
  }
6
6
 
7
7
  export default function Placeholder(props: PlaceholderProps) {
@@ -7,26 +7,35 @@ import GridImage from "./ImageGrid/GridImage";
7
7
  import useToastStore from "../stores/useToastStore";
8
8
  import { post } from "../lib/request";
9
9
 
10
- import { createDraggable,
11
- collectionOrder,
12
- useDragCollection,
13
- useDragUploader } from "./drag";
10
+ import {
11
+ createDraggable,
12
+ collectionOrder,
13
+ useDragCollection,
14
+ useDragUploader
15
+ } from "./drag";
14
16
 
15
17
  function filterFiles(files) {
16
- const validMimeTypes = ["image/gif",
17
- "image/jpeg",
18
- "image/pjpeg",
19
- "image/png",
20
- "image/tiff"];
21
- return files.filter(f => (validMimeTypes.indexOf(f.type) !== -1));
18
+ const validMimeTypes = [
19
+ "image/gif",
20
+ "image/jpeg",
21
+ "image/pjpeg",
22
+ "image/png",
23
+ "image/tiff"
24
+ ];
25
+ return files.filter((f) => validMimeTypes.indexOf(f.type) !== -1);
22
26
  }
23
27
 
24
28
  function draggedImageOrder(primaryCollection, imagesCollection, dragState) {
25
29
  const [primary, ...rest] = collectionOrder(primaryCollection, dragState);
26
30
  let images = [...rest, ...collectionOrder(imagesCollection, dragState)];
27
31
 
28
- if (dragState.dragging && [primary, ...images].indexOf(dragState.dragging) === -1) {
29
- if (dragState.y < imagesCollection.ref.current.getBoundingClientRect().top) {
32
+ if (
33
+ dragState.dragging &&
34
+ [primary, ...images].indexOf(dragState.dragging) === -1
35
+ ) {
36
+ if (
37
+ dragState.y < imagesCollection.ref.current.getBoundingClientRect().top
38
+ ) {
30
39
  images = [dragState.dragging, ...images];
31
40
  } else {
32
41
  images.push(dragState.dragging);
@@ -37,11 +46,11 @@ function draggedImageOrder(primaryCollection, imagesCollection, dragState) {
37
46
  }
38
47
 
39
48
  function initRecords(props) {
40
- const primary = props.enablePrimary ?
41
- props.records.filter(r => r.primary).slice(0, 1) :
42
- [];
49
+ const primary = props.enablePrimary
50
+ ? props.records.filter((r) => r.primary).slice(0, 1)
51
+ : [];
43
52
 
44
- return [primary, props.records.filter(r => primary.indexOf(r) === -1)];
53
+ return [primary, props.records.filter((r) => primary.indexOf(r) === -1)];
45
54
  }
46
55
 
47
56
  export default function ImageGrid(props) {
@@ -59,8 +68,11 @@ export default function ImageGrid(props) {
59
68
  };
60
69
 
61
70
  const dragEnd = (dragState, files) => {
62
- const [draggedPrimary,
63
- draggedImages] = draggedImageOrder(primary, images, dragState);
71
+ const [draggedPrimary, draggedImages] = draggedImageOrder(
72
+ primary,
73
+ images,
74
+ dragState
75
+ );
64
76
 
65
77
  primary.dispatch({
66
78
  type: "reorder",
@@ -69,19 +81,24 @@ export default function ImageGrid(props) {
69
81
  images.dispatch({ type: "reorder", payload: draggedImages });
70
82
 
71
83
  if (files) {
72
- const uploads = filterFiles(files).map(f => uploadImage(f));
84
+ const uploads = filterFiles(files).map((f) => uploadImage(f));
73
85
  dispatchAll({ type: "insertFiles", payload: uploads });
74
86
  }
75
87
  };
76
88
 
77
- const [dragState,
78
- dragStart,
79
- listeners] = useDragUploader([primary, images], dragEnd);
89
+ const [dragState, dragStart, listeners] = useDragUploader(
90
+ [primary, images],
91
+ dragEnd
92
+ );
80
93
 
81
94
  const position = (record) => {
82
- return [...primary.draggables.map(d => d.record),
83
- ...images.draggables.map(d => d.record),
84
- ...deleted].indexOf(record) + 1;
95
+ return (
96
+ [
97
+ ...primary.draggables.map((d) => d.record),
98
+ ...images.draggables.map((d) => d.record),
99
+ ...deleted
100
+ ].indexOf(record) + 1
101
+ );
85
102
  };
86
103
 
87
104
  const attrName = (record) => {
@@ -89,26 +106,23 @@ export default function ImageGrid(props) {
89
106
  };
90
107
 
91
108
  const uploadImage = (file) => {
92
- const draggable = createDraggable(
93
- { image: null, file: file }
94
- );
109
+ const draggable = createDraggable({ image: null, file: file });
95
110
 
96
111
  let data = new FormData();
97
112
 
98
113
  data.append("image[file]", file);
99
114
 
100
- post("/admin/images.json", data)
101
- .then(json => {
102
- if (json.status === "error") {
103
- error("Error uploading image: " + json.error);
104
- dispatchAll({ type: "remove", payload: draggable });
105
- } else {
106
- dispatchAll({
107
- type: "update",
108
- payload: { ...draggable, record: { image: json } }
109
- });
110
- }
111
- });
115
+ post("/admin/images.json", data).then((json) => {
116
+ if (json.status === "error") {
117
+ error("Error uploading image: " + json.error);
118
+ dispatchAll({ type: "remove", payload: draggable });
119
+ } else {
120
+ dispatchAll({
121
+ type: "update",
122
+ payload: { ...draggable, record: { image: json } }
123
+ });
124
+ }
125
+ });
112
126
 
113
127
  return draggable;
114
128
  };
@@ -136,28 +150,30 @@ export default function ImageGrid(props) {
136
150
  const { dragging } = dragState;
137
151
 
138
152
  if (draggable === "Files") {
139
- return (<FilePlaceholder key="placeholder" />);
153
+ return <FilePlaceholder key="placeholder" />;
140
154
  }
141
155
 
142
156
  return (
143
- <GridImage key={draggable.handle}
144
- draggable={draggable}
145
- locale={props.locale}
146
- locales={props.locales}
147
- showEmbed={props.showEmbed}
148
- startDrag={dragStart}
149
- position={position(draggable.record)}
150
- primary={isPrimary}
151
- onUpdate={update(draggable)}
152
- enablePrimary={props.enablePrimary}
153
- deleteImage={remove(draggable)}
154
- attributeName={attrName(draggable.record)}
155
- placeholder={dragging && dragging == draggable} />
157
+ <GridImage
158
+ key={draggable.handle}
159
+ draggable={draggable}
160
+ locale={props.locale}
161
+ locales={props.locales}
162
+ showEmbed={props.showEmbed}
163
+ startDrag={dragStart}
164
+ position={position(draggable.record)}
165
+ primary={isPrimary}
166
+ onUpdate={update(draggable)}
167
+ enablePrimary={props.enablePrimary}
168
+ deleteImage={remove(draggable)}
169
+ attributeName={attrName(draggable.record)}
170
+ placeholder={dragging && dragging == draggable}
171
+ />
156
172
  );
157
173
  };
158
174
 
159
175
  const uploadPrimary = (files) => {
160
- const [first, ...rest] = filterFiles(files).map(f => uploadImage(f));
176
+ const [first, ...rest] = filterFiles(files).map((f) => uploadImage(f));
161
177
  if (first) {
162
178
  images.dispatch({
163
179
  type: "prepend",
@@ -170,7 +186,7 @@ export default function ImageGrid(props) {
170
186
  const uploadAdditional = (files) => {
171
187
  images.dispatch({
172
188
  type: "append",
173
- payload: filterFiles(files).map(f => uploadImage(f))
189
+ payload: filterFiles(files).map((f) => uploadImage(f))
174
190
  });
175
191
  };
176
192
 
@@ -179,67 +195,82 @@ export default function ImageGrid(props) {
179
195
  classNames.push("with-primary-image");
180
196
  }
181
197
 
182
- const [draggedPrimary,
183
- draggedImages] = draggedImageOrder(primary, images, dragState);
198
+ const [draggedPrimary, draggedImages] = draggedImageOrder(
199
+ primary,
200
+ images,
201
+ dragState
202
+ );
184
203
 
185
204
  return (
186
- <div className={classNames.join(" ")}
187
- ref={containerRef}
188
- {...listeners}>
189
- {dragState.dragging &&
190
- <DragElement draggable={dragState.dragging}
191
- dragState={dragState}
192
- container={containerRef} />}
205
+ <div className={classNames.join(" ")} ref={containerRef} {...listeners}>
206
+ {dragState.dragging && (
207
+ <DragElement
208
+ draggable={dragState.dragging}
209
+ dragState={dragState}
210
+ container={containerRef}
211
+ />
212
+ )}
193
213
  {props.enablePrimary && (
194
214
  <div className="primary-image" ref={primary.ref}>
195
- <h3>
196
- Main image
197
- </h3>
198
- {draggedPrimary &&
199
- <>
200
- {renderImage(draggedPrimary, true)}
201
- {props.primaryAttribute && (
202
- <input type="hidden" name={props.primaryAttribute}
203
- value={(draggedPrimary.record &&
204
- draggedPrimary.record.image &&
205
- draggedPrimary.record.image.id) || ""} />
206
- )}
207
- </>}
215
+ <h3>Main image</h3>
216
+ {draggedPrimary && (
217
+ <>
218
+ {renderImage(draggedPrimary, true)}
219
+ {props.primaryAttribute && (
220
+ <input
221
+ type="hidden"
222
+ name={props.primaryAttribute}
223
+ value={
224
+ (draggedPrimary.record &&
225
+ draggedPrimary.record.image &&
226
+ draggedPrimary.record.image.id) ||
227
+ ""
228
+ }
229
+ />
230
+ )}
231
+ </>
232
+ )}
208
233
  {!draggedPrimary && (
209
234
  <div className="drop-target">
210
- <FileUploadButton multiple={true}
211
- type="image"
212
- multiline={true}
213
- callback={uploadPrimary} />
214
- </div>)}
235
+ <FileUploadButton
236
+ multiple={true}
237
+ type="image"
238
+ multiline={true}
239
+ callback={uploadPrimary}
240
+ />
241
+ </div>
242
+ )}
215
243
  </div>
216
244
  )}
217
245
  <div className="grid" ref={images.ref}>
218
- <h3>
219
- {props.enablePrimary ? "More images" : "Images"}
220
- </h3>
246
+ <h3>{props.enablePrimary ? "More images" : "Images"}</h3>
221
247
  <div className="drop-target">
222
- <FileUploadButton multiple={true}
223
- type="image"
224
- callback={uploadAdditional} />
248
+ <FileUploadButton
249
+ multiple={true}
250
+ type="image"
251
+ callback={uploadAdditional}
252
+ />
225
253
  </div>
226
254
  <div className="images">
227
- {draggedImages.map(r => renderImage(r, false))}
255
+ {draggedImages.map((r) => renderImage(r, false))}
228
256
  </div>
229
257
  </div>
230
258
  <div className="deleted">
231
- {deleted.map(r =>
259
+ {deleted.map((r) => (
232
260
  <span className="deleted-image" key={r.id}>
233
- <input name={`${attrName(r)}[id]`}
234
- type="hidden"
235
- value={r.id} />
236
- <input name={`${attrName(r)}[attachment_id]`}
237
- type="hidden"
238
- value={(r.image && r.image.id) || ""} />
239
- <input name={`${attrName(r)}[_destroy]`}
240
- type="hidden"
241
- value={true} />
242
- </span>)}
261
+ <input name={`${attrName(r)}[id]`} type="hidden" value={r.id} />
262
+ <input
263
+ name={`${attrName(r)}[attachment_id]`}
264
+ type="hidden"
265
+ value={(r.image && r.image.id) || ""}
266
+ />
267
+ <input
268
+ name={`${attrName(r)}[_destroy]`}
269
+ type="hidden"
270
+ value={true}
271
+ />
272
+ </span>
273
+ ))}
243
274
  </div>
244
275
  </div>
245
276
  );
@@ -5,17 +5,17 @@ import useToastStore from "../stores/useToastStore";
5
5
  import { ImageResource, Locale } from "../types";
6
6
  import { post } from "../lib/request";
7
7
 
8
- type ImageResponse = ImageResource | { status: "error", error: string }
8
+ type ImageResponse = ImageResource | { status: "error"; error: string };
9
9
 
10
10
  interface ImageUploaderProps {
11
- locale: string,
12
- locales: { [index: string]: Locale },
13
- image: ImageResource,
14
- src: string,
15
- width: number,
16
- caption: boolean,
17
- attr: string,
18
- alternative: string
11
+ locale: string;
12
+ locales: { [index: string]: Locale };
13
+ image: ImageResource;
14
+ src: string;
15
+ width: number;
16
+ caption: boolean;
17
+ attr: string;
18
+ alternative: string;
19
19
  }
20
20
 
21
21
  function getFiles(dt: DataTransfer): File[] {
@@ -87,15 +87,19 @@ export default function ImageUploader(props: ImageUploaderProps) {
87
87
  };
88
88
 
89
89
  const uploadImage = (file: File) => {
90
- const validTypes = ["image/gif",
91
- "image/jpeg",
92
- "image/pjpeg",
93
- "image/png",
94
- "image/tiff"];
90
+ const validTypes = [
91
+ "image/gif",
92
+ "image/jpeg",
93
+ "image/pjpeg",
94
+ "image/png",
95
+ "image/tiff"
96
+ ];
95
97
 
96
98
  if (validTypes.indexOf(file.type) == -1) {
97
- alert("Invalid file type, only images in JPEG, PNG or GIF " +
98
- "formats are supported");
99
+ alert(
100
+ "Invalid file type, only images in JPEG, PNG or GIF " +
101
+ "formats are supported"
102
+ );
99
103
  return;
100
104
  }
101
105
 
@@ -111,19 +115,18 @@ export default function ImageUploader(props: ImageUploaderProps) {
111
115
 
112
116
  data.append("image[file]", file);
113
117
  locales.forEach((l) => {
114
- data.append(`image[alternative][${l}]`, (props.alternative || ""));
118
+ data.append(`image[alternative][${l}]`, props.alternative || "");
115
119
  });
116
120
 
117
- void post("/admin/images.json", data)
118
- .then((response: ImageResponse) => {
119
- setUploading(false);
120
- if ("status" in response && response.status === "error") {
121
- error(`Error uploading image: ${response.error}`);
122
- } else if ("thumbnail_url" in response) {
123
- setSrc(response.thumbnail_url);
124
- setImage(response);
125
- }
126
- });
121
+ void post("/admin/images.json", data).then((response: ImageResponse) => {
122
+ setUploading(false);
123
+ if ("status" in response && response.status === "error") {
124
+ error(`Error uploading image: ${response.error}`);
125
+ } else if ("thumbnail_url" in response) {
126
+ setSrc(response.thumbnail_url);
127
+ setImage(response);
128
+ }
129
+ });
127
130
  };
128
131
 
129
132
  const classes = ["image-uploader"];
@@ -133,38 +136,39 @@ export default function ImageUploader(props: ImageUploaderProps) {
133
136
  classes.push("dragover");
134
137
  }
135
138
  return (
136
- <div className={classes.join(" ")}
137
- onDragOver={handleDragOver}
138
- onDragLeave={handleDragLeave}
139
- onDragEnd={handleDragEnd}
140
- onDrop={handleDrop}>
141
- <input type="hidden"
142
- name={props.attr}
143
- value={image ? image.id : ""} />
144
- {image &&
145
- <div className="image">
146
- <EditableImage image={image}
147
- src={src}
148
- width={props.width}
149
- caption={props.caption}
150
- locale={props.locale}
151
- locales={props.locales} />
152
- </div>}
139
+ <div
140
+ className={classes.join(" ")}
141
+ onDragOver={handleDragOver}
142
+ onDragLeave={handleDragLeave}
143
+ onDragEnd={handleDragEnd}
144
+ onDrop={handleDrop}>
145
+ <input type="hidden" name={props.attr} value={image ? image.id : ""} />
146
+ {image && (
147
+ <div className="image">
148
+ <EditableImage
149
+ image={image}
150
+ src={src}
151
+ width={props.width}
152
+ caption={props.caption}
153
+ locale={props.locale}
154
+ locales={props.locales}
155
+ />
156
+ </div>
157
+ )}
153
158
  <div className="ui-wrapper">
154
- {uploading && (
155
- <div className="ui">
156
- Uploading image...
157
- </div>
158
- )}
159
+ {uploading && <div className="ui">Uploading image...</div>}
159
160
  {!uploading && (
160
161
  <div className="ui">
161
- <FileUploadButton type="image"
162
- multiline={true}
163
- callback={receiveFiles} />
162
+ <FileUploadButton
163
+ type="image"
164
+ multiline={true}
165
+ callback={receiveFiles}
166
+ />
164
167
  {image && (
165
- <a className="delete remove-image"
166
- href="#"
167
- onClick={handleRemove}>
168
+ <a
169
+ className="delete remove-image"
170
+ href="#"
171
+ onClick={handleRemove}>
168
172
  Remove image
169
173
  </a>
170
174
  )}
@@ -37,12 +37,10 @@ export default function Modal() {
37
37
  return (
38
38
  <div className="modal-wrapper open">
39
39
  <div className="background" onClick={handleClose} />
40
- <div className="modal">
41
- {component}
42
- </div>
40
+ <div className="modal">{component}</div>
43
41
  </div>
44
42
  );
45
43
  } else {
46
- return (<div className="modal-wrapper"></div>);
44
+ return <div className="modal-wrapper"></div>;
47
45
  }
48
46
  }