@flozy/editor 3.4.8 → 3.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -247,7 +247,7 @@ function AppHeader(props) {
247
247
  width: "auto"
248
248
  },
249
249
  src: appLogo
250
- }) : null, "\xA0", appTitle]
250
+ }) : null, appTitle]
251
251
  }), /*#__PURE__*/_jsxs(Box, {
252
252
  sx: {
253
253
  display: {
@@ -15,6 +15,12 @@ import { allowedDomains, decodeString } from "../../utils/helper";
15
15
  // };
16
16
  import { jsx as _jsx } from "react/jsx-runtime";
17
17
  import { jsxs as _jsxs } from "react/jsx-runtime";
18
+ const getCode = (embedData, isEncoded) => {
19
+ if (isEncoded) {
20
+ return decodeString(embedData);
21
+ }
22
+ return embedData;
23
+ };
18
24
  const Code = props => {
19
25
  const codeRef = useRef();
20
26
  const {
@@ -24,17 +30,20 @@ const Code = props => {
24
30
  } = props;
25
31
  const {
26
32
  embedData,
27
- isEncoded
33
+ isEncoded,
34
+ isSanitized
28
35
  } = element;
29
36
  useEffect(() => {
30
37
  if (codeRef?.current) {
31
- const clean = sanitizeHtml(isEncoded ? decodeString(embedData) : embedData, {
38
+ const code = getCode(embedData, isEncoded);
39
+ const clean = isSanitized ? code : sanitizeHtml(code, {
32
40
  allowedTags: false,
33
41
  // Allow all tags
34
42
  allowedAttributes: false,
35
43
  // Allow all attributes
36
- allowedScriptDomains: allowedDomains
44
+ allowedScriptDomains: allowedDomains // for old code's that are already inserted without sanitization
37
45
  });
46
+
38
47
  const slotHtml = document.createRange().createContextualFragment(clean); // Create a 'tiny' document and parse the html string
39
48
  codeRef.current.innerHTML = ""; // Clear the container
40
49
  codeRef.current.appendChild(slotHtml);
@@ -1,26 +1,66 @@
1
- import React, { useState } from "react";
1
+ import React, { useEffect, useState } from "react";
2
2
  import ToolbarIcon from "../../common/ToolbarIcon";
3
3
  import Icon from "../../common/Icon";
4
- import { Button, Dialog, DialogActions, DialogContent, DialogTitle } from "@mui/material";
4
+ import { Box, Button, Dialog, DialogActions, DialogContent, DialogTitle, Tooltip } from "@mui/material";
5
5
  import { insertEmbedScript } from "../../utils/embedScript";
6
+ import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined";
6
7
  import { jsx as _jsx } from "react/jsx-runtime";
7
8
  import { jsxs as _jsxs } from "react/jsx-runtime";
8
9
  import { Fragment as _Fragment } from "react/jsx-runtime";
9
10
  const EmbedScript = props => {
10
11
  const {
11
12
  editor,
12
- icoBtnType
13
+ icoBtnType,
14
+ customProps
13
15
  } = props;
14
16
  const [open, setOpen] = useState(false);
15
17
  const [code, setCode] = useState("");
18
+ const [apiStatus, setApiStatus] = useState({
19
+ loading: false,
20
+ error: false
21
+ });
22
+ const [allowedDomains, setAllowedDomains] = useState([]);
23
+ const {
24
+ loading,
25
+ error
26
+ } = apiStatus;
27
+ useEffect(() => {
28
+ customProps.services("allowedDomains", {}).then(data => {
29
+ setAllowedDomains(data?.data || []);
30
+ }).catch(err => {
31
+ console.log(err);
32
+ });
33
+ }, []);
34
+ const updateApiStatus = update => {
35
+ setApiStatus(prev => ({
36
+ ...prev,
37
+ ...update
38
+ }));
39
+ };
16
40
  const handleChange = e => {
17
41
  setCode(e.target.value);
18
42
  };
19
43
  const handleClick = () => {
20
44
  setOpen(true);
21
45
  };
22
- const onSubmit = () => {
23
- insertEmbedScript(editor, code);
46
+ const onSubmit = async () => {
47
+ updateApiStatus({
48
+ loading: true
49
+ });
50
+ const result = await customProps.services("validateCode", {
51
+ code
52
+ });
53
+ const {
54
+ error,
55
+ sanitizedCode
56
+ } = result?.data || {};
57
+ updateApiStatus({
58
+ loading: false,
59
+ error
60
+ });
61
+ if (!error) {
62
+ insertEmbedScript(editor, sanitizedCode || "");
63
+ }
24
64
  };
25
65
  const onCancel = () => {
26
66
  setOpen(false);
@@ -37,9 +77,37 @@ const EmbedScript = props => {
37
77
  open: open,
38
78
  fullWidth: true,
39
79
  children: [/*#__PURE__*/_jsx(DialogTitle, {
40
- children: "Embed Code"
41
- }), /*#__PURE__*/_jsx(DialogContent, {
42
- children: /*#__PURE__*/_jsx("textarea", {
80
+ children: /*#__PURE__*/_jsxs(Box, {
81
+ component: "div",
82
+ sx: {
83
+ display: "flex",
84
+ alignItems: "center",
85
+ gap: "6px"
86
+ },
87
+ children: ["Embed Code", allowedDomains?.length ? /*#__PURE__*/_jsx(Tooltip, {
88
+ title: /*#__PURE__*/_jsxs(Box, {
89
+ sx: {
90
+ textTransform: "none"
91
+ },
92
+ children: [/*#__PURE__*/_jsx("span", {
93
+ style: {
94
+ fontWeight: "bold"
95
+ },
96
+ children: "Allowed Domains"
97
+ }), /*#__PURE__*/_jsx("br", {}), allowedDomains.join(", ")]
98
+ }),
99
+ children: /*#__PURE__*/_jsx(InfoOutlinedIcon, {
100
+ color: "gray",
101
+ fontSize: "14px",
102
+ style: {
103
+ fill: "#94A3B8",
104
+ cursor: "pointer"
105
+ }
106
+ })
107
+ }) : null]
108
+ })
109
+ }), /*#__PURE__*/_jsxs(DialogContent, {
110
+ children: [/*#__PURE__*/_jsx("textarea", {
43
111
  value: code,
44
112
  onChange: handleChange,
45
113
  style: {
@@ -49,11 +117,16 @@ const EmbedScript = props => {
49
117
  padding: "4px",
50
118
  boxSizing: "border-box"
51
119
  }
52
- })
120
+ }), /*#__PURE__*/_jsx(Box, {
121
+ component: "div",
122
+ color: "red",
123
+ children: error ? "There was some error on this code." : ""
124
+ })]
53
125
  }), /*#__PURE__*/_jsxs(DialogActions, {
54
126
  children: [/*#__PURE__*/_jsx(Button, {
55
127
  onClick: onSubmit,
56
- children: "Save"
128
+ disabled: loading,
129
+ children: loading ? "Validating" : "Save"
57
130
  }), /*#__PURE__*/_jsx(Button, {
58
131
  onClick: onCancel,
59
132
  children: "Cancel"
@@ -1,6 +1,6 @@
1
1
  import React, { useState } from "react";
2
2
  import { useSlateStatic } from "slate-react";
3
- import { Box, Divider, Grid, Tooltip } from "@mui/material";
3
+ import { Box, Divider, Grid, IconButton, Tooltip } from "@mui/material";
4
4
  import { toolbarGroups } from "../toolbarGroups";
5
5
  import { MarkButton } from "../FormatTools";
6
6
  import LinkButton from "../../Elements/Link/LinkButton";
@@ -8,6 +8,7 @@ import { addMarkData, isBlockActive } from "../../utils/SlateUtilityFunctions";
8
8
  import ColorPickerButton from "../../common/ColorPickerButton";
9
9
  import { colors } from "../../Elements/Color Picker/defaultColors";
10
10
  import VariableButton from "../../Elements/Variables/VariableButton";
11
+ import Icon from "../../common/Icon";
11
12
  import { jsx as _jsx } from "react/jsx-runtime";
12
13
  import { Fragment as _Fragment } from "react/jsx-runtime";
13
14
  import { jsxs as _jsxs } from "react/jsx-runtime";
@@ -21,10 +22,11 @@ const BasicToolbar = props => {
21
22
  variableOptions,
22
23
  fontStyleOptions,
23
24
  hideLink = false,
24
- hideTextColor = false
25
+ hideTextColor = false,
26
+ hideResetIcon = true,
27
+ onResetClick = () => {}
25
28
  }
26
29
  } = props;
27
-
28
30
  // state
29
31
  const [activeColor, setActiveColor] = useState("#000000");
30
32
  const fontStyle = allTools.filter(f => f.basic || fontStyleOptions?.includes(f.format));
@@ -83,9 +85,23 @@ const BasicToolbar = props => {
83
85
  })
84
86
  }), /*#__PURE__*/_jsx(Grid, {
85
87
  item: true,
86
- children: variableOptions && variableOptions.length > 0 && /*#__PURE__*/_jsx(VariableButton, {
87
- placeholder: "Variables",
88
- options: variableOptions
88
+ children: /*#__PURE__*/_jsxs(Grid, {
89
+ container: true,
90
+ children: [!hideResetIcon && /*#__PURE__*/_jsx(Grid, {
91
+ item: true,
92
+ children: /*#__PURE__*/_jsx(IconButton, {
93
+ onClick: onResetClick,
94
+ children: /*#__PURE__*/_jsx(Icon, {
95
+ icon: "resetIcon"
96
+ })
97
+ })
98
+ }), /*#__PURE__*/_jsx(Grid, {
99
+ item: true,
100
+ children: variableOptions && variableOptions.length > 0 && /*#__PURE__*/_jsx(VariableButton, {
101
+ placeholder: "Variables",
102
+ options: variableOptions
103
+ })
104
+ })]
89
105
  })
90
106
  })]
91
107
  }), /*#__PURE__*/_jsx(Divider, {})]
@@ -7,7 +7,7 @@ import { AiFillEdit, AiOutlineInsertRowBelow, AiOutlineInsertRowRight, AiOutline
7
7
  import { SiLatex } from "react-icons/si";
8
8
  import { RiDeleteColumn, RiDeleteRow } from "react-icons/ri";
9
9
  import { IoIosImage } from "react-icons/io";
10
- import { GridIcon, AccordionIcon, SignatureIcon, ButtonIcon, Carousal, FormIcon, BoldIcon, FontFamilyIcon, FontSizeIcon, ImageIcon, ItalicIcon, LinkIcon, StrikethroughIcon, TableIcon, UnderLineIcon, VideoIcon, CheckboxIcon, AppHeader, MoreHorizontal, UploadImage, DocsUpload, LeftArrow, RightArrow, CheckListButton, CheckListButtonActive, ExcelIcon, CsvIcon, DividerIcon, CloseIcon, SearchIcon, ExpandIcon, CalendarIconNew, Text, TextAreaIcon, Phone, BriefCase, Bank, CalendarTick, DollarSquare, Checkbox, Description, RadioButtonIcon, CheckedIcon, UncheckedIcon, InfinityIcon } from "./iconslist";
10
+ import { GridIcon, AccordionIcon, SignatureIcon, ButtonIcon, Carousal, FormIcon, BoldIcon, FontFamilyIcon, FontSizeIcon, ImageIcon, ItalicIcon, LinkIcon, StrikethroughIcon, TableIcon, UnderLineIcon, VideoIcon, CheckboxIcon, AppHeader, MoreHorizontal, UploadImage, DocsUpload, LeftArrow, RightArrow, CheckListButton, CheckListButtonActive, ExcelIcon, CsvIcon, DividerIcon, CloseIcon, SearchIcon, ExpandIcon, CalendarIconNew, Text, TextAreaIcon, Phone, BriefCase, Bank, CalendarTick, DollarSquare, Checkbox, Description, RadioButtonIcon, CheckedIcon, UncheckedIcon, InfinityIcon, ResetIcon } from "./iconslist";
11
11
  import ArrowRightIcon from "@mui/icons-material/ArrowRight";
12
12
  import ArrowDropDownIcon from "@mui/icons-material/ArrowDropDown";
13
13
  import EmailRoundedIcon from '@mui/icons-material/EmailRounded';
@@ -243,7 +243,8 @@ const iconList = {
243
243
  }),
244
244
  checkedIcon: /*#__PURE__*/_jsx(CheckedIcon, {}),
245
245
  uncheckedIcon: /*#__PURE__*/_jsx(UncheckedIcon, {}),
246
- infinityIcon: /*#__PURE__*/_jsx(InfinityIcon, {})
246
+ infinityIcon: /*#__PURE__*/_jsx(InfinityIcon, {}),
247
+ resetIcon: /*#__PURE__*/_jsx(ResetIcon, {})
247
248
  };
248
249
  const Icon = props => {
249
250
  const {
@@ -2344,4 +2344,30 @@ export const InfinityIcon = () => /*#__PURE__*/_jsxs("svg", {
2344
2344
  })]
2345
2345
  })]
2346
2346
  })]
2347
+ });
2348
+ export const ResetIcon = () => /*#__PURE__*/_jsxs("svg", {
2349
+ width: "22",
2350
+ height: "23",
2351
+ viewBox: "0 0 22 23",
2352
+ fill: "none",
2353
+ xmlns: "http://www.w3.org/2000/svg",
2354
+ children: [/*#__PURE__*/_jsx("path", {
2355
+ d: "M13.6514 5.61292C12.8539 5.37458 11.9739 5.21875 11.0022 5.21875C6.61135 5.21875 3.05469 8.77542 3.05469 13.1662C3.05469 17.5662 6.61135 21.1229 11.0022 21.1229C15.393 21.1229 18.9497 17.5662 18.9497 13.1754C18.9497 11.5438 18.4547 10.0221 17.6114 8.75708",
2356
+ stroke: "#64748B",
2357
+ strokeWidth: "1.5",
2358
+ strokeLinecap: "round",
2359
+ strokeLinejoin: "round"
2360
+ }), /*#__PURE__*/_jsx("path", {
2361
+ d: "M14.782 5.8324L12.1328 2.78906",
2362
+ stroke: "#64748B",
2363
+ strokeWidth: "1.5",
2364
+ strokeLinecap: "round",
2365
+ strokeLinejoin: "round"
2366
+ }), /*#__PURE__*/_jsx("path", {
2367
+ d: "M14.7845 5.83203L11.6953 8.08703",
2368
+ stroke: "#64748B",
2369
+ strokeWidth: "1.5",
2370
+ strokeLinecap: "round",
2371
+ strokeLinejoin: "round"
2372
+ })]
2347
2373
  });
@@ -7,7 +7,9 @@ export const createEmbedScript = embedData => ({
7
7
  children: [{
8
8
  text: " "
9
9
  }],
10
- isEncoded: true // to handle the old code's that already inserted
10
+ isEncoded: true,
11
+ // to handle the old code's that already inserted
12
+ isSanitized: true // to handle the old code's that already inserted
11
13
  });
12
14
 
13
15
  export const insertEmbedScript = (editor, embedData) => {
@@ -242,7 +242,8 @@ export const handleLinkType = (url, linkType, readOnly, openInNewTab, onClick =
242
242
  props.component = "a";
243
243
  const [page, section] = url?.split("#") || [];
244
244
  const sec = section ? `#${section}` : "";
245
- props.href = isHomePage(page) ? `./home${sec}` : `./${url}`;
245
+ const currentUserPage = getCurrentUserPage();
246
+ props.href = isHomePage(page) ? `./${currentUserPage}${sec}` : `./${url}`;
246
247
  if (openInNewTab) {
247
248
  if (isCurrentPage(page)) {
248
249
  // temp fix, if user is presented in current page, open in new tab option is restricted, we will scroll to the element in current page
@@ -304,9 +305,13 @@ export const handleLinkType = (url, linkType, readOnly, openInNewTab, onClick =
304
305
  }
305
306
  return props;
306
307
  };
307
- const isCurrentPage = page => {
308
+ const getCurrentUserPage = () => {
308
309
  const paths = window.location.pathname.split("/");
309
310
  let currentUserPage = paths[paths?.length - 1];
311
+ return currentUserPage;
312
+ };
313
+ const isCurrentPage = page => {
314
+ let currentUserPage = getCurrentUserPage();
310
315
  currentUserPage = isHomePage(currentUserPage) ? "home" : currentUserPage;
311
316
  const buttonPage = isHomePage(page) ? "home" : page;
312
317
  return currentUserPage === buttonPage;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flozy/editor",
3
- "version": "3.4.8",
3
+ "version": "3.5.0",
4
4
  "description": "An Editor for flozy app brain",
5
5
  "files": [
6
6
  "dist"