marko
Version:
UI Components + streaming, async, high performance, HTML templating for Node.js and the browser.
333 lines (232 loc) • 6.64 kB
JavaScript
"use strict";
/* jshint newcap:false */
var BaseState;
var BaseComponent;
var inherit;
var req = require("@internal/require");
var registry = require("@internal/components-registry");
var jQuery = require("../../../runtime/components/legacy/jquery");
var ready = require("../../../runtime/components/legacy/ready");
var stateToJSONDef = {
enumerable: false,
value: function returnSelf() {
return this;
}
};
function noop() {}
module.exports = function defineWidget(def, renderer) {
def = def.Widget || def;
if (def.x_) {
return def;
}
var ComponentClass = function () {};
var proto;
var legacyInit;
if (typeof def === "function") {
proto = def.prototype;
legacyInit = def;
} else if (typeof def === "object") {
proto = def;
legacyInit = def.init;
} else {
throw TypeError();
}
ComponentClass.prototype = proto;
// We don't use the constructor provided by the user
// since we don't invoke their constructor until
// we have had a chance to do our own initialization.
// Instead, we store their constructor in the "initComponent"
// property and that method gets called later inside
// init-components-browser.js
function Component(id, doc) {
BaseComponent.call(this, id, doc);
}
if (!proto.x_) {
// Inherit from Component if they didn't already
ComponentClass.prototype = Object.create(BaseComponent.prototype);
for (var propName in proto) {
if (proto.hasOwnProperty(propName)) {
ComponentClass.prototype[propName] = proto[propName];
}
}
}
// The same prototype will be used by our constructor after
// we he have set up the prototype chain using the inherit function
proto = Component.prototype = ComponentClass.prototype;
proto.y_ = true;
proto.constructor = def.constructor = Component;
Object.defineProperty(proto, "state", {
get: function () {
var raw = this.z_ && this.z_.A_;
if (raw && !raw.toJSON) {
Object.defineProperty(this.z_.A_, "toJSON", stateToJSONDef);
}
return raw;
},
set: function (newState) {
newState = newState || {};
// eslint-disable-next-line no-constant-condition
this.setState(newState);
}
});
Object.defineProperty(proto, "__document", {
get: function () {
// eslint-disable-next-line no-constant-condition
return this.B_;
}
});
Object.defineProperty(proto, "el", {
get: function () {
// eslint-disable-next-line no-constant-condition
return this.C_;
}
});
// get legacy methods
proto.D_ = proto.onRender;
Object.defineProperty(proto, "onRender", {
get: noop,
set: function (v) {
proto.D_ = v;
}
});
proto.E_ = proto.onUpdate;
Object.defineProperty(proto, "onUpdate", {
get: function () {
return modernMountOrUpdate;
},
set: function (v) {
proto.E_ = v;
}
});
proto.F_ = proto.onDestroy;
Object.defineProperty(proto, "onDestroy", {
get: function () {
return modernOnDestory;
},
set: function (v) {
proto.F_ = v;
}
});
proto.getWidget = proto.getComponent;
proto.getWidgets = proto.getComponents;
proto.onMount = modernMountOrUpdate;
if (legacyInit) {
proto.G_ = legacyInit;
}
// convert legacy to modern
proto.H_ = proto.update;
proto.update = function () {
if (this.I_) {
// eslint-disable-next-line no-constant-condition
this.destroy = modernOnDestory;
this.I_ = false;
}
this.J_ = true;
if (this.C_) {
this.onBeforeUpdate && this.onBeforeUpdate();
}
this.H_();
this.J_ = false;
};
function modernMountOrUpdate() {
var self = this;
var el = this.K_["@_wbind"];
var prevEl = this.C_;
if (prevEl !== el) {
this.C_ = el;
if (prevEl) {
this.onBeforeDestroy && this.onBeforeDestroy();
this.F_ && this.F_();
this.L_ = undefined;
this.removeAllListeners();
}
if (el) {
this.G_ && this.G_(this.widgetConfig || {});
this.D_ && this.D_({ firstRender: true });
this.L_ = legacyRender;
// eslint-disable-next-line no-constant-condition
el.__widget = this;
}
} else if (el) {
if (prevEl) {
this.E_ && this.E_();
}
if (this.M_) {
this.D_ &&
this.D_({ firstRender: false });
}
}
this.N_ = this.O_;
this.O_ = null;
this.M_ = false;
}
function legacyRender() {
if (!this.J_) {
this.onBeforeUpdate && this.onBeforeUpdate();
}
this.M_ = true;
}
function modernOnDestory() {
if (this.C_) {
this.onBeforeDestroy && this.onBeforeDestroy();
this.F_ && this.F_();
this.C_ = null;
}
}
// Set a flag on the constructor function to make it clear this is
// a component so that we can short-circuit this work later
Component.x_ = true;
function State() {
BaseState.apply(this, arguments);
}
inherit(State, BaseState);
proto.P_ = State;
jQuery.patchComponent(
window.$,
proto,
true /* don't throw error until used if `$` is missing*/
);
ready.patchComponent(proto);
if (!renderer) {
renderer = ComponentClass.renderer || ComponentClass.prototype.renderer;
if (renderer) {
// Legacy support
var createOut = renderer.createOut;
if (typeof renderer !== "function") {
var rendererObject = renderer;
renderer = function (input, out) {
var rendererFunc = rendererObject.renderer || rendererObject.render;
rendererFunc(input, out);
};
renderer.createOut = createOut;
}
renderer.render = function (input) {
var out = createOut();
renderer(input, out);
return out.end();
};
}
}
if (renderer) {
// Add the rendering related methods as statics on the
// new component constructor function
Component.renderer = proto.Q_ = renderer;
Component.render = renderer.render;
Component.renderSync = renderer.renderSync;
}
// eslint-disable-next-line no-constant-condition
Component._isWidget = true;
var template = def.template;
if (template) {
if (typeof template === "string") {
template = req(template);
}
registry.r((template.default || template).R_, function () {
return Component;
});
}
return Component;
};
BaseState = require("../../../runtime/components/State");
BaseComponent = require("../../../runtime/components/Component");
inherit = require("raptor-util/inherit");