Skip to content

Commit

Permalink
refactor: rewrite m-model to work with new 'set' method
Browse files Browse the repository at this point in the history
- if key is dynamic
  - creates temporary 'modelValue' variable to hold value of base
  - sets keypath of 'modelValue'
  - calls 'set' on base and 'modelValue'
- if key is static
  - calls 'set' on base and input value depending on input type
  • Loading branch information
kbrsh committed Aug 30, 2017
1 parent 455a945 commit 563313b
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 121 deletions.
105 changes: 45 additions & 60 deletions dist/moon.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,6 @@
var directives = {};
var specialDirectives = {};
var components = {};
var eventModifiersCode = {
stop: 'event.stopPropagation();',
prevent: 'event.preventDefault();',
ctrl: 'if(event.ctrlKey === false) {return null;};',
shift: 'if(event.shiftKey === false) {return null;};',
alt: 'if(event.altKey === false) {return null;};',
enter: 'if(event.keyCode !== 13) {return null;};'
};
var eventModifiers = {};

/* ======= Observer ======= */
/**
Expand Down Expand Up @@ -961,9 +952,9 @@
return output;
}

var compileTemplateExpression = function(expr, exclude, dependencies) {
var compileTemplateExpression = function(expression, exclude, dependencies) {
var references;
while((references = expressionRE.exec(expr)) !== null) {
while((references = expressionRE.exec(expression)) !== null) {
var reference = references[1];
if(reference !== undefined && dependencies.indexOf(reference) === -1 && exclude.indexOf(reference) === -1) {
dependencies.push(reference);
Expand Down Expand Up @@ -1589,10 +1580,10 @@

for(var i = 0; i < dependencies.length; i++) {
var dependency = dependencies[i];
dependenciesCode += "var " + dependency + " = instance.get(\"" + dependency + "\"); ";
dependenciesCode += "var " + dependency + " = instance.get(\"" + dependency + "\");";
}

var code = "var instance = this; " + dependenciesCode + "return " + rootCode + ";";
var code = "var instance = this;" + dependenciesCode + "return " + rootCode + ";";

try {
return new Function("m", code);
Expand Down Expand Up @@ -1957,6 +1948,23 @@

/* ======= Global API ======= */

/**
* Code for default Event Modifiers
*/
var eventModifiersCode = {
stop: 'event.stopPropagation();',
prevent: 'event.preventDefault();',
ctrl: 'if(event.ctrlKey === false) {return null;};',
shift: 'if(event.shiftKey === false) {return null;};',
alt: 'if(event.altKey === false) {return null;};',
enter: 'if(event.keyCode !== 13) {return null;};'
};

/**
* Event Modifiers Added
*/
var eventModifiers = {};

/**
* Configuration of Moon
*/
Expand Down Expand Up @@ -2088,6 +2096,7 @@
/* ======= Default Directives ======= */

var emptyNode = "m(\"#text\", {}, \"\")";
var hashRE = /\.|\[/;

var ifDynamic = 0;
var ifStack = [];
Expand Down Expand Up @@ -2230,67 +2239,43 @@
}

// Generate event listener code and install handler
var code = "function(event) {" + modifiersCode + "instance.callMethod(\"" + methodToCall + "\", [" + params + "])}";
var code = "function(event) {" + modifiersCode + "instance.callMethod(\"" + methodToCall + "\", [" + params + "]);}";
addEventListenerCodeToNode(eventType, code, node);
}
};

specialDirectives["m-model"] = {
beforeGenerate: function(prop, node, parentNode, state) {
// Get attributes
var value = prop.value;
var attrs = node.props.attrs;

// Get exclusions
var exclude = state.exclude;

// Get dependencies
var dependencies = state.dependencies;
var exclude = state.exclude;
var value = prop.value;

// Add dependencies
compileTemplateExpression(value, exclude, dependencies);

// Setup default event type, keypath to set, value of setter, DOM property to change, and value of DOM property
var eventType = "input";
var domGetter = "value";
var domSetter = value;
var keypathGetter = value;
var keypathSetter = "event.target." + domGetter;

// If input type is checkbox, listen on 'change' and change the 'checked' DOM property
var type = attrs.type;
if(type !== undefined) {
type = type.value;
var radio = false;
if(type === "checkbox" || (type === "radio" && (radio = true))) {
eventType = "change";
domGetter = "checked";

if(radio === true) {
var valueAttr = attrs.value;
var literalValueAttr;
var valueAttrValue = "null";
if(valueAttr !== undefined) {
valueAttrValue = "\"" + (compileTemplate(valueAttr.value, exclude, dependencies)) + "\"";
} else if((literalValueAttr = attrs["m-literal:value"])) {
valueAttrValue = compileTemplate(literalValueAttr.value, exclude, dependencies);
}
domSetter += "=== " + valueAttrValue;
keypathSetter = valueAttrValue;
} else {
keypathSetter = "event.target." + domGetter;
}
}
var dynamicIndex = value.search(hashRE);
var base;
var properties;
if(dynamicIndex !== -1) {
base = value.substring(0, dynamicIndex);
properties = value.substring(dynamicIndex);
value = "instance.get(\"" + base + "\")" + properties;
}

// Generate the listener
var code = "function(event) {instance.set(\"" + keypathGetter + "\", " + keypathSetter + ")}";
var eventType = "input";
var instanceKey = value;
var instanceValue = "event.target.value";
var domKey = "value";
var domValue = value;
var code = "";

if(dynamicIndex === -1) {
code = "function(event) {instance.set(\"" + instanceKey + "\", " + instanceValue + ");}";
} else {
code = "function(event) {var modelValue = instance.get(\"" + base + "\");modelValue" + properties + " = " + instanceValue + ";instance.set(\"" + base + "\", modelValue);}";
}

// Push the listener to it's event listeners
addEventListenerCodeToNode(eventType, code, node);

// Setup a query used to get the value, and set the corresponding dom property
addDomPropertyCodeToNode(domGetter, domSetter, node);
addDomPropertyCodeToNode(domKey, domValue, node);
}
};

Expand Down
2 changes: 1 addition & 1 deletion dist/moon.min.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions src/compiler/generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -243,10 +243,10 @@ const generate = function(tree) {

for(let i = 0; i < dependencies.length; i++) {
const dependency = dependencies[i];
dependenciesCode += `var ${dependency} = instance.get("${dependency}"); `;
dependenciesCode += `var ${dependency} = instance.get("${dependency}");`;
}

const code = `var instance = this; ${dependenciesCode}return ${rootCode};`;
const code = `var instance = this;${dependenciesCode}return ${rootCode};`;

try {
return new Function("m", code);
Expand Down
4 changes: 2 additions & 2 deletions src/compiler/template.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,9 @@ const compileTemplateState = function(state) {
return output;
}

const compileTemplateExpression = function(expr, exclude, dependencies) {
const compileTemplateExpression = function(expression, exclude, dependencies) {
let references;
while((references = expressionRE.exec(expr)) !== null) {
while((references = expressionRE.exec(expression)) !== null) {
let reference = references[1];
if(reference !== undefined && dependencies.indexOf(reference) === -1 && exclude.indexOf(reference) === -1) {
dependencies.push(reference);
Expand Down
71 changes: 24 additions & 47 deletions src/directives/default.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* ======= Default Directives ======= */

const emptyNode = `m("#text", {}, "")`;
const hashRE = /\.|\[/;

let ifDynamic = 0;
let ifStack = [];
Expand Down Expand Up @@ -143,67 +144,43 @@ specialDirectives["m-on"] = {
}

// Generate event listener code and install handler
const code = `function(event) {${modifiersCode}instance.callMethod("${methodToCall}", [${params}])}`;
const code = `function(event) {${modifiersCode}instance.callMethod("${methodToCall}", [${params}]);}`;
addEventListenerCodeToNode(eventType, code, node);
}
};

specialDirectives["m-model"] = {
beforeGenerate: function(prop, node, parentNode, state) {
// Get attributes
const value = prop.value;
const attrs = node.props.attrs;

// Get exclusions
const dependencies = state.dependencies;
const exclude = state.exclude;
let value = prop.value;

// Get dependencies
let dependencies = state.dependencies;

// Add dependencies
compileTemplateExpression(value, exclude, dependencies);

// Setup default event type, keypath to set, value of setter, DOM property to change, and value of DOM property
let eventType = "input";
let domGetter = "value";
let domSetter = value;
let keypathGetter = value;
let keypathSetter = `event.target.${domGetter}`;

// If input type is checkbox, listen on 'change' and change the 'checked' DOM property
let type = attrs.type;
if(type !== undefined) {
type = type.value;
let radio = false;
if(type === "checkbox" || (type === "radio" && (radio = true))) {
eventType = "change";
domGetter = "checked";

if(radio === true) {
let valueAttr = attrs.value;
let literalValueAttr;
let valueAttrValue = "null";
if(valueAttr !== undefined) {
valueAttrValue = `"${compileTemplate(valueAttr.value, exclude, dependencies)}"`;
} else if((literalValueAttr = attrs["m-literal:value"])) {
valueAttrValue = compileTemplate(literalValueAttr.value, exclude, dependencies);
}
domSetter += `=== ${valueAttrValue}`;
keypathSetter = valueAttrValue;
} else {
keypathSetter = `event.target.${domGetter}`;
}
}
const dynamicIndex = value.search(hashRE);
let base;
let properties;
if(dynamicIndex !== -1) {
base = value.substring(0, dynamicIndex);
properties = value.substring(dynamicIndex);
value = `instance.get("${base}")${properties}`;
}

// Generate the listener
const code = `function(event) {instance.set("${keypathGetter}", ${keypathSetter})}`;
let eventType = "input";
let instanceKey = value;
let instanceValue = "event.target.value";
let domKey = "value";
let domValue = value;
let code = "";

if(dynamicIndex === -1) {
code = `function(event) {instance.set("${instanceKey}", ${instanceValue});}`;
} else {
code = `function(event) {var modelValue = instance.get("${base}");modelValue${properties} = ${instanceValue};instance.set("${base}", modelValue);}`;
}

// Push the listener to it's event listeners
addEventListenerCodeToNode(eventType, code, node);

// Setup a query used to get the value, and set the corresponding dom property
addDomPropertyCodeToNode(domGetter, domSetter, node);
addDomPropertyCodeToNode(domKey, domValue, node);
}
};

Expand Down
17 changes: 17 additions & 0 deletions src/global/api.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
/* ======= Global API ======= */

/**
* Code for default Event Modifiers
*/
const eventModifiersCode = {
stop: 'event.stopPropagation();',
prevent: 'event.preventDefault();',
ctrl: 'if(event.ctrlKey === false) {return null;};',
shift: 'if(event.shiftKey === false) {return null;};',
alt: 'if(event.altKey === false) {return null;};',
enter: 'if(event.keyCode !== 13) {return null;};'
};

/**
* Event Modifiers Added
*/
let eventModifiers = {};

/**
* Configuration of Moon
*/
Expand Down
9 changes: 0 additions & 9 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,6 @@
let directives = {};
let specialDirectives = {};
let components = {};
let eventModifiersCode = {
stop: 'event.stopPropagation();',
prevent: 'event.preventDefault();',
ctrl: 'if(event.ctrlKey === false) {return null;};',
shift: 'if(event.shiftKey === false) {return null;};',
alt: 'if(event.altKey === false) {return null;};',
enter: 'if(event.keyCode !== 13) {return null;};'
};
let eventModifiers = {};

/* ======= Observer ======= */
//=require observer/methods.js
Expand Down

0 comments on commit 563313b

Please sign in to comment.