diff --git a/src/_node/html/apis.ts b/src/_node/html/apis.ts
index c7b19018..08fca7a4 100644
--- a/src/_node/html/apis.ts
+++ b/src/_node/html/apis.ts
@@ -25,6 +25,20 @@ import {
THtmlReferenceData,
} from './types';
+const noNeedClosingTag = ['area',
+ 'base',
+ 'br',
+ 'col',
+ 'embed',
+ 'hr',
+ 'img',
+ 'input',
+ 'link',
+ 'meta',
+ 'param',
+ 'source',
+ 'track',
+ 'wbr']
const emptyImage = window.location.origin + "/images/empty-image.svg"
export const setHtmlNodeInAppAttribName = (node: TNode, newUid: TNodeUid) => {
const nodeData = node.data as THtmlNodeData
@@ -308,7 +322,7 @@ export const serializeHtml = (tree: TNodeTreeData, htmlReferenceData: THtmlRefer
nodeHtmlInApp = ``
} else if (nodeData.type === 'text') {
// replace "<" or ">" to "<" and ">", only in app
- nodeHtml = nodeData.data.replace(//g, `>`)
+ nodeHtml = nodeData.data
nodeHtmlInApp = nodeData.data.replace(//g, `>`)
} else if (nodeData.type === 'script' || nodeData.type === 'style') {
nodeHtml = `<${nodeData.type}${attribsHtml}>${childrenHtml}${nodeData.type}>`
@@ -393,7 +407,12 @@ export const parseHtmlCodePart = (content: string, htmlReferenceData: THtmlRefer
ReactHtmlParser(content, {
decodeEntities: true,
transform: (node, index, transform) => {
- node.valid = true
+ if ((node as THtmlDomNodeData).type === 'tag' && (htmlReferenceData.elements[(node as THtmlDomNodeData).name] || (node as THtmlDomNodeData).name.indexOf('-') !== -1)) {
+ node.valid = true
+ }
+ else{
+ node.valid = false
+ }
},
preprocessNodes: (nodes: THtmlDomNodeData[]) => {
// build root node
@@ -496,4 +515,43 @@ export const parseHtmlCodePart = (content: string, htmlReferenceData: THtmlRefer
const { html: formattedContent } = serializeHtml(tree, htmlReferenceData, osType)
return { formattedContent, contentInApp: '', tree, nodeMaxUid: String(_nodeMaxUid) as TNodeUid }
+}
+
+export const checkValidHtml = (content: string): boolean => {
+ // remove code & pre & script tag's content
+ const tmpString = content.replace(/
)<[^<]*)*<\/pre>/gi, '').replace(/)<[^<]*)*<\/code>/gi, '
').replace(/').replace(/');
+ let hasMismatchedTags = false
+ let openingTags = [];
+ let closingTags = [];
+ let regex = /<\/?[a-zA-Z0-9]+\b[^>]*>/g; // Matches any HTML tag
+ let match = regex.exec(tmpString);
+ while (match) {
+ let tag = match[0];
+ if (tag.startsWith('')) {
+ let _tag = tag.slice(2, -1).split(' ')[0]
+ if (noNeedClosingTag.find(_item => _tag === _item) === undefined) {
+ closingTags.push(_tag);
+ }
+ } else {
+ let _tag = tag.slice(1, -1).split(' ')[0]
+ if (noNeedClosingTag.find(_item => _tag === _item) === undefined) {
+ openingTags.push(_tag);
+ }
+ }
+ match = regex.exec(tmpString);
+ }
+
+ if (openingTags.length !== closingTags.length) {
+ hasMismatchedTags = true; // Different number of opening and closing tags
+ }
+ else {
+ openingTags.sort()
+ closingTags.sort()
+ for (let i = 0 ; i < openingTags.length ; i ++) {
+ if (openingTags[i] !== closingTags[i])
+ hasMismatchedTags = true
+ }
+ }
+
+ return hasMismatchedTags
}
\ No newline at end of file
diff --git a/src/_ref/cmdk.ref/Actions.csv b/src/_ref/cmdk.ref/Actions.csv
index cc89cdfa..1568d94e 100644
--- a/src/_ref/cmdk.ref/Actions.csv
+++ b/src/_ref/cmdk.ref/Actions.csv
@@ -1,11 +1,8 @@
Name,Icon,Description,Keyboard Shortcut,Group,Context
Add,plus,Add something,a,Project,all
Code,code-html,Open Code,c,Project,all
-Run,play,"""Run"" (Preview)",r,Project,all
Save,data,Save current file,cmd+s,Project,all
Design,edit,"""Design"" On/Off (hide panels)",\,Project,all
-Publish,cloud-upload,,p,Project,all
-Share,share,,h,Project,all
Download,download,,cmd+d,Project,all
Cut,copy,,cmd+x,Basic,"file, html"
Copy,copy,,cmd+c,Basic,"file, html"
@@ -14,8 +11,6 @@ Delete,cross,,backspace,Basic,"file, html"
Duplicate,copy,,cmd+j,Basic,"file, html"
Group,border,,cmd+g,Basic,html
Ungroup,position,,cmd+shift+g,Basic,html
-Style,brush,Add Style,s,Basic,html
Text,text,Edit Text,t,Basic,html
Undo,undo,,cmd+z,Basic,all
-Redo,redo,,cmd+shift+z,Basic,all
-Turn into,sync,,,Other,html
\ No newline at end of file
+Redo,redo,,cmd+shift+z,Basic,all
\ No newline at end of file
diff --git a/src/components/main/actionsPanel/navigatorPanel/NavigatorPanel.tsx b/src/components/main/actionsPanel/navigatorPanel/NavigatorPanel.tsx
index 336a8f30..86edae24 100644
--- a/src/components/main/actionsPanel/navigatorPanel/NavigatorPanel.tsx
+++ b/src/components/main/actionsPanel/navigatorPanel/NavigatorPanel.tsx
@@ -114,28 +114,28 @@ export default function NavigatorPanel(props: NavigatorPanelProps) {
setFaviconFallback(false)
// set favicons of the workspace
if (file.uid === `${RootNodeUid}/index.html`) {
- if (validNodeTree) {
- let hasFavicon = false
- for (const x in validNodeTree) {
- const nodeData = validNodeTree[x].data as THtmlNodeData
- if (nodeData && nodeData.type === 'tag' && nodeData.name === 'link' && nodeData.attribs.rel === 'icon') {
- if (nodeData.attribs.href.startsWith('http') || nodeData.attribs.href.startsWith('//')) {
- setFavicon(nodeData.attribs.href)
- }
- else{
- setFavicon(window.location.origin + '/rnbw/' + project.name + '/' + nodeData.attribs.href)
- }
- hasFavicon = true
- }
- }
+ // if (validNodeTree) {
+ // let hasFavicon = false
+ // for (const x in validNodeTree) {
+ // const nodeData = validNodeTree[x].data as THtmlNodeData
+ // if (nodeData && nodeData.type === 'tag' && nodeData.name === 'link' && nodeData.attribs.rel === 'icon') {
+ // if (nodeData.attribs.href.startsWith('http') || nodeData.attribs.href.startsWith('//')) {
+ // setFavicon(nodeData.attribs.href)
+ // }
+ // else{
+ // setFavicon(window.location.origin + '/rnbw/' + project.name + '/' + nodeData.attribs.href)
+ // }
+ // hasFavicon = true
+ // }
+ // }
- if (!hasFavicon) {
- setFavicon('')
- }
- }
- else{
- setFavicon('')
- }
+ // if (!hasFavicon) {
+ // setFavicon('')
+ // }
+ // }
+ // else{
+ // setFavicon('')
+ // }
let hasFavicon = false
for (const x in validNodeTree) {
@@ -252,18 +252,7 @@ export default function NavigatorPanel(props: NavigatorPanelProps) {
return file.uid !== '' ? <>
@@ -271,7 +260,7 @@ export default function NavigatorPanel(props: NavigatorPanelProps) {
<>
{/* workspace */}
{/* <>
-
+
> */}
@@ -280,12 +269,10 @@ export default function NavigatorPanel(props: NavigatorPanelProps) {
{/* project */}
<>
-
- {favicon === null || favicon === "" || faviconFallback ?
-
folder :
-
- }
-
+ {/* {favicon === null || favicon === "" || faviconFallback ? */}
+
folder
+ {/*
*/}
+ {/* } */}
{project.name}
>
@@ -311,7 +298,7 @@ export default function NavigatorPanel(props: NavigatorPanelProps) {
<>
{/* workspace */}
{/* <>
-
+
> */}
@@ -320,7 +307,7 @@ export default function NavigatorPanel(props: NavigatorPanelProps) {
<>
{/* workspace */}
{/* <>
-
+
>
@@ -329,12 +316,12 @@ export default function NavigatorPanel(props: NavigatorPanelProps) {
{/* project */}
<>
-
- {favicon === null || favicon === "" || faviconFallback ?
-
folder :
-
- }
-
+
+ {/* {favicon === null || favicon === "" || faviconFallback ? */}
+
folder
+ {/*
*/}
+ {/* } */}
+
{project.name}
>
@@ -381,7 +368,7 @@ export default function NavigatorPanel(props: NavigatorPanelProps) {
onOpenProject(_project)
}}>
-
+
{_project.favicon ?
:
folder}
{_project.name}
diff --git a/src/components/main/actionsPanel/nodeTreeView/NodeTreeView.tsx b/src/components/main/actionsPanel/nodeTreeView/NodeTreeView.tsx
index f8711350..ba0a634a 100644
--- a/src/components/main/actionsPanel/nodeTreeView/NodeTreeView.tsx
+++ b/src/components/main/actionsPanel/nodeTreeView/NodeTreeView.tsx
@@ -45,6 +45,7 @@ import {
} from '@_node/types';
import {
collapseFNNode,
+ expandFFNode,
expandFNNode,
fnSelector,
focusFNNode,
@@ -86,6 +87,7 @@ export default function NodeTreeView(props: NodeTreeViewProps) {
ffHandlers, setFFHandlers,
ffHoveredItem, setFFHoveredItem,
isHms, setIsHms,
+ setInitialFileToOpen,
ffAction, setFFAction,
currentFileUid, setCurrentFileUid,
// node tree view
@@ -656,6 +658,60 @@ export default function NodeTreeView(props: NodeTreeViewProps) {
navigatorDropDownType !== null && setNavigatorDropDownType(null)
}, [navigatorDropDownType])
+ // ------------------------------------------------------------- open wc -------------------------------------------------------------
+ const openWebComponent = useCallback((item: TNodeUid) => {
+ // check the element is wc
+ const nodeData = validNodeTree[item].data as THtmlNodeData
+ let exist = false
+ if (nodeData && htmlReferenceData.elements[nodeData.name] === undefined && nodeData.type === 'tag') {
+ const wcName = nodeData.name
+ for (let x in ffTree) {
+ const defineRegex = /customElements\.define\(\s*['"]([\w-]+)['"]/;
+ if ((ffTree[x].data as TFileNodeData).content && (ffTree[x].data as TFileNodeData).ext === '.js') {
+ const match = ((ffTree[x].data as TFileNodeData).content).match(defineRegex);
+ if (match) {
+ // check web component
+ if (wcName === match[1].toLowerCase()) {
+ const fileName = (ffTree[x].data as TFileNodeData).name
+ let src = ''
+ for (let i in validNodeTree) {
+ if ((validNodeTree[i].data as THtmlNodeData).type === 'script' && (validNodeTree[i].data as THtmlNodeData).html.search(fileName + '.js') !== -1) {
+ src = (validNodeTree[i].data as THtmlNodeData).attribs.src
+ break
+ }
+ }
+ if (src !== '') {
+ if (src.startsWith('http') || src.startsWith('//')) {
+ alert('rnbw couldn\'t find it\'s source file')
+ break
+ }
+ else{
+ setInitialFileToOpen(ffTree[x].uid)
+ setNavigatorDropDownType('project')
+ // expand path to the uid
+ const _expandedItems: string[] = []
+ let _file = ffTree[x]
+ while (_file && _file.uid !== RootNodeUid) {
+ _file = ffTree[_file.parentUid as string]
+ if (_file && !_file.isEntity && (!expandedItemsObj[_file.uid] || expandedItemsObj[_file.uid] === undefined))
+ _expandedItems.push(_file.uid)
+ }
+ dispatch(expandFFNode(_expandedItems))
+ exist = true
+ break
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!exist) {
+ alert('rnbw couldn\'t find it\'s source file')
+ }
+ }
+ }, [htmlReferenceData, validNodeTree, ffTree])
+
const isDragging = useRef
(false)
return useMemo(() => {
@@ -754,6 +810,10 @@ export default function NodeTreeView(props: NodeTreeViewProps) {
navigatorDropDownType !== null && setNavigatorDropDownType(null)
}}
+ onDoubleClick={(e: React.MouseEvent) => {
+ e.stopPropagation()
+ openWebComponent(props.item.index as TNodeUid)
+ }}
onMouseEnter={(e) => {
const ele = e.target as HTMLElement
let _uid: TNodeUid | null = ele.getAttribute('id')
diff --git a/src/components/main/actionsPanel/workspaceTreeView/WorkspaceTreeView.tsx b/src/components/main/actionsPanel/workspaceTreeView/WorkspaceTreeView.tsx
index 85669b89..79a232c0 100644
--- a/src/components/main/actionsPanel/workspaceTreeView/WorkspaceTreeView.tsx
+++ b/src/components/main/actionsPanel/workspaceTreeView/WorkspaceTreeView.tsx
@@ -1937,7 +1937,7 @@ export default function WorkspaceTreeView(props: WorkspaceTreeViewProps) {
...(navigatorDropDownType ? { zIndex: 2 } : {})
}}
- className={navigatorDropDownType ? 'border-left border-right border-bottom shadow background-primary' : ''}
+ className={navigatorDropDownType ? 'border-bottom background-primary' : ''}
onClick={onPanelClick}
>
(true)
+ const currentPosition = useRef(null)
const monacoRef = useRef(null)
const editorWrapperRef = useRef(null)
const codeContent = useRef('')
@@ -108,40 +112,66 @@ export default function CodeView(props: CodeViewProps) {
const decorationCollectionRef = useRef()
const codeChangeDecorationRef = useRef