mirror of
https://github.com/marko-js/marko.git
synced 2026-01-18 14:55:13 +00:00
168 lines
4.8 KiB
JavaScript
168 lines
4.8 KiB
JavaScript
"use strict";
|
|
var complain = "MARKO_DEBUG" && require("complain");
|
|
var componentUtil = require("./util");
|
|
var attachBubblingEvent = componentUtil.___attachBubblingEvent;
|
|
var addDelegatedEventHandler = require("./event-delegation")
|
|
.___addDelegatedEventHandler;
|
|
var extend = require("raptor-util/extend");
|
|
var KeySequence = require("./KeySequence");
|
|
|
|
var FLAG_WILL_RERENDER_IN_BROWSER = 1;
|
|
// var FLAG_HAS_BODY_EL = 2;
|
|
// var FLAG_HAS_HEAD_EL = 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, globalComponentsContext) {
|
|
this.___globalComponentsContext = globalComponentsContext; // 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;
|
|
|
|
this.___preservedDOMNodes = null;
|
|
}
|
|
|
|
ComponentDef.prototype = {
|
|
___nextKey: function(key) {
|
|
var keySequence =
|
|
this.___keySequence || (this.___keySequence = new KeySequence());
|
|
return keySequence.___nextKey(key);
|
|
},
|
|
|
|
___preserveDOMNode: function(key, bodyOnly) {
|
|
var lookup =
|
|
this.___preservedDOMNodes || (this.___preservedDOMNodes = {});
|
|
lookup[key] = bodyOnly ? 2 : 1;
|
|
},
|
|
|
|
/**
|
|
* 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.___deserialize = function(o, types, global, registry) {
|
|
var id = o[0];
|
|
var typeName = types[o[1]];
|
|
var input = o[2];
|
|
var extra = o[3];
|
|
|
|
var isLegacy = extra.l;
|
|
var state = extra.s;
|
|
var componentProps = extra.w;
|
|
var flags = extra.f;
|
|
|
|
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;
|
|
|
|
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 (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);
|
|
}
|
|
|
|
component.___global = global;
|
|
|
|
return {
|
|
id: id,
|
|
___component: component,
|
|
___boundary: extra.r,
|
|
___domEvents: extra.d,
|
|
___flags: extra.f || 0
|
|
};
|
|
};
|
|
|
|
module.exports = ComponentDef;
|