marko/components/util-browser.js

157 lines
4.5 KiB
JavaScript

var markoGlobal = window.$MG || (window.$MG = {
uid: 0
});
var runtimeId = markoGlobal.uid++;
var componentLookup = {};
var defaultDocument = document;
var EMPTY_OBJECT = {};
function getComponentForEl(el, doc) {
if (el) {
var node = typeof el == 'string' ? (doc || defaultDocument).getElementById(el) : el;
if (node) {
var component = node._w;
while(component) {
var rootFor = component.$__rootFor;
if (rootFor) {
component = rootFor;
} else {
break;
}
}
return component;
}
}
}
var lifecycleEventMethods = {};
[
'create',
'render',
'update',
'mount',
'destroy'
].forEach(function(eventName) {
lifecycleEventMethods[eventName] = 'on' + eventName[0].toUpperCase() + eventName.substring(1);
});
/**
* This method handles invoking a component's event handler method
* (if present) while also emitting the event through
* the standard EventEmitter.prototype.emit method.
*
* Special events and their corresponding handler methods
* include the following:
*
* beforeDestroy --> onBeforeDestroy
* destroy --> onDestroy
* beforeUpdate --> onBeforeUpdate
* update --> onUpdate
* render --> onRender
*/
function emitLifecycleEvent(component, eventType, eventArg1, eventArg2) {
var listenerMethod = component[lifecycleEventMethods[eventType]];
if (listenerMethod !== undefined) {
listenerMethod.call(component, eventArg1, eventArg2);
}
component.emit(eventType, eventArg1, eventArg2);
}
function destroyComponentForEl(el) {
var componentToDestroy = el._w;
if (componentToDestroy) {
componentToDestroy.$__destroyShallow();
el._w = null;
while ((componentToDestroy = componentToDestroy.$__rootFor)) {
componentToDestroy.$__rootFor = null;
componentToDestroy.$__destroyShallow();
}
}
}
function destroyElRecursive(el) {
var curChild = el.firstChild;
while(curChild) {
if (curChild.nodeType === 1) {
destroyComponentForEl(curChild);
destroyElRecursive(curChild);
}
curChild = curChild.nextSibling;
}
}
function nextComponentId() {
// Each component will get an ID that is unique across all loaded
// marko runtimes. This allows multiple instances of marko to be
// loaded in the same window and they should all place nice
// together
return 'b' + ((markoGlobal.uid)++);
}
function nextComponentIdProvider(out) {
return nextComponentId;
}
function getElementById(doc, id) {
return doc.getElementById(id);
}
function attachBubblingEvent(componentDef, handlerMethodName, extraArgs) {
if (handlerMethodName) {
var id = componentDef.id;
if (extraArgs) {
var isRerenderInBrowser = componentDef.$__globalComponentsContext.$__isRerenderInBrowser;
if (isRerenderInBrowser === true) {
// If we are bootstrapping a page rendered on the server
// we need to put the actual event args on the UI component
// since we will not actually be updating the DOM
var component = componentDef.$__component;
var bubblingDomEvents = component.$__bubblingDomEvents ||
( component.$__bubblingDomEvents = [] );
bubblingDomEvents.push(extraArgs);
return;
} else {
return [handlerMethodName, id, extraArgs];
}
} else {
return [handlerMethodName, id];
}
}
}
function getMarkoPropsFromEl(el) {
var virtualProps = el._vprops;
if (virtualProps === undefined) {
virtualProps = el.getAttribute('data-marko');
if (virtualProps) {
virtualProps = JSON.parse(virtualProps);
}
el._vprops = virtualProps = virtualProps || EMPTY_OBJECT;
}
return virtualProps;
}
exports.$__runtimeId = runtimeId;
exports.$__componentLookup = componentLookup;
exports.$__getComponentForEl = getComponentForEl;
exports.$__emitLifecycleEvent = emitLifecycleEvent;
exports.$__destroyComponentForEl = destroyComponentForEl;
exports.$__destroyElRecursive = destroyElRecursive;
exports.$__nextComponentIdProvider = nextComponentIdProvider;
exports.$__getElementById = getElementById;
exports.$__attachBubblingEvent = attachBubblingEvent;
exports.$__getMarkoPropsFromEl = getMarkoPropsFromEl;