diff --git a/dist/moon.js b/dist/moon.js index 611799c3..13664532 100644 --- a/dist/moon.js +++ b/dist/moon.js @@ -68,7 +68,7 @@ stack[stack.length - 1].children.push(child); }; - var parseAttributes = function (index, input, length, stack, dependencies, attributes) { + var parseAttributes = function (index, input, length, dependencies, attributes) { while (index < length) { var char = input[index]; @@ -127,30 +127,12 @@ } } - var first = key[0]; - if (first === "#") { - var element = { - index: stack[0].nextIndex++, - type: key, - attributes: [{ - key: "", - value: value, - expression: expression, - dynamic: expression && parseTemplate(value, dependencies) - }], - children: [] - }; - - pushChild(element, stack); - stack.push(element); - } else { - attributes.push({ - key: key, - value: value, - expression: expression, - dynamic: expression && parseTemplate(value, dependencies) - }); - } + attributes.push({ + key: key, + value: value, + expression: expression, + dynamic: expression && parseTemplate(value, dependencies) + }); } } @@ -158,19 +140,38 @@ }; var parseOpeningTag = function (index, input, length, stack, dependencies) { - var type = ""; - var attributes = []; + var element = { + index: stack[0].nextIndex++, + type: "", + attributes: [], + children: [] + }; while (index < length) { var char = input[index]; if (char === ">") { - var element = { - index: stack[0].nextIndex++, - type: type, - attributes: attributes, - children: [] - }; + var attributes = element.attributes; + for (var i = 0; i < attributes.length;) { + var attribute = attributes[i]; + if (attribute.key[0] === "#") { + element = { + index: stack[0].nextIndex++, + type: attribute.key, + attributes: [{ + key: "", + value: attribute.value, + expression: attribute.expression, + dynamic: attribute.dynamic + }], + children: [element] + }; + pushChild(element, stack); + attributes.splice(i, 1); + } else { + i += 1; + } + } pushChild(element, stack); stack.push(element); @@ -178,20 +179,14 @@ index += 1; break; } else if (char === "/" && input[index + 1] === ">") { - pushChild({ - index: stack[0].nextIndex++, - type: type, - attributes: attributes, - children: [] - }, stack); + pushChild(element, stack); index += 2; break; } else if ((whitespaceRE.test(char) && (index += 1)) || char === "=") { - attributes = []; - index = parseAttributes(index, input, length, stack, dependencies, attributes); + index = parseAttributes(index, input, length, dependencies, element.attributes); } else { - type += char; + element.type += char; index += 1; } } @@ -301,7 +296,6 @@ nextIndex: 1, type: "#root", attributes: [], - events: [], children: [], dependencies: dependencies }; @@ -339,6 +333,8 @@ var createTextNode = function (content) { return ("m.ctn(" + content + ");"); }; + var createComment = function () { return "m.cc();"; }; + var attributeValue = function (attribute) { return attribute.expression ? attribute.value : ("\"" + (attribute.value) + "\""); }; var setAttribute = function (element, attribute) { return ("m.sa(" + (getElement(element)) + ",\"" + (attribute.key) + "\"," + (attributeValue(attribute)) + ");"); }; @@ -351,14 +347,26 @@ var removeChild = function (element, parent) { return ("m.rc(" + (getElement(element)) + "," + (getElement(parent)) + ");"); }; - var generateCreate = function (element, parent, root) { + var insertBefore = function (element, reference, parent) { return ("m.ib(" + (getElement(element)) + "," + (getElement(reference)) + "," + (getElement(parent)) + ");"); }; + + var generateCreate = function (element, parent, root, insert) { + var createCode; switch (element.type) { + case "#if": + var ifCreate = element.ifCreate = root.nextIndex++; + return setElement(element.index, createComment()) + appendChild(element.index, parent.index) + setElement(ifCreate, ("function(){" + (mapReduce(element.children, function (child) { return generateCreate(child, parent, root, element.index); })) + "};")) + "if(" + (attributeValue(element.attributes[0])) + "){" + (getElement(ifCreate)) + "();}"; + break; + case "#else": + var elseCreate = element.elseCreate = root.nextIndex++; + return ("else{" + (getElement(elseCreate)) + "();}" + (setElement(elseCreate, ("function(){" + (mapReduce(element.children, function (child) { return generateCreate(child, parent, root, element.index - 1); })) + "};")))); case "#text": - return setElement(element.index, createTextNode(attributeValue(element.attributes[0]))) + appendChild(element.index, parent.index); + createCode = setElement(element.index, createTextNode(attributeValue(element.attributes[0]))); break; default: - return setElement(element.index, createElement(element.type)) + mapReduce(element.attributes, function (attribute) { return attribute.key[0] === "@" ? addEventListener(element.index, attribute) : setAttribute(element.index, attribute); }) + mapReduce(element.children, function (child) { return generateCreate(child, element, root); }) + appendChild(element.index, parent.index); + createCode = setElement(element.index, createElement(element.type)) + mapReduce(element.attributes, function (attribute) { return attribute.key[0] === "@" ? addEventListener(element.index, attribute) : setAttribute(element.index, attribute); }) + mapReduce(element.children, function (child) { return generateCreate(child, element, root); }); } + + return createCode + (insert === undefined ? appendChild(element.index, parent.index) : insertBefore(element.index, insert, parent.index)); }; var generateUpdate = function (element, parent, root) { @@ -417,8 +425,8 @@ parent.removeChild(element); }; - var replaceChild$1 = function (element, old, parent) { - parent.replaceChild(element, old); + var insertBefore$1 = function (element, reference, parent) { + parent.insertBefore(element, reference); }; var m = function () { @@ -432,7 +440,7 @@ m.stc = setTextContent$1; m.ac = appendChild$1; m.rc = removeChild$1; - m.pc = replaceChild$1; + m.ib = insertBefore$1; return m; }; diff --git a/dist/moon.min.js b/dist/moon.min.js index 6c794e58..8d9ffff9 100644 --- a/dist/moon.min.js +++ b/dist/moon.min.js @@ -4,4 +4,4 @@ * Released under the MIT License * https://kbrsh.github.io/moon */ -!function(t,e){"undefined"==typeof module?t.Moon=e():module.exports=e()}(this,function(){"use strict";var a=function(t,e,n){for(;t"===u){t+=3;break}t+=1}}return t},u=/"[^"]*"|'[^']*'|\d+[a-zA-Z$_]\w*|\.[a-zA-Z$_]\w*|[a-zA-Z$_]\w*:|([a-zA-Z$_]\w*)/g,o=["NaN","event","false","in","m","null","this","true","typeof","undefined"],v=function(t,e){for(var n,i=!1;null!==(n=u.exec(t));){var r=n[1];void 0!==r&&-1===o.indexOf(r)&&"$"!==r[0]&&(i=!0,-1===e.indexOf(r)&&e.push(r))}return i},t={silent:!0},h=/\s+/,l=function(t,e){e[e.length-1].children.push(t)},f=function(t,e,n,i,r,u){for(;t"===o)break;if(h.test(o))t+=1;else{for(var a="",c="",f=!1;t"===o||h.test(o)){c=a;break}if("="===o){t+=1;break}a+=o,t+=1}if(0===c.length){var d=void 0;for('"'===(o=e[t])||"'"===o?(d=o,t+=1):"{"===o?(d="}",f=!0,t+=1):d=h;t"!==o;){if("object"==typeof d&&d.test(o)||o===d){t+=1;break}c+=o,t+=1}}if("#"===a[0]){var s={index:i[0].nextIndex++,type:a,attributes:[{key:"",value:c,expression:f,dynamic:f&&v(c,r)}],children:[]};l(s,i),i.push(s)}else u.push({key:a,value:c,expression:f,dynamic:f&&v(c,r)})}}return t},c=function(t,e,n,i,r){for(var u="",o=[];t"===a){var c={index:i[0].nextIndex++,type:u,attributes:o,children:[]};l(c,i),i.push(c),t+=1;break}if("/"===a&&">"===e[t+1]){l({index:i[0].nextIndex++,type:u,attributes:o,children:[]},i),t+=2;break}h.test(a)&&(t+=1)||"="===a?t=f(t,e,n,i,r,o=[]):(u+=a,t+=1)}return t},d=function(t,e,n,i){for(;t"===r){t+=1;break}r}var u=i.pop();return u.type,t},s=/(?:(?:&(?:amp|gt|lt|nbsp|quot);)|"|\\|\n)/g,p={"&":"&",">":">","<":"<"," ":" ",""":'\\"',"\\":"\\\\",'"':'\\"',"\n":"\\n"},m=function(t,e,n,i){for(var r="";t"===u){e+=3;break}e+=1}}return e},u=/"[^"]*"|'[^']*'|\d+[a-zA-Z$_]\w*|\.[a-zA-Z$_]\w*|[a-zA-Z$_]\w*:|([a-zA-Z$_]\w*)/g,a=["NaN","event","false","in","m","null","this","true","typeof","undefined"],s=function(e,t){for(var n,i=!1;null!==(n=u.exec(e));){var r=n[1];void 0!==r&&-1===a.indexOf(r)&&"$"!==r[0]&&(i=!0,-1===t.indexOf(r)&&t.push(r))}return i},e={silent:!0},d=/\s+/,v=function(e,t){t[t.length-1].children.push(e)},h=function(e,t,n,i,r){for(;e"===u)break;if(d.test(u))e+=1;else{for(var a="",o="",c=!1;e"===u||d.test(u)){o=a;break}if("="===u){e+=1;break}a+=u,e+=1}if(0===o.length){var f=void 0;for('"'===(u=t[e])||"'"===u?(f=u,e+=1):"{"===u?(f="}",c=!0,e+=1):f=d;e"!==u;){if("object"==typeof f&&f.test(u)||u===f){e+=1;break}o+=u,e+=1}}r.push({key:a,value:o,expression:c,dynamic:c&&s(o,i)})}}return e},c=function(e,t,n,i,r){for(var u={index:i[0].nextIndex++,type:"",attributes:[],children:[]};e"===a){for(var o=u.attributes,c=0;c"===t[e+1]){v(u,i),e+=2;break}d.test(a)&&(e+=1)||"="===a?e=h(e,t,n,r,u.attributes):(u.type+=a,e+=1)}return e},f=function(e,t,n,i){for(;e"===r){e+=1;break}r}var u=i.pop();return u.type,e},l=/(?:(?:&(?:amp|gt|lt|nbsp|quot);)|"|\\|\n)/g,x={"&":"&",">":">","<":"<"," ":" ",""":'\\"',"\\":"\\\\",'"':'\\"',"\n":"\\n"},m=function(e,t,n,i){for(var r="";e { +export const generateCreate = (element, parent, root, insert) => { + let createCode; switch (element.type) { + case "#if": + const ifCreate = element.ifCreate = root.nextIndex++; + return setElement(element.index, createComment()) + appendChild(element.index, parent.index) + setElement(ifCreate, `function(){${mapReduce(element.children, (child) => generateCreate(child, parent, root, element.index))}};`) + `if(${attributeValue(element.attributes[0])}){${getElement(ifCreate)}();}`; + break; + case "#else": + const elseCreate = element.elseCreate = root.nextIndex++; + return `else{${getElement(elseCreate)}();}${setElement(elseCreate, `function(){${mapReduce(element.children, (child) => generateCreate(child, parent, root, element.index - 1))}};`)}`; case "#text": - return setElement(element.index, createTextNode(attributeValue(element.attributes[0]))) + appendChild(element.index, parent.index); + createCode = setElement(element.index, createTextNode(attributeValue(element.attributes[0]))); break; default: - return setElement(element.index, createElement(element.type)) + mapReduce(element.attributes, (attribute) => attribute.key[0] === "@" ? addEventListener(element.index, attribute) : setAttribute(element.index, attribute)) + mapReduce(element.children, (child) => generateCreate(child, element, root)) + appendChild(element.index, parent.index); + createCode = setElement(element.index, createElement(element.type)) + mapReduce(element.attributes, (attribute) => attribute.key[0] === "@" ? addEventListener(element.index, attribute) : setAttribute(element.index, attribute)) + mapReduce(element.children, (child) => generateCreate(child, element, root)); } + + return createCode + (insert === undefined ? appendChild(element.index, parent.index) : insertBefore(element.index, insert, parent.index)); }; diff --git a/src/compiler/generator/util.js b/src/compiler/generator/util.js index 143197e3..870ad0ce 100644 --- a/src/compiler/generator/util.js +++ b/src/compiler/generator/util.js @@ -22,4 +22,4 @@ export const appendChild = (element, parent) => `m.ac(${getElement(element)},${g export const removeChild = (element, parent) => `m.rc(${getElement(element)},${getElement(parent)});`; -export const replaceChild = (element, old, parent) => `m.pc(${getElement(element)},${getElement(old)},${getElement(parent)});`; +export const insertBefore = (element, reference, parent) => `m.ib(${getElement(element)},${getElement(reference)},${getElement(parent)});`; diff --git a/src/compiler/parser/parser.js b/src/compiler/parser/parser.js index 54adb4de..37822aa6 100644 --- a/src/compiler/parser/parser.js +++ b/src/compiler/parser/parser.js @@ -12,7 +12,6 @@ export const parse = (input) => { nextIndex: 1, type: "#root", attributes: [], - events: [], children: [], dependencies: dependencies }; diff --git a/src/compiler/parser/tag.js b/src/compiler/parser/tag.js index d0b7bc32..dd937645 100644 --- a/src/compiler/parser/tag.js +++ b/src/compiler/parser/tag.js @@ -1,7 +1,7 @@ import { parseTemplate } from "./template"; import { whitespaceRE, error, pushChild } from "./util"; -const parseAttributes = (index, input, length, stack, dependencies, attributes) => { +const parseAttributes = (index, input, length, dependencies, attributes) => { while (index < length) { let char = input[index]; @@ -60,30 +60,12 @@ const parseAttributes = (index, input, length, stack, dependencies, attributes) } } - const first = key[0]; - if (first === "#") { - const element = { - index: stack[0].nextIndex++, - type: key, - attributes: [{ - key: "", - value: value, - expression: expression, - dynamic: expression && parseTemplate(value, dependencies) - }], - children: [] - }; - - pushChild(element, stack); - stack.push(element); - } else { - attributes.push({ - key: key, - value: value, - expression: expression, - dynamic: expression && parseTemplate(value, dependencies) - }); - } + attributes.push({ + key: key, + value: value, + expression: expression, + dynamic: expression && parseTemplate(value, dependencies) + }); } } @@ -91,19 +73,38 @@ const parseAttributes = (index, input, length, stack, dependencies, attributes) }; export const parseOpeningTag = (index, input, length, stack, dependencies) => { - let type = ""; - let attributes = []; + let element = { + index: stack[0].nextIndex++, + type: "", + attributes: [], + children: [] + }; while (index < length) { const char = input[index]; if (char === ">") { - const element = { - index: stack[0].nextIndex++, - type: type, - attributes: attributes, - children: [] - }; + const attributes = element.attributes; + for (let i = 0; i < attributes.length;) { + const attribute = attributes[i]; + if (attribute.key[0] === "#") { + element = { + index: stack[0].nextIndex++, + type: attribute.key, + attributes: [{ + key: "", + value: attribute.value, + expression: attribute.expression, + dynamic: attribute.dynamic + }], + children: [element] + }; + pushChild(element, stack); + attributes.splice(i, 1); + } else { + i += 1; + } + } pushChild(element, stack); stack.push(element); @@ -111,20 +112,14 @@ export const parseOpeningTag = (index, input, length, stack, dependencies) => { index += 1; break; } else if (char === "/" && input[index + 1] === ">") { - pushChild({ - index: stack[0].nextIndex++, - type: type, - attributes: attributes, - children: [] - }, stack); + pushChild(element, stack); index += 2; break; } else if ((whitespaceRE.test(char) && (index += 1)) || char === "=") { - attributes = []; - index = parseAttributes(index, input, length, stack, dependencies, attributes); + index = parseAttributes(index, input, length, dependencies, element.attributes); } else { - type += char; + element.type += char; index += 1; } } diff --git a/src/util/m.js b/src/util/m.js index 7fb821a4..e38e8298 100644 --- a/src/util/m.js +++ b/src/util/m.js @@ -26,8 +26,8 @@ const removeChild = (element, parent) => { parent.removeChild(element); }; -const replaceChild = (element, old, parent) => { - parent.replaceChild(element, old); +const insertBefore = (element, reference, parent) => { + parent.insertBefore(element, reference); }; export const m = () => { @@ -41,6 +41,6 @@ export const m = () => { m.stc = setTextContent; m.ac = appendChild; m.rc = removeChild; - m.pc = replaceChild; + m.ib = insertBefore; return m; };