pages_core 3.12.0 → 3.12.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (199) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/app/assets/builds/fonts/661557ef.ttf +0 -0
  4. data/app/assets/builds/fonts/a18fc2d2.woff2 +0 -0
  5. data/app/assets/builds/fonts/b2c7b78f.woff2 +0 -0
  6. data/app/assets/builds/fonts/ceddc204.ttf +0 -0
  7. data/app/assets/builds/pages_core/admin-dist.js +60 -14
  8. data/app/assets/builds/pages_core/admin-dist.js.map +7 -0
  9. data/app/assets/builds/pages_core/admin.css +9272 -0
  10. data/app/assets/images/pages/admin/angle-down-solid.svg +1 -0
  11. data/app/assets/images/pages/admin/icon.svg +1 -0
  12. data/app/assets/stylesheets/pages_core/admin/components/archive.css +6 -0
  13. data/app/assets/stylesheets/{pages/admin/components/attachments.scss → pages_core/admin/components/attachments.css} +35 -28
  14. data/app/assets/stylesheets/{pages/admin.scss → pages_core/admin/components/base.css} +125 -123
  15. data/app/assets/stylesheets/pages_core/admin/components/forms.css +223 -0
  16. data/app/assets/stylesheets/{pages/admin/components/header.scss → pages_core/admin/components/header.css} +76 -46
  17. data/app/assets/stylesheets/{pages/admin/components/image_editor.scss → pages_core/admin/components/image_editor.css} +42 -31
  18. data/app/assets/stylesheets/{pages/admin/components/image_grid.scss → pages_core/admin/components/image_grid.css} +76 -64
  19. data/app/assets/stylesheets/{pages/admin/components/image_uploader.scss → pages_core/admin/components/image_uploader.css} +12 -12
  20. data/app/assets/stylesheets/{pages/admin/components/layout.scss → pages_core/admin/components/layout.css} +13 -9
  21. data/app/assets/stylesheets/pages_core/admin/components/links.css +40 -0
  22. data/app/assets/stylesheets/pages_core/admin/components/list_table.css +66 -0
  23. data/app/assets/stylesheets/{pages/admin/components/login.scss → pages_core/admin/components/login.css} +6 -5
  24. data/app/assets/stylesheets/{pages/admin/components/modal.scss → pages_core/admin/components/modal.css} +10 -12
  25. data/app/assets/stylesheets/{pages/admin/components/page_tree.scss → pages_core/admin/components/page_tree.css} +54 -55
  26. data/app/assets/stylesheets/{pages/admin/components/pagination.scss → pages_core/admin/components/pagination.css} +17 -17
  27. data/app/assets/stylesheets/pages_core/admin/components/search.css +27 -0
  28. data/app/assets/stylesheets/{pages/admin/components/sidebar.scss → pages_core/admin/components/sidebar.css} +8 -7
  29. data/app/assets/stylesheets/{pages/admin/components/tag_editor.scss → pages_core/admin/components/tag_editor.css} +10 -15
  30. data/app/assets/stylesheets/{pages/admin/components/textarea.scss → pages_core/admin/components/textarea.css} +1 -1
  31. data/app/assets/stylesheets/{pages/admin/components/toast.scss → pages_core/admin/components/toast.css} +5 -3
  32. data/app/assets/stylesheets/{pages/admin/components/toolbar.scss → pages_core/admin/components/toolbar.css} +56 -29
  33. data/app/assets/stylesheets/{pages/admin/controllers/pages.scss → pages_core/admin/controllers/pages.css} +69 -52
  34. data/app/assets/stylesheets/pages_core/admin/controllers/users.css +3 -0
  35. data/app/assets/stylesheets/pages_core/admin/vars.css +34 -0
  36. data/app/assets/stylesheets/pages_core/admin.postcss.css +9 -0
  37. data/app/controllers/admin/pages_controller.rb +12 -11
  38. data/app/controllers/concerns/pages_core/rss_controller.rb +17 -1
  39. data/app/controllers/pages_core/admin_controller.rb +6 -0
  40. data/app/controllers/pages_core/frontend/pages_controller.rb +9 -5
  41. data/app/controllers/pages_core/sitemaps_controller.rb +3 -5
  42. data/app/formatters/pages_core/image_embedder.rb +5 -27
  43. data/app/helpers/admin/calendars_helper.rb +8 -0
  44. data/app/helpers/admin/news_helper.rb +13 -0
  45. data/app/helpers/admin/pages_helper.rb +32 -0
  46. data/app/helpers/pages_core/admin/admin_helper.rb +11 -54
  47. data/app/helpers/pages_core/admin/deprecated_admin_helper.rb +40 -0
  48. data/app/helpers/pages_core/images_helper.rb +37 -0
  49. data/app/javascript/admin-dist.ts +2 -0
  50. data/app/javascript/components/Attachments/{Attachment.jsx → Attachment.tsx} +44 -35
  51. data/app/javascript/components/Attachments/{AttachmentEditor.jsx → AttachmentEditor.tsx} +23 -23
  52. data/app/javascript/components/{EditableImage.jsx → EditableImage.tsx} +28 -25
  53. data/app/javascript/components/{FileUploadButton.jsx → FileUploadButton.tsx} +15 -16
  54. data/app/javascript/components/ImageCropper/FocalPoint.tsx +94 -0
  55. data/app/javascript/components/ImageCropper/{Image.jsx → Image.tsx} +13 -14
  56. data/app/javascript/components/ImageCropper/{Toolbar.jsx → Toolbar.tsx} +19 -15
  57. data/app/javascript/components/ImageCropper/{useCrop.js → useCrop.ts} +80 -37
  58. data/app/javascript/components/{ImageCropper.jsx → ImageCropper.tsx} +17 -15
  59. data/app/javascript/components/ImageEditor/{Form.jsx → Form.tsx} +24 -23
  60. data/app/javascript/components/{ImageEditor.jsx → ImageEditor.tsx} +17 -15
  61. data/app/javascript/components/ImageGrid/{DragElement.jsx → DragElement.tsx} +12 -10
  62. data/app/javascript/components/ImageGrid/{GridImage.jsx → GridImage.tsx} +40 -30
  63. data/app/javascript/components/ImageGrid/{Placeholder.jsx → Placeholder.tsx} +5 -6
  64. data/app/javascript/components/ImageGrid.jsx +3 -4
  65. data/app/javascript/components/{ImageUploader.jsx → ImageUploader.tsx} +46 -41
  66. data/app/javascript/components/Modal.tsx +48 -0
  67. data/app/javascript/components/PageImages.tsx +28 -0
  68. data/app/javascript/components/{PageTreeDraggable.jsx → PageTree/Draggable.tsx} +79 -57
  69. data/app/javascript/components/{PageTreeNode.jsx → PageTree/Node.tsx} +86 -77
  70. data/app/javascript/components/PageTree/types.ts +15 -0
  71. data/app/javascript/components/PageTree.tsx +206 -0
  72. data/app/javascript/components/RichTextToolbarButton.tsx +17 -0
  73. data/app/javascript/components/TagEditor/{AddTagForm.jsx → AddTagForm.tsx} +9 -10
  74. data/app/javascript/components/TagEditor/{Tag.jsx → Tag.tsx} +8 -9
  75. data/app/javascript/components/{TagEditor.jsx → TagEditor.tsx} +12 -13
  76. data/app/javascript/components/Toast.tsx +61 -0
  77. data/app/javascript/components/drag/{draggedOrder.js → draggedOrder.ts} +22 -12
  78. data/app/javascript/components/drag/types.ts +28 -0
  79. data/app/javascript/components/drag/{useDragCollection.js → useDragCollection.ts} +40 -22
  80. data/app/javascript/components/drag/{useDragUploader.js → useDragUploader.ts} +34 -25
  81. data/app/javascript/components/drag/useDraggable.ts +21 -0
  82. data/app/javascript/components/{drag.js → drag.ts} +1 -0
  83. data/app/javascript/controllers/{EditPageController.js → EditPageController.ts} +3 -1
  84. data/app/javascript/controllers/{LoginController.js → LoginController.ts} +7 -3
  85. data/app/javascript/controllers/{MainController.js → MainController.ts} +19 -14
  86. data/app/javascript/{index.js → index.ts} +8 -7
  87. data/app/javascript/lib/{Tree.js → Tree.ts} +106 -85
  88. data/app/javascript/lib/{copyToClipboard.js → copyToClipboard.ts} +1 -1
  89. data/app/javascript/lib/{readyHandler.js → readyHandler.ts} +4 -2
  90. data/app/javascript/lib/{request.js → request.ts} +11 -5
  91. data/app/javascript/stores/useModalStore.ts +15 -0
  92. data/app/javascript/stores/useToastStore.ts +26 -0
  93. data/app/javascript/stores.ts +2 -0
  94. data/app/javascript/types.ts +30 -0
  95. data/app/mailers/admin_mailer.rb +1 -0
  96. data/app/models/invite.rb +8 -0
  97. data/app/policies/page_policy.rb +4 -0
  98. data/app/views/admin/calendars/_sidebar.html.erb +50 -0
  99. data/app/views/admin/calendars/show.html.erb +15 -53
  100. data/app/views/admin/invites/new.html.erb +2 -8
  101. data/app/views/admin/invites/show.html.erb +2 -4
  102. data/app/views/admin/news/_sidebar.html.erb +51 -0
  103. data/app/views/admin/news/index.html.erb +21 -56
  104. data/app/views/admin/pages/_list_item.html.erb +4 -22
  105. data/app/views/admin/pages/_search_bar.html.erb +12 -0
  106. data/app/views/admin/pages/deleted.html.erb +10 -8
  107. data/app/views/admin/pages/edit.html.erb +20 -11
  108. data/app/views/admin/pages/index.html.erb +10 -8
  109. data/app/views/admin/pages/new.html.erb +10 -14
  110. data/app/views/admin/pages/search.html.erb +54 -0
  111. data/app/views/admin/password_resets/show.html.erb +3 -5
  112. data/app/views/admin/users/deactivated.html.erb +6 -7
  113. data/app/views/admin/users/edit.html.erb +7 -9
  114. data/app/views/admin/users/index.html.erb +3 -6
  115. data/app/views/admin/users/login.html.erb +4 -5
  116. data/app/views/admin/users/new.html.erb +2 -4
  117. data/app/views/admin/users/new_password.html.erb +4 -5
  118. data/app/views/admin/users/show.html.erb +11 -9
  119. data/app/views/errors/401.html.erb +2 -1
  120. data/app/views/errors/403.html.erb +2 -1
  121. data/app/views/errors/404.html.erb +1 -3
  122. data/app/views/errors/405.html.erb +2 -1
  123. data/app/views/errors/422.html.erb +2 -1
  124. data/app/views/errors/500.html.erb +2 -3
  125. data/app/views/feeds/pages.rss.builder +3 -9
  126. data/app/views/layouts/admin/_header.html.erb +1 -2
  127. data/app/views/layouts/admin/_page_header.html.erb +4 -4
  128. data/app/views/layouts/admin.html.erb +3 -3
  129. data/app/views/layouts/errors.html.erb +127 -4
  130. data/config/routes.rb +1 -0
  131. data/lib/pages_core/configuration/pages.rb +0 -1
  132. data/lib/pages_core/engine.rb +4 -3
  133. data/lib/pages_core.rb +0 -1
  134. data/lib/rails/generators/pages_core/frontend/frontend_generator.rb +33 -17
  135. data/lib/rails/generators/pages_core/frontend/templates/application.html.erb +0 -1
  136. data/lib/rails/generators/pages_core/frontend/templates/javascript/lib/gridOverlay.ts +40 -0
  137. data/lib/rails/generators/pages_core/frontend/templates/javascript/lib/responsiveEmbeds.ts +68 -0
  138. data/lib/rails/generators/pages_core/frontend/templates/postcss.config.js +17 -0
  139. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/application.postcss.css +4 -0
  140. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/components/base.css +24 -0
  141. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/components/layout.css +21 -0
  142. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/config.css +5 -0
  143. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/global/animation.css +5 -0
  144. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/global/colors.css +18 -0
  145. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/global/fonts.css +6 -0
  146. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/global/grid.css +65 -0
  147. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/global/typography.css +131 -0
  148. data/lib/rails/generators/pages_core/install/templates/pages_initializer.rb +0 -3
  149. metadata +104 -255
  150. data/app/assets/images/pages/admin/icon.png +0 -0
  151. data/app/assets/images/pages/admin/image-editor-bg.png +0 -0
  152. data/app/assets/images/pages/admin/list-table-pin-blue.gif +0 -0
  153. data/app/assets/images/pages/admin/list-table-pin-disabled.gif +0 -0
  154. data/app/assets/images/pages/admin/list-table-pin-green.gif +0 -0
  155. data/app/assets/images/pages/admin/list-table-pin-red.gif +0 -0
  156. data/app/assets/images/pages/admin/list-table-pin-yellow.gif +0 -0
  157. data/app/assets/images/pages/admin/loading-modal.gif +0 -0
  158. data/app/assets/images/pages/feed-icon-14x14.png +0 -0
  159. data/app/assets/stylesheets/pages/admin/components/archive.scss +0 -6
  160. data/app/assets/stylesheets/pages/admin/components/buttons.scss +0 -23
  161. data/app/assets/stylesheets/pages/admin/components/forms.scss +0 -169
  162. data/app/assets/stylesheets/pages/admin/components/links.scss +0 -43
  163. data/app/assets/stylesheets/pages/admin/components/list_table.scss +0 -61
  164. data/app/assets/stylesheets/pages/admin/controllers/users.scss +0 -3
  165. data/app/assets/stylesheets/pages/admin/mixins/breakpoints.scss +0 -21
  166. data/app/assets/stylesheets/pages/admin/mixins/clearfix.scss +0 -7
  167. data/app/assets/stylesheets/pages/admin/mixins/gradients.scss +0 -7
  168. data/app/assets/stylesheets/pages/admin/vars.scss +0 -30
  169. data/app/assets/stylesheets/pages/errors.css +0 -128
  170. data/app/javascript/admin-dist.js +0 -2
  171. data/app/javascript/components/ImageCropper/FocalPoint.jsx +0 -93
  172. data/app/javascript/components/Modal.jsx +0 -59
  173. data/app/javascript/components/PageImages.jsx +0 -25
  174. data/app/javascript/components/PageTree.jsx +0 -196
  175. data/app/javascript/components/RichTextToolbarButton.jsx +0 -20
  176. data/app/javascript/components/Toast.jsx +0 -72
  177. data/app/javascript/components/drag/useDraggable.js +0 -17
  178. data/app/javascript/stores/ModalStore.jsx +0 -12
  179. data/app/javascript/stores/ToastStore.jsx +0 -14
  180. data/app/javascript/stores.js +0 -2
  181. data/lib/rails/generators/pages_core/frontend/templates/javascript/lib/GridOverlay.js +0 -66
  182. data/lib/rails/generators/pages_core/frontend/templates/javascript/lib/ResponsiveEmbeds.js +0 -72
  183. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/application.sass.scss +0 -15
  184. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/components/base.scss +0 -12
  185. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/config.scss +0 -26
  186. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/framework/breakpoints.scss +0 -42
  187. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/framework/clearfix.scss +0 -7
  188. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/framework/fonts.scss +0 -32
  189. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/framework/grid.scss +0 -168
  190. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/framework/grid_overlay.scss +0 -44
  191. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/global/colors.scss +0 -8
  192. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/global/typography.scss +0 -90
  193. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/vendor/normalize.css +0 -349
  194. data/vendor/assets/stylesheets/ReactCrop.css +0 -167
  195. /data/app/assets/stylesheets/{pages/admin/components/tabs.scss → pages_core/admin/components/tabs.css} +0 -0
  196. /data/app/javascript/components/Attachments/{Placeholder.jsx → Placeholder.tsx} +0 -0
  197. /data/app/javascript/components/ImageGrid/{FilePlaceholder.jsx → FilePlaceholder.tsx} +0 -0
  198. /data/app/javascript/{components.js → components.ts} +0 -0
  199. /data/app/javascript/{hooks.js → hooks.ts} +0 -0
@@ -1,20 +1,24 @@
1
1
  import { useEffect, useState } from "react";
2
2
 
3
- function containsFiles(evt) {
4
- if (!evt.dataTransfer || !evt.dataTransfer.types) {
5
- return false;
6
- }
7
- const types = evt.dataTransfer.types;
8
- for (var i = 0; i < types.length; i++) {
9
- if (types[i] === "Files" || types[i] === "application/x-moz-file") {
10
- return true;
3
+ import { Draggable, DragCollection, DragState, Position } from "./types";
4
+
5
+ function containsFiles(evt: Event) {
6
+ if ("dataTransfer" in evt) {
7
+ const dataTransfer: DataTransfer = evt.dataTransfer;
8
+ if ("types" in dataTransfer) {
9
+ const types = dataTransfer.types;
10
+ for (let i = 0; i < types.length; i++) {
11
+ if (types[i] === "Files" || types[i] === "application/x-moz-file") {
12
+ return true;
13
+ }
14
+ }
11
15
  }
12
16
  }
13
17
  return false;
14
18
  }
15
19
 
16
- function getFiles(dt) {
17
- var files = [];
20
+ function getFiles(dt: DataTransfer): File[] {
21
+ const files: File[] = [];
18
22
  if (dt.items) {
19
23
  for (let i = 0; i < dt.items.length; i++) {
20
24
  if (dt.items[i].kind == "file") {
@@ -29,36 +33,41 @@ function getFiles(dt) {
29
33
  return files;
30
34
  }
31
35
 
32
- function mousePosition(evt) {
33
- var x, y;
34
- if (evt.type == "touchmove") {
36
+ function mousePosition(evt: TouchEvent | MouseEvent): Position {
37
+ let x: number | null, y: number | null;
38
+ if ("touches" in evt && evt.type == "touchmove") {
35
39
  x = evt.touches[0].clientX;
36
40
  y = evt.touches[0].clientY;
37
- } else {
41
+ } else if (evt instanceof MouseEvent) {
38
42
  x = evt.clientX;
39
43
  y = evt.clientY;
40
44
  }
41
45
  return { x: x, y: y };
42
46
  }
43
47
 
44
- export default function useDragUploader(collections, onDragEnd) {
45
- const [dragState, setDragState] = useState({
48
+ export default function useDragUploader(
49
+ collections: DragCollection[],
50
+ onDragEnd: (dragState: DragState, files: File[]) => void
51
+ ) {
52
+ const initialState: DragState = {
46
53
  dragging: false,
47
54
  x: null, y: null
48
- });
55
+ };
56
+
57
+ const [dragState, setDragState] = useState(initialState);
49
58
 
50
- const updatePositions = (dragging) => {
59
+ const updatePositions = (dragging: Draggable | null) => {
51
60
  collections.forEach(c => {
52
61
  c.dispatch({ type: "updatePositions", payload: dragging });
53
62
  });
54
63
  };
55
64
 
56
- const startDrag = (evt, draggable) => {
65
+ const startDrag = (evt: Event, draggable: Draggable) => {
57
66
  updatePositions(draggable);
58
67
  setDragState({ dragging: draggable, ...mousePosition(evt) });
59
68
  };
60
69
 
61
- const drag = (evt) => {
70
+ const drag = (evt: Event) => {
62
71
  if (dragState.dragging) {
63
72
  evt.stopPropagation();
64
73
  evt.preventDefault();
@@ -70,13 +79,13 @@ export default function useDragUploader(collections, onDragEnd) {
70
79
  }
71
80
  };
72
81
 
73
- const dragEnd = (evt) => {
82
+ const dragEnd = (evt: Event) => {
74
83
  if (dragState.dragging) {
75
84
  const prevDragState = dragState;
76
- var files = [];
77
- evt.preventDefault();
85
+ let files: File[] = [];
78
86
  evt.stopPropagation();
79
- if (dragState.dragging == "Files") {
87
+ evt.preventDefault();
88
+ if ("dataTransfer" in evt && dragState.dragging == "Files") {
80
89
  files = getFiles(evt.dataTransfer);
81
90
  }
82
91
  setDragState({ dragging: false, x: null, y: null });
@@ -85,7 +94,7 @@ export default function useDragUploader(collections, onDragEnd) {
85
94
  }
86
95
  };
87
96
 
88
- const dragLeave = (evt) => {
97
+ const dragLeave = (evt: Event) => {
89
98
  if (dragState.dragging === "Files") {
90
99
  evt.preventDefault();
91
100
  evt.stopPropagation();
@@ -0,0 +1,21 @@
1
+ import React, { useEffect, useRef } from "react";
2
+ import { Draggable } from "./types";
3
+
4
+ export default function useDraggable(
5
+ draggable: Draggable,
6
+ startDrag: (evt: React.MouseEvent, draggable: Draggable) => void
7
+ ) {
8
+ const ref = useRef<HTMLDivElement>(null);
9
+
10
+ const handleDrag = (evt: Event) => {
11
+ evt.preventDefault();
12
+ evt.stopPropagation();
13
+ startDrag(evt, draggable);
14
+ };
15
+
16
+ useEffect(() => {
17
+ draggable.ref.current = ref.current;
18
+ }, []);
19
+
20
+ return { ref: ref, onDragStart: handleDrag, draggable: true };
21
+ }
@@ -1,3 +1,4 @@
1
+ export { Draggable, DragState } from "./drag/types";
1
2
  export { default as useDragCollection,
2
3
  createDraggable } from "./drag/useDragCollection";
3
4
  export { default as useDragUploader } from "./drag/useDragUploader";
@@ -1,6 +1,8 @@
1
1
  import { Controller } from "@hotwired/stimulus";
2
2
 
3
- export default class EditPageController extends Controller {
3
+ export default class EditPageController extends Controller<HTMLFormElement> {
4
+ readonly formTarget: HTMLFormElement;
5
+
4
6
  static get targets() {
5
7
  return ["form"];
6
8
  }
@@ -1,6 +1,8 @@
1
1
  import { Controller } from "@hotwired/stimulus";
2
2
 
3
3
  export default class LoginController extends Controller {
4
+ readonly tabTargets: HTMLDivElement[];
5
+
4
6
  static get targets() {
5
7
  return ["tab"];
6
8
  }
@@ -12,12 +14,14 @@ export default class LoginController extends Controller {
12
14
  }
13
15
 
14
16
 
15
- changeTab(evt) {
17
+ changeTab(evt: Event) {
16
18
  evt.preventDefault();
17
- this.showTab(evt.target.dataset.tab);
19
+ if ("dataset" in evt.target && "tab" in evt.target.dataset) {
20
+ this.showTab(evt.target.dataset.tab);
21
+ }
18
22
  }
19
23
 
20
- showTab(tab) {
24
+ showTab(tab: string) {
21
25
  this.tabTargets.forEach((t) => {
22
26
  if (t.dataset.tab == tab) {
23
27
  t.classList.remove("hidden");
@@ -1,18 +1,21 @@
1
1
  import { Controller } from "@hotwired/stimulus";
2
2
 
3
3
  export default class MainController extends Controller {
4
+ readonly linkTargets: HTMLLinkElement[];
5
+ readonly tabTargets: HTMLDivElement[];
6
+
4
7
  static get targets() {
5
8
  return ["tab", "link"];
6
9
  }
7
10
 
8
11
  connect() {
9
- let tabs = this.tabNames();
12
+ const tabs = this.tabNames();
10
13
  if (tabs.length > 0) {
11
- let initTab = null;
14
+ let initTab: string = null;
12
15
  const tabExpression = /#(.*)$/;
13
16
 
14
17
  if (document.location.toString().match(tabExpression)) {
15
- let id = document.location.toString().match(tabExpression)[1];
18
+ const id = document.location.toString().match(tabExpression)[1];
16
19
  if (tabs.indexOf(id) !== -1) {
17
20
  initTab = id;
18
21
  }
@@ -21,27 +24,29 @@ export default class MainController extends Controller {
21
24
  this.showTab(initTab || tabs[0]);
22
25
  }
23
26
 
24
- window.addEventListener("popstate", this.stateHandler.bind(this));
27
+ window.addEventListener("popstate", this.stateHandler);
25
28
  }
26
29
 
27
30
  disconnect() {
28
- window.removeEventListener("popstate", this.stateHandler.bind(this));
31
+ window.removeEventListener("popstate", this.stateHandler);
29
32
  }
30
33
 
31
- stateHandler(evt) {
32
- if (evt.state && evt.state.tabId) {
34
+ stateHandler = (evt: Event) => {
35
+ if ("state" in evt && "tabId" in evt.state) {
33
36
  this.showTab(evt.state.tabId);
34
37
  }
35
- }
38
+ };
36
39
 
37
- changeTab(evt) {
40
+ changeTab(evt: Event) {
38
41
  evt.preventDefault();
39
- const tab = evt.target.dataset.tab;
40
- this.showTab(tab);
41
- history.pushState({ tabId: tab }, "", `${window.location.pathname}#${tab}`);
42
+ if ("dataset" in evt.target && "tab" in evt.target.dataset) {
43
+ const tab = evt.target.dataset.tab as string;
44
+ this.showTab(tab);
45
+ history.pushState({ tabId: tab }, "", `${window.location.pathname}#${tab}`);
46
+ }
42
47
  }
43
48
 
44
- showTab(tab) {
49
+ showTab(tab: string | null) {
45
50
  this.linkTargets.forEach((l) => {
46
51
  if (l.dataset.tab == tab) {
47
52
  l.classList.add("current");
@@ -59,7 +64,7 @@ export default class MainController extends Controller {
59
64
  });
60
65
  }
61
66
 
62
- tabNames () {
67
+ tabNames (): string[] {
63
68
  return this.linkTargets.map((l) => l.dataset.tab);
64
69
  }
65
70
  }
@@ -1,6 +1,7 @@
1
- import Rails from "@rails/ujs";
1
+ import { start as startRails } from "@rails/ujs";
2
2
  import { Application } from "@hotwired/stimulus";
3
- require("react_ujs");
3
+ import "react_ujs";
4
+ import { FC } from "react";
4
5
 
5
6
  import * as Components from "./components";
6
7
 
@@ -11,14 +12,14 @@ import PageOptionsController from "./controllers/PageOptionsController";
11
12
 
12
13
  import RichText from "./features/RichText";
13
14
 
14
- export function registerComponent(name, component) {
15
+ export function registerComponent(name: string, component: FC) {
15
16
  window[name] = component;
16
17
  }
17
18
 
18
19
  export default function startPages () {
19
- Rails.start();
20
- for (var name in Components) {
21
- registerComponent(name, Components[name]);
20
+ startRails();
21
+ for (const name in Components) {
22
+ registerComponent(name, Components[name] as FC);
22
23
  }
23
24
  RichText.start();
24
25
 
@@ -33,6 +34,6 @@ export * from "./components";
33
34
  export * from "./hooks";
34
35
  export * from "./stores";
35
36
 
36
- export * from "./lib/request.js";
37
+ export * from "./lib/request";
37
38
  export { default as copyToClipboard,
38
39
  copySupported } from "./lib/copyToClipboard";
@@ -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 default class Tree {
54
- constructor(obj) {
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
- var indexes = this.indexes;
63
- var startId = this.cnt;
64
- var self = this;
88
+ build(obj: N): TreeIndex<N> {
89
+ const indexes = this.indexes;
90
+ const startId = this.cnt;
65
91
 
66
- var index = { id: startId, node: obj };
67
- indexes[this.cnt + ""] = index;
92
+ const index = { id: startId, node: obj };
93
+ indexes[indexName(this.cnt)] = index;
68
94
  this.cnt++;
69
95
 
70
- if (obj.children && obj.children.length) {
71
- walk(obj.children, index);
72
- }
73
-
74
- function walk(objs, parent) {
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[self.cnt + ""] = index;
86
- children.push(self.cnt);
87
- self.cnt++;
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
- var index = indexes[id + ""];
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
- var index = this.indexes[id + ""];
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
- var self = this;
118
- del(index);
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(function(child) {
124
- del(self.getIndex(child));
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
- var index = this.getIndex(id);
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
- var index = this.getIndex(id);
140
- var node = this.get(id);
141
- var parentIndex = this.getIndex(index.parent);
142
- var parentNode = this.get(index.parent);
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(function(id, i) {
153
- var index = this.getIndex(id);
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
- }.bind(this));
181
+ });
162
182
  }
163
183
 
164
- insert(obj, parentId, i) {
165
- var parentIndex = this.getIndex(parentId);
166
- var parentNode = this.get(parentId);
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
- var index = this.build(obj);
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
- var destIndex = this.getIndex(destId);
187
- var parentId = destIndex.parent;
188
- var i = this.getIndex(parentId).children.indexOf(destId);
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
- var destIndex = this.getIndex(destId);
194
- var parentId = destIndex.parent;
195
- var i = this.getIndex(parentId).children.indexOf(destId);
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
- var destIndex = this.getIndex(destId);
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
- var top = 1;
213
- var left = 1;
214
- var root = this.getIndex(1);
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
- if (root.children && root.children.length) {
221
- walk(root.children, root, left, root.node.collapsed);
222
- }
223
-
224
- function walk(children, parent, left, collapsed) {
225
- var height = 1;
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
- var obj = this.remove(fromId);
261
- var index = null;
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
- var indexes = this.indexes;
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
- var indexes = this.indexes;
287
- for(var id in indexes) {
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
- let readyHandlers = [];
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
- return document.querySelector("[name=csrf-token]").content;
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,