Skip to content
Permalink
master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
module Drop {
// @attribute
var attributeDefinition = new DecoratorDefinition('attribute', null);
attributeDefinition.onchange = (decorator, args) => {
var name = decorator.name;
var keys = name.split('.');
var value: string = decorator.expressionValue;
var prevClass: string;
if (name == 'class') {
if (decorator.data) {
prevClass = decorator.data.class;
} else {
decorator.data = {};
}
if (prevClass == value) {
return;
}
decorator.data.class = value;
}
decorator.target.ensure(ele => {
if (keys.length == 2) {
var key = keys[0];
if (key in ele) {
ele[key][keys[1]] = value;
}
} else if (name == 'class' && ele.classList) {
if (prevClass) {
prevClass
.split(' ')
.forEach(className => className && ele.classList.remove(className));
}
if (value) {
value
.split(' ')
.forEach(className => className && ele.classList.add(className));
}
} else if (ele.setAttribute) {
ele.setAttribute(name, value);
}
}, decorator);
};
DecoratorDefinition.register(attributeDefinition);
// >event
var eventDefinition = new DecoratorDefinition('event', null);
eventDefinition.oninitialize = decorator => {
var type = decorator.name;
function handler(e: MouseEvent) {
var onevent = decorator.expressionValue;
if (typeof onevent == 'function') {
onevent.call(this, e, decorator.scope);
}
}
decorator.target.ensure(ele => {
ele.addEventListener(type, handler);
}, decorator);
};
eventDefinition.onchange = (decorator, args) => { };
DecoratorDefinition.register(eventDefinition);
// =html
var htmlDefinition = new DecoratorDefinition('html', null);
htmlDefinition.onchange = (decorator, args) => {
var value = decorator.expressionValue;
if (value === undefined) {
value = '';
}
var tempDiv = document.createElement('div');
tempDiv.innerHTML = value;
decorator.target.replaceWith(tempDiv.childNodes);
};
DecoratorDefinition.register(htmlDefinition);
// text
var textDefinition = new DecoratorDefinition('text', null);
textDefinition.onchange = (decorator, args) => {
var value = decorator.expressionValue;
if (value === undefined) {
value = '';
}
var textNode = document.createTextNode(value);
decorator.target.replaceWith(textNode);
};
DecoratorDefinition.register(textDefinition);
// #scope
var scopeDefinition = new ModifierDefinition('scope');
scopeDefinition.onchange = modifier => {
var scope = modifier.scope;
scope.initialize();
modifier.target.replaceWith(scope.fragment);
};
DecoratorDefinition.register(scopeDefinition);
// #each
module EachModifier {
var splice = Array.prototype.splice;
function remove(e, scope: Scope) {
var keys = scope.fullScopeKeys;
scope.data.removeByKeys(keys);
}
interface IIndexTarget {
comment: Comment;
scope: Scope;
}
var eachDefinition = new ModifierDefinition('each');
eachDefinition.oninitialize = modifier => {
var scope = modifier.scope;
var indexTargets: IIndexTarget[] = [];
modifier.data = {
indexTargets: indexTargets
};
var fragmentTemplate = scope.fragmentTemplate;
var items: any[] = modifier.expressionValue;
if (!items || !items.length) {
modifier.target.replaceWith(null);
return;
}
var fragment = document.createDocumentFragment();
for (var i = 0; i < items.length; i++) {
var subScope = new Scope(<HTMLDivElement>fragmentTemplate.cloneNode(true), null, scope, null, [i.toString()], {
index: i,
remove: remove
});
var comment = document.createComment(subScope.fullScopeKeys.join('.'));
indexTargets.push({
comment: comment,
scope: subScope
});
fragment.appendChild(comment);
fragment.appendChild(subScope.fragment);
}
modifier.target.replaceWith(fragment);
};
eachDefinition.onchange = (modifier, args) => {
if (!args) {
modifier.initialize();
return;
}
args.forEach(arg => {
var scope = modifier.scope;
switch (arg.changeType) {
case DataChangeType.clear:
scope.dispose(true);
case DataChangeType.set:
modifier.initialize();
break;
case DataChangeType.insert:
var fragmentTemplate = scope.fragmentTemplate;
var index = arg.index;
var items = arg.values;
var length = items.length;
if (!length) {
break;
}
var fragment = document.createDocumentFragment();
var tempIndexTargets: IIndexTarget[] = [];
var indexTargets: IIndexTarget[] = modifier.data.indexTargets;
var subScopes = scope.childScopes;
var pendingSubScopes: Scope[] = [];
for (var i = index; i < index + length; i++) {
var subScope = new Scope(<HTMLDivElement>fragmentTemplate.cloneNode(true), null, scope, null, [i.toString()], {
index: i,
remove: remove
});
pendingSubScopes.push(subScopes.pop());
var comment = document.createComment(subScope.fullScopeKeys.join('.'));
tempIndexTargets.push({
comment: comment,
scope: subScope
});
fragment.appendChild(comment);
fragment.appendChild(subScope.fragment);
}
var target = indexTargets[index];
var targetComment = target && target.comment;
for (var i = index; i < indexTargets.length; i++) {
indexTargets[i].scope.setScopeData('index', i + length);
}
splice.apply(indexTargets, (<any[]>[index, 0]).concat(tempIndexTargets));
splice.apply(subScopes, (<any[]>[index, 0]).concat(pendingSubScopes));
modifier.target.insertBefore(fragment, targetComment);
break;
case DataChangeType.remove:
var index = arg.index;
var ids = arg.ids;
var length = ids.length;
if (!length) {
break;
}
var subScopes = scope.childScopes;
var indexTargets: IIndexTarget[] = modifier.data.indexTargets;
var target = indexTargets[index];
var endTarget = indexTargets[index + length];
var targetNode: Node = target.comment;
var parentNode = targetNode.parentNode;
var endTargetNode = endTarget && endTarget.comment || modifier.target.end;
var targetNodes: Node[] = [];
do {
if (targetNode == endTargetNode) {
break;
}
targetNodes.push(targetNode);
} while (targetNode = targetNode.nextSibling);
targetNodes.forEach(node => parentNode.removeChild(node));
// remove from child scopes & index targets
var removedScopes = subScopes.splice(index, length);
indexTargets.splice(index, length);
removedScopes.forEach(scope => scope.dispose());
for (var i = index; i < indexTargets.length; i++) {
indexTargets[i].scope.setScopeData('index', i - length + 1);
}
break;
}
});
};
DecoratorDefinition.register(eachDefinition);
}
// %bind-value
// target limitation in the future?
var bindValueDefinition = new ProcessorDefinition('bind-value');
bindValueDefinition.oninitialize = processor => {
var value = processor.expressionValue;
if (value === undefined) {
value = '';
}
var idKeys = processor.expressionFullIdKeys;
processor.target.ensure((ele: HTMLInputElement) => {
ele.value = value;
ele.addEventListener('change', onchange);
ele.addEventListener('input', onchange);
ele.addEventListener('paste', onchange);
}, processor);
function onchange() {
processor.scope.setData(idKeys, this.value);
}
};
bindValueDefinition.onchange = (processor, args) => {
var value = processor.expressionValue;
if (value === undefined) {
value = '';
}
// no need to use ensure here because newly added element would go through ensure handler first.
processor.target.each((ele: HTMLInputElement) => {
if (ele.value != value) {
ele.value = value;
}
});
};
DecoratorDefinition.register(bindValueDefinition);
// %var
var varDefinition = new ProcessorDefinition('var');
varDefinition.skipExpessionParsing = true;
var isVariableRegex = /^[a-z$_][\w$]*$/i;
varDefinition.oninitialize = processor => {
var expression = processor.expression;
var name = isVariableRegex.test(expression) ? expression : null;
if (!name && processor.expressionFullIdKeys) {
return;
}
var scope = processor.scope
if (name) {
// 1. {%var abc}
if (scope.getScopeData<any>(name) === undefined) {
scope.setScopeData(name, undefined);
}
} else {
// 2. {%var abc = 123}
var value = processor.expressionValue;
if (value instanceof Object) {
Object
.keys(value)
.forEach(name => {
if (scope.getScopeData<any>(name) === undefined) {
scope.setScopeData(name, undefined);
}
});
}
}
};
DecoratorDefinition.register(varDefinition);
// %click-toggle
var clickToggleDefinition = new ProcessorDefinition('click-toggle');
clickToggleDefinition.oninitialize = (processor) => {
var fullIdKeys = processor.expressionFullIdKeys;
if (!fullIdKeys) {
throw new TypeError('[drop %click-toggle] expression "' + processor.expression + '" is not valid for toggle');
}
function onclick() {
var value = !processor.expressionValue;
processor.scope.setData(fullIdKeys, value);
}
processor.target.ensure(ele => {
ele.addEventListener('click', onclick);
}, processor);
};
DecoratorDefinition.register(clickToggleDefinition);
// %show
var showDefinition = new ProcessorDefinition('show');
showDefinition.oninitialize = processor => {
var value = processor.expressionValue;
processor.target.ensure(ele => {
ele.style.display = value ? '' : 'none';
}, processor);
};
showDefinition.onchange = (processor, args) => {
var value = processor.expressionValue;
processor.target.each(ele => {
ele.style.display = value ? '' : 'none';
});
};
DecoratorDefinition.register(showDefinition);
// %if
var ifDefinition = new ProcessorDefinition('if');
ifDefinition.onchange = (processor, args) => {
//debugger;
var value = processor.expressionValue;
if (value) {
processor.target.append();
} else {
processor.target.remove();
}
};
DecoratorDefinition.register(ifDefinition);
// &input
var inputDefinition = new ComponentDefinition('input');
var bindIdKeysRegex = /(?:\{|,)\s*value:\s*\{([^}]+)\}/;
inputDefinition.oninitialize = component => {
var value: string;
var idKeys = component.expressionFullIdKeys;
if (idKeys) {
value = component.expressionValue;
} else {
var expression = component.parsedExpression;
var groups = expression && expression.match(bindIdKeysRegex);
if (!groups) {
debugger;
throw new TypeError('[drop &input] unable to bind value to expression "' + component.expression + '"');
}
idKeys = groups[1].split('.');
value = component.expressionValue.value;
}
if (value === undefined) {
value = '';
}
var input = document.createElement('input');
component.target.replaceWith(input);
component.target.ensure((ele: HTMLInputElement) => {
ele.value = value;
ele.addEventListener('change', onchange);
ele.addEventListener('input', onchange);
ele.addEventListener('paste', onchange);
}, component);
function onchange() {
component.scope.setData(idKeys, this.value);
}
};
inputDefinition.onchange = (processor, args) => {
var value = processor.expressionValue;
value = value instanceof Object ? value.value : value;
if (value === undefined) {
value = '';
}
// no need to use ensure here because newly added element would go through ensure handler first.
processor.target.each((ele: HTMLInputElement) => {
if (ele.value != value) {
ele.value = value;
}
});
};
DecoratorDefinition.register(inputDefinition);
}