Skip to content

Commit

Permalink
Allow applyAttrs and applyStatics to use a different mutator object (#…
Browse files Browse the repository at this point in the history
…457)

This wil allow two different frameworks using attr() in different ways to coexist (c3 and soy).
  • Loading branch information
iteriani committed Apr 16, 2021
1 parent 34be6bd commit 8e1445e
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 31 deletions.
2 changes: 1 addition & 1 deletion index.ts
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

export {applyAttr, applyProp, attributes,} from './src/attributes';
export {applyAttr, applyProp, attributes, createAttributeMap} from './src/attributes';
export {alignWithDOM, alwaysDiffAttributes, close, createPatchInner, createPatchOuter, currentElement, currentContext, currentPointer, open, patchInner as patch, patchInner, patchOuter, skip, skipNode} from './src/core';
export {setKeyAttributeName} from './src/global';
export {clearCache,getKey, importNode, isDataInitialized} from './src/node_data';
Expand Down
21 changes: 13 additions & 8 deletions src/attributes.ts
Expand Up @@ -145,13 +145,17 @@ function applyAttributeTyped(el: Element, name: string, value: unknown) {
* will just assume attributes is "any" otherwise and throws away
* the type annotation set by tsickle.
*/
const attributes: AttrMutatorConfig = createMap() as AttrMutatorConfig;
const attributes = createAttributeMap();

// Special generic mutator that's called for any attribute that does not
// have a specific mutator.
attributes[symbols.default] = applyAttributeTyped;
function createAttributeMap() {
const attributes: AttrMutatorConfig = createMap() as AttrMutatorConfig;
// Special generic mutator that's called for any attribute that does not
// have a specific mutator.
attributes[symbols.default] = applyAttributeTyped;

attributes["style"] = applyStyle;
attributes["style"] = applyStyle;
return attributes;
}

/**
* Calls the appropriate attribute mutator for this attribute.
Expand All @@ -161,9 +165,10 @@ attributes["style"] = applyStyle;
* function it is set on the Element, otherwise, it is set as an HTML
* attribute.
*/
function updateAttribute(el: Element, name: string, value: unknown) {
const mutator = attributes[name] || attributes[symbols.default];
function updateAttribute(
el: Element, name: string, value: unknown, attrs: AttrMutatorConfig) {
const mutator = attrs[name] || attrs[symbols.default];
mutator(el, name, value);
}

export { updateAttribute, applyProp, applyAttr, attributes };
export { createAttributeMap, updateAttribute, applyProp, applyAttr, attributes };
15 changes: 9 additions & 6 deletions src/changes.ts
Expand Up @@ -26,17 +26,20 @@ let bufferStart = 0;
* @param a The first argument to the function.
* @param b The second argument to the function.
* @param c The third argument to the function.
* @param d The fourth argument to the function
*/
function queueChange<A, B, C>(
fn: (a: A, b: B, c: C) => void,
function queueChange<A, B, C, D>(
fn: (a: A, b: B, c: C, d: D) => void,
a: A,
b: B,
c: C
c: C,
d: D,
) {
buffer.push(fn);
buffer.push(a);
buffer.push(b);
buffer.push(c);
buffer.push(d);
}

/**
Expand All @@ -51,9 +54,9 @@ function flush() {

bufferStart = end;

for (let i = start; i < end; i += 4) {
const fn = buffer[i] as (a: any, b: any, c: any) => undefined;
fn(buffer[i + 1], buffer[i + 2], buffer[i + 3]);
for (let i = start; i < end; i += 5) {
const fn = buffer[i] as (a: any, b: any, c: any, d:any) => undefined;
fn(buffer[i + 1], buffer[i + 2], buffer[i + 3], buffer[i + 4]);
}

bufferStart = start;
Expand Down
11 changes: 7 additions & 4 deletions src/diff.ts
Expand Up @@ -14,6 +14,7 @@
* limitations under the License.
*/

import { AttrMutatorConfig } from "./types";
import { createMap, truncateArray } from "./util";
import { flush, queueChange } from "./changes";

Expand All @@ -32,13 +33,15 @@ const prevValuesMap = createMap();
* @param next The next values, alternating name, value pairs.
* @param updateCtx The context for the updateFn.
* @param updateFn A function to call when a value has changed.
* @param attrs Attribute map for mutators
* @param alwaysDiffAttributes Whether to diff attributes unconditionally
*/
function calculateDiff<T>(
prev: Array<string>,
next: Array<string>,
updateCtx: T,
updateFn: (ctx: T, x: string, y: {} | undefined) => void,
updateFn: (ctx: T, x: string, y: {} | undefined, attrs: AttrMutatorConfig) => void,
attrs: AttrMutatorConfig,
alwaysDiffAttributes: boolean = false
) {
const isNew = !prev.length || alwaysDiffAttributes;
Expand All @@ -55,7 +58,7 @@ function calculateDiff<T>(
const value = next[i + 1];
if (isNew || prev[i + 1] !== value) {
prev[i + 1] = value;
queueChange(updateFn, updateCtx, name, value);
queueChange(updateFn, updateCtx, name, value, attrs);
}
}

Expand All @@ -73,7 +76,7 @@ function calculateDiff<T>(
const value = next[i + 1];

if (prevValuesMap[name] !== value) {
queueChange(updateFn, updateCtx, name, value);
queueChange(updateFn, updateCtx, name, value, attires);
}

prev[i] = name;
Expand All @@ -85,7 +88,7 @@ function calculateDiff<T>(
truncateArray(prev, next.length);

for (const name in prevValuesMap) {
queueChange(updateFn, updateCtx, name, undefined);
queueChange(updateFn, updateCtx, name, undefined, attrs);
delete prevValuesMap[name];
}
}
Expand Down
25 changes: 13 additions & 12 deletions src/virtual_elements.ts
Expand Up @@ -34,7 +34,7 @@ import {
} from "./core";
import { DEBUG } from "./global";
import { getData, NodeData } from "./node_data";
import { Key, NameOrCtorDef, Statics } from "./types";
import { AttrMutatorConfig, Key, NameOrCtorDef, Statics } from "./types";
import { createMap, truncateArray } from "./util";
import { calculateDiff } from "./diff";

Expand All @@ -55,13 +55,14 @@ const prevAttrsMap = createMap();
/**
* @param element The Element to diff the attrs for.
* @param data The NodeData associated with the Element.
* @param attrs The attribute map of mutators
*/
function diffAttrs(element: Element, data: NodeData) {
function diffAttrs(element: Element, data: NodeData, attrs: AttrMutatorConfig) {
const attrsBuilder = getAttrsBuilder();
const prevAttrsArr = data.getAttrsArr(attrsBuilder.length);

calculateDiff(prevAttrsArr, attrsBuilder, element, updateAttribute,
data.alwaysDiffAttributes);
data.alwaysDiffAttributes, attrs);
truncateArray(attrsBuilder, 0);
}

Expand All @@ -72,7 +73,7 @@ function diffAttrs(element: Element, data: NodeData) {
* @param data The NodeData associated with the Element.
* @param statics The statics array.
*/
function diffStatics(node: Element, data: NodeData, statics: Statics) {
function diffStatics(node: Element, data: NodeData, statics: Statics, attrs: AttrMutatorConfig) {
if (data.staticsApplied) {
return;
}
Expand All @@ -85,7 +86,7 @@ function diffStatics(node: Element, data: NodeData, statics: Statics) {

if (data.hasEmptyAttrsArr()) {
for (let i = 0; i < statics.length; i += 2) {
updateAttribute(node, statics[i] as string, statics[i + 1]);
updateAttribute(node, statics[i] as string, statics[i + 1], attrs);
}
return;
}
Expand Down Expand Up @@ -120,7 +121,7 @@ function diffStatics(node: Element, data: NodeData, statics: Statics) {
truncateArray(attrsArr, j);

for (const name in prevAttrsMap) {
updateAttribute(node, name, statics[prevAttrsMap[name]]);
updateAttribute(node, name, statics[prevAttrsMap[name]], attrs);
delete prevAttrsMap[name];
}
}
Expand Down Expand Up @@ -204,8 +205,8 @@ function elementOpenEnd(): HTMLElement {
const node = open(<NameOrCtorDef>argsBuilder[0], <Key>argsBuilder[1]);
const data = getData(node);

diffStatics(node, data, <Statics>argsBuilder[2]);
diffAttrs(node, data);
diffStatics(node, data, <Statics>argsBuilder[2], attributes);
diffAttrs(node, data, attributes);
truncateArray(argsBuilder, 0);

return node;
Expand Down Expand Up @@ -249,23 +250,23 @@ function elementOpen(
* Applies the currently buffered attrs to the currently open element. This
* clears the buffered attributes.
*/
function applyAttrs() {
function applyAttrs(attrs = attributes) {
const node = currentElement();
const data = getData(node);

diffAttrs(node, data);
diffAttrs(node, data, attrs);
}

/**
* Applies the current static attributes to the currently open element. Note:
* statics should be applied before calling `applyAtrs`.
* @param statics The statics to apply to the current element.
*/
function applyStatics(statics: Statics) {
function applyStatics(statics: Statics, attrs = attributes) {
const node = currentElement();
const data = getData(node);

diffStatics(node, data, statics);
diffStatics(node, data, statics, attrs);
}

/**
Expand Down

0 comments on commit 8e1445e

Please sign in to comment.