marko
Version:
UI Components + streaming, async, high performance, HTML templating for Node.js and the browser.
170 lines (142 loc) • 4.8 kB
JavaScript
;
// eslint-disable-next-line no-constant-binary-expression
var complain = "MARKO_DEBUG" && require("complain");
var extend = require("raptor-util/extend");
var componentUtil = require("@internal/components-util");
var w10NOOP = require("../helpers/serialize-noop").___noop;
var attachBubblingEvent = componentUtil.___attachBubblingEvent;
var addDelegatedEventHandler =
require("./event-delegation").___addDelegatedEventHandler;
var KeySequence = require("./KeySequence");
var EMPTY_OBJECT = {};
var FLAG_WILL_RERENDER_IN_BROWSER = 1;
var FLAG_HAS_RENDER_BODY = 2;
var FLAG_IS_LEGACY = 4;
var FLAG_OLD_HYDRATE_NO_CREATE = 8;
/**
* A ComponentDef is used to hold the metadata collected at runtime for
* a single component and this information is used to instantiate the component
* later (after the rendered HTML has been added to the DOM)
*/
function ComponentDef(component, componentId, componentsContext) {
this.___componentsContext = componentsContext; // The AsyncWriter that this component is associated with
this.___component = component;
this.id = componentId;
this.___domEvents = undefined; // An array of DOM events that need to be added (in sets of three)
this.___isExisting = false;
this.___renderBoundary = false;
this.___flags = 0;
this.___nextIdIndex = 0; // The unique integer to use for the next scoped ID
this.___keySequence = null;
}
ComponentDef.prototype = {
___nextKey: function (key) {
return (
this.___keySequence || (this.___keySequence = new KeySequence())
).___nextKey(key);
},
/**
* This helper method generates a unique and fully qualified DOM element ID
* that is unique within the scope of the current component.
*/
elId: function (nestedId) {
var id = this.id;
if (nestedId == null) {
return id;
} else {
if (typeof nestedId !== "string") {
// eslint-disable-next-line no-constant-condition
if ("MARKO_DEBUG") {
complain("Using non strings as keys is deprecated.");
}
nestedId = String(nestedId);
}
if (nestedId.indexOf("#") === 0) {
id = "#" + id;
nestedId = nestedId.substring(1);
}
return id + "-" + nestedId;
}
},
/**
* Returns the next auto generated unique ID for a nested DOM element or nested DOM component
*/
___nextComponentId: function () {
return this.id + "-c" + this.___nextIdIndex++;
},
d: function (eventName, handlerMethodName, isOnce, extraArgs) {
addDelegatedEventHandler(eventName);
return attachBubblingEvent(this, handlerMethodName, isOnce, extraArgs);
},
get ___type() {
return this.___component.___type;
},
};
ComponentDef.prototype.nk = ComponentDef.prototype.___nextKey;
ComponentDef.___deserialize = function (o, types, global, registry) {
var id = o[0];
var typeName = types[o[1]];
var input = o[2] || null;
var extra = o[3] || EMPTY_OBJECT;
var state = extra.s;
var componentProps = extra.w || EMPTY_OBJECT;
var flags = extra.f;
var isLegacy = flags & FLAG_IS_LEGACY;
var renderBody = flags & FLAG_HAS_RENDER_BODY ? w10NOOP : extra.r;
var component =
typeName /* legacy */ &&
registry.___createComponent(typeName, id, isLegacy);
// Prevent newly created component from being queued for update since we area
// just building it from the server info
component.___updateQueued = true;
component.___global = global;
if (isLegacy) {
component.widgetConfig = componentProps;
component.___widgetBody = renderBody;
} else if (renderBody) {
(input || (input = {})).renderBody = renderBody;
}
if (
!isLegacy &&
flags & FLAG_WILL_RERENDER_IN_BROWSER &&
!(flags & FLAG_OLD_HYDRATE_NO_CREATE)
) {
if (component.onCreate) {
component.onCreate(input, { global: global });
}
if (component.onInput) {
input = component.onInput(input, { global: global }) || input;
}
} else {
if (state) {
var undefinedPropNames = extra.u;
if (undefinedPropNames) {
undefinedPropNames.forEach(function (undefinedPropName) {
state[undefinedPropName] = undefined;
});
}
// We go through the setter here so that we convert the state object
// to an instance of `State`
component.state = state;
}
if (!isLegacy && componentProps) {
extend(component, componentProps);
}
}
component.___input = input;
if (extra.b) {
component.___bubblingDomEvents = extra.b;
}
var scope = extra.p;
var customEvents = extra.e;
if (customEvents) {
component.___setCustomEvents(customEvents, scope);
}
return {
id: id,
___component: component,
___domEvents: extra.d,
___flags: extra.f || 0,
};
};
module.exports = ComponentDef;