Comparing version 0.3.0-alpha.0 to 0.3.0
{ | ||
"name": "okam-core", | ||
"version": "0.3.0-alpha.0", | ||
"version": "0.3.0", | ||
"description": "The extension for small program framework", | ||
@@ -33,3 +33,3 @@ "main": "index.js", | ||
}, | ||
"gitHead": "0ed261a68474d31fe211483ba154555471eea32c" | ||
"gitHead": "6ed61daccfe296b8679452d8b5a2b1af287344c3" | ||
} |
@@ -10,2 +10,17 @@ /** | ||
/** | ||
* Emit custom component event | ||
* | ||
* @param {...any} args the event arguments | ||
*/ | ||
componentBase.methods.$emit = function (...args) { | ||
this.__beforeEmit && this.__beforeEmit(args); | ||
this.$listener.emit.apply(this.$listener, args); | ||
let eventProp = args[0]; | ||
eventProp = 'on' + eventProp.charAt(0).toUpperCase() + eventProp.substr(1); | ||
let eventHandler = this.props[eventProp]; | ||
eventHandler.call(this, args[1]); | ||
}; | ||
export default Object.assign(componentBase, { | ||
@@ -12,0 +27,0 @@ didMount() { |
@@ -9,5 +9,16 @@ /** | ||
import {createComponent} from '../helper/factory'; | ||
import {normalizeEventArgs} from './helper/triggerEvent'; | ||
import {normalizeComponent} from './helper/component'; | ||
import componentBase from './base/component'; | ||
/** | ||
* Fix ant component event args | ||
* | ||
* @param {Array} args the event args | ||
* @return {Array} | ||
*/ | ||
componentBase.methods.__beforeEmit = function (args) { | ||
return normalizeEventArgs(this, args); | ||
}; | ||
export default function extendComponent(componentInfo, refComponents) { | ||
@@ -14,0 +25,0 @@ return createComponent( |
@@ -8,3 +8,2 @@ /** | ||
import {normalizeProps} from '../../helper/props'; | ||
import {normalizeMethods} from '../../helper/methods'; | ||
@@ -23,2 +22,20 @@ | ||
/** | ||
* Normalize component props data using mini program syntax | ||
* | ||
* @param {Object} props the props data to normalize | ||
* @return {?Object} | ||
*/ | ||
function normalizeProps(props) { | ||
Object.keys(props).forEach(k => { | ||
let propValue = props[k]; | ||
let defaultValue = null; | ||
if (propValue && propValue.default !== undefined) { | ||
defaultValue = propValue.default; | ||
} | ||
props[k] = defaultValue; | ||
}); | ||
return props; | ||
} | ||
/** | ||
* Normalize the component or behavior attribute names to native | ||
@@ -25,0 +42,0 @@ * |
@@ -23,2 +23,4 @@ /** | ||
Object.assign(this, base); | ||
let promiseApis = this.$promisifyApis; | ||
@@ -50,3 +52,3 @@ let interceptAPis = this.$interceptApis; | ||
export default Object.assign({ | ||
export default { | ||
@@ -70,3 +72,3 @@ /** | ||
} | ||
}, base); | ||
}; | ||
@@ -13,112 +13,2 @@ /** | ||
/** | ||
* Normalize event arguments to fix the native swan framework bug | ||
* | ||
* @inner | ||
* @param {Object} args the event args to normalize | ||
* @return {Object} | ||
*/ | ||
function normalizeEventArgs(args) { | ||
let eventData = args[1]; | ||
if (eventData.currentTarget && eventData.target) { | ||
return args; | ||
} | ||
let propData = this.properties; | ||
let dataset = {}; | ||
propData && Object.keys(propData).forEach(k => { | ||
if (/^data\w+$/.test(k)) { | ||
let dataKey = k.replace( | ||
/^data(\w)/, | ||
(match, char) => char.toLowerCase() | ||
); | ||
dataset[dataKey] = propData[k]; | ||
} | ||
}); | ||
let eventObj = { | ||
type: args[0], | ||
currentTarget: { | ||
dataset, | ||
id: this.id | ||
}, | ||
target: { | ||
dataset, | ||
id: this.id | ||
}, | ||
detail: eventData | ||
}; | ||
args[1] = eventObj; | ||
return args; | ||
} | ||
/** | ||
* Query the reference instance information by the given reference class | ||
* | ||
* @inner | ||
* @param {string|Array.<string>} value the reference class | ||
* @return {?Object|Array} | ||
*/ | ||
function queryRefInstance(value) { | ||
let isSelectAll = Array.isArray(value); | ||
let result; | ||
if (isSelectAll) { | ||
let path = `.${value[0]}`; | ||
if (typeof this.selectAllComponents === 'function') { | ||
result = this.selectAllComponents(path); | ||
} | ||
if (!result || !result.length) { | ||
result = this.$selector.selectAll(path); | ||
} | ||
} | ||
else { | ||
let path = `.${value}`; | ||
if (typeof this.selectComponent === 'function') { | ||
result = this.selectComponent(path); | ||
} | ||
if (!result) { | ||
// if not custom component, try to query element info by selector API | ||
result = this.$selector.select(path); | ||
} | ||
} | ||
return result; | ||
} | ||
/** | ||
* Initialize the `$refs` value | ||
* | ||
* @inner | ||
*/ | ||
function initRefs() { | ||
this.$refs = {}; | ||
let refs = this.$rawRefData; | ||
if (typeof refs === 'function') { | ||
refs = refs(); | ||
} | ||
if (!refs) { | ||
return; | ||
} | ||
let result = {}; | ||
const self = this; | ||
Object.keys(refs).forEach(id => { | ||
result[id] = { | ||
get() { | ||
let value = refs[id]; | ||
return queryRefInstance.call(self, value); | ||
}, | ||
enumerable: true | ||
}; | ||
}); | ||
Object.defineProperties(this.$refs, result); | ||
} | ||
export default { | ||
@@ -161,5 +51,2 @@ | ||
ready() { | ||
// init component refs | ||
initRefs.call(this); | ||
// call mounted hook | ||
@@ -179,3 +66,3 @@ this.mounted && this.mounted(); | ||
this.$listener.off(); | ||
this.$refs = this.$selector = null; | ||
this.$selector = null; | ||
this.$isDestroyed = true; // add destroyed flag | ||
@@ -192,6 +79,6 @@ | ||
* | ||
* @param {...any} args the event arguments | ||
* @param {...any} args the event arguments | ||
*/ | ||
$emit(...args) { | ||
args = normalizeEventArgs.call(this, args); | ||
this.__beforeEmit && this.__beforeEmit(args); | ||
this.$listener.emit.apply(this.$listener, args); | ||
@@ -198,0 +85,0 @@ |
/** | ||
* @file Create component instance | ||
* @file Create swan component instance | ||
* @author sparklewhy@gmail.com | ||
@@ -10,5 +10,16 @@ */ | ||
import {normalizeComponent} from './helper/component'; | ||
import {normalizeEventArgs} from './swan/triggerEvent'; | ||
import componentBase from './base/component'; | ||
/** | ||
* Fix swan component event args | ||
* | ||
* @param {Array} args the event args | ||
* @return {Array} | ||
*/ | ||
componentBase.methods.__beforeEmit = function (args) { | ||
return normalizeEventArgs(this, args); | ||
}; | ||
/** | ||
* Create component instance | ||
@@ -15,0 +26,0 @@ * |
@@ -10,5 +10,14 @@ /** | ||
import {normalizeExtendProp} from '../helper/methods'; | ||
import eventCenter from '../helper/eventCenter'; | ||
const ONCE_LISTEN_REGEXP = /^(.*)\.once$/; | ||
const broadcastAPIs = { | ||
/** | ||
* Send broadcast event | ||
* | ||
* @param {...any} args the broadcast args | ||
*/ | ||
$broadcast(...args) { | ||
@@ -18,3 +27,10 @@ eventCenter.emit.apply(eventCenter, args); | ||
$onbroadcast(eventName, handler, isOnce) { | ||
/** | ||
* Listen broadcast event | ||
* | ||
* @param {string} eventName the event name to broadcast | ||
* @param {Function} handler the listen handler | ||
* @param {boolean=} isOnce whether is once listen, optional, by default false | ||
*/ | ||
$onBroadcast(eventName, handler, isOnce) { | ||
let bindEvents = this._bindBroadcastEvents; | ||
@@ -35,8 +51,19 @@ if (!bindEvents) { | ||
$offbroadcast(eventName, handler) { | ||
/** | ||
* Remove broadcast event listener | ||
* | ||
* @param {string} eventName the event to remove | ||
* @param {Function} handler the handler to remove | ||
*/ | ||
$offBroadcast(eventName, handler) { | ||
eventCenter.off(eventName, handler); | ||
}, | ||
bindBroadcastEvents() { | ||
let events = this.events; | ||
/** | ||
* Bind the declaration broadcast events | ||
* | ||
* @param {Object} events the broadcast events to listen | ||
* @private | ||
*/ | ||
__bindBroadcastEvents(events) { | ||
if (!events) { | ||
@@ -46,4 +73,4 @@ return; | ||
let onceRegexp = /^(.*)\.once$/; | ||
let bindEvents = this._bindBroadcastEvents; | ||
/* istanbul ignore next */ | ||
if (!bindEvents) { | ||
@@ -54,3 +81,3 @@ bindEvents = this._bindBroadcastEvents = []; | ||
Object.keys(events).forEach(k => { | ||
let result = onceRegexp.exec(k); | ||
let result = ONCE_LISTEN_REGEXP.exec(k); | ||
let eventName = result ? result[1] : k; | ||
@@ -70,4 +97,10 @@ let handler = events[k].bind(this); | ||
removeBroadcastEventListeners() { | ||
/** | ||
* Remove the bind broadcast events | ||
* | ||
* @private | ||
*/ | ||
__removeBroadcastEventListeners() { | ||
let bindEvents = this._bindBroadcastEvents; | ||
/* istanbul ignore next */ | ||
if (!bindEvents) { | ||
@@ -84,4 +117,10 @@ return; | ||
app: Object.assign({ | ||
ready() { | ||
this.bindBroadcastEvents(); | ||
/** | ||
* The hook when app launch | ||
* | ||
* @private | ||
*/ | ||
onLaunch() { | ||
this.__bindBroadcastEvents(this.broadcastEvents); | ||
} | ||
@@ -91,8 +130,35 @@ }, broadcastAPIs), | ||
component: { | ||
ready() { | ||
this.bindBroadcastEvents(); | ||
/** | ||
* The instance initialization before the instance is normalized and created. | ||
* | ||
* @param {boolean} isPage whether is page component | ||
* @private | ||
*/ | ||
$init(isPage) { | ||
normalizeExtendProp( | ||
this, 'broadcastEvents', '$rawBroadcastEvents', isPage | ||
); | ||
}, | ||
/** | ||
* The hook when component created | ||
* | ||
* @private | ||
*/ | ||
created() { | ||
let events = this.$rawBroadcastEvents; | ||
if (typeof events === 'function') { | ||
events = this.$rawBroadcastEvents = events(); | ||
} | ||
this.__bindBroadcastEvents(events); | ||
}, | ||
/** | ||
* The hook when component detached | ||
* | ||
* @private | ||
*/ | ||
detached() { | ||
this.removeBroadcastEventListeners(); | ||
this.__removeBroadcastEventListeners(); | ||
}, | ||
@@ -99,0 +165,0 @@ |
@@ -9,5 +9,6 @@ /** | ||
import {isPlainObject} from '../../../util/index'; | ||
import EventListener from '../../../util/EventListener'; | ||
import {normalizeExtendProp} from '../../../helper/methods'; | ||
import {default as Observer, proxyObject} from './Observer'; | ||
import ComputedObserver from './ComputedObserver'; | ||
import EventListener from '../../../util/EventListener'; | ||
import nextTick from './nextTick'; | ||
@@ -17,2 +18,9 @@ import {getSetDataPaths} from './setData'; | ||
/** | ||
* The component property data key | ||
* | ||
* @type {string} | ||
*/ | ||
let propDataKey = 'data'; | ||
/** | ||
* Make computed props observable | ||
@@ -60,3 +68,3 @@ * | ||
let observer = new Observer(ctx, ctx.data, null, true); | ||
let observer = new Observer(ctx, ctx[propDataKey] || {}, null, true); | ||
let propsObj = {}; | ||
@@ -103,6 +111,7 @@ | ||
* | ||
* @private | ||
* @inner | ||
* @param {Object} ctx the component definition context | ||
* @param {boolean} isPage whether is page component | ||
*/ | ||
function initProps(ctx) { | ||
function initProps(ctx, isPage) { | ||
// cache the raw props information because the mini program will merge data | ||
@@ -115,3 +124,5 @@ // and props later on. | ||
ctx.$rawProps = Object.assign({}, props); | ||
let rawProps = Object.assign({}, props); | ||
ctx.rawProps = rawProps; | ||
normalizeExtendProp(ctx, 'rawProps', '$rawProps', isPage); | ||
@@ -129,2 +140,11 @@ Object.keys(props).forEach(p => { | ||
/** | ||
* Set the component property data key | ||
* | ||
* @param {string} key the prop data key | ||
*/ | ||
export function setPropDataKey(key) { | ||
key && (propDataKey = key); | ||
} | ||
export default { | ||
@@ -136,12 +156,10 @@ component: { | ||
* | ||
* @param {boolean} isPage whether is page component | ||
* @private | ||
*/ | ||
$init() { | ||
initProps(this); | ||
$init(isPage) { | ||
initProps(this, isPage); | ||
let computed = this.computed; | ||
if (computed) { | ||
this.$rawComputed = computed; | ||
delete this.computed; | ||
} | ||
// normalize extend computed property | ||
normalizeExtendProp(this, 'computed', '$rawComputed', isPage); | ||
}, | ||
@@ -163,2 +181,10 @@ | ||
this.$dataListener = new EventListener(); | ||
if (this.$rawComputed) { | ||
// fix ant reference bug: `this.data.xx` operation is not allowed | ||
// when page onload, otherwise it'll affect the init data state | ||
// of the page when load next time. | ||
// So, here create a shadow copy of data. | ||
this.data = Object.assign({}, this.data); | ||
} | ||
this.__propsObserver = makePropsObservable(this); | ||
@@ -165,0 +191,0 @@ this.__dataObserver = makeDataObservable(this); |
@@ -9,2 +9,4 @@ /** | ||
import {normalizeExtendProp} from '../../helper/methods'; | ||
function toDataGetter(path) { | ||
@@ -88,8 +90,11 @@ let parts = path.split('.'); | ||
$init() { | ||
let watch = this.watch; | ||
if (watch) { | ||
this.$rawWatch = watch; | ||
delete this.watch; | ||
} | ||
/** | ||
* The instance initialization before the instance is normalized and created. | ||
* | ||
* @param {boolean} isPage whether is page component | ||
* @private | ||
*/ | ||
$init(isPage) { | ||
// normalize extended watch property | ||
normalizeExtendProp(this, 'watch', '$rawWatch', isPage); | ||
}, | ||
@@ -96,0 +101,0 @@ |
/** | ||
* @file Component helper | ||
* @file Component normalizer helper | ||
* @author sparklewhy@gmail.com | ||
@@ -8,6 +8,22 @@ */ | ||
import {normalizeProps} from './props'; | ||
import {normalizeMethods} from './methods'; | ||
/** | ||
* Normalize component props data using mini program syntax | ||
* | ||
* @param {Object} props the props data to normalize | ||
* @return {?Object} | ||
*/ | ||
function normalizeProps(props) { | ||
Object.keys(props).forEach(k => { | ||
let propValue = props[k]; | ||
if (propValue && propValue.default !== undefined) { | ||
propValue.value = propValue.default; | ||
delete propValue.default; | ||
} | ||
}); | ||
return props; | ||
} | ||
/** | ||
* Normalize the component or behavior attribute names to native | ||
@@ -14,0 +30,0 @@ * |
@@ -78,4 +78,3 @@ /** | ||
refData && (instance.$rawRefData = refData); | ||
instance.$init && instance.$init(isPage); | ||
instance.$init && instance.$init(isPage, refData); | ||
} | ||
@@ -82,0 +81,0 @@ |
@@ -17,10 +17,31 @@ /** | ||
'beforeDestroy', 'destroyed', | ||
'beforeUpdate', 'updated', | ||
'$rawComputed', | ||
'$rawWatch', | ||
'$rawProps', | ||
'$rawRefData' | ||
'beforeUpdate', 'updated' | ||
]; | ||
/** | ||
* Normalize extended property | ||
* | ||
* @param {Object} component the component instance | ||
* @param {string} propName the extended property name | ||
* @param {string} newPropName the new extended property name | ||
* @param {boolean} isPage whether is page component | ||
*/ | ||
export function normalizeExtendProp(component, propName, newPropName, isPage) { | ||
let value = component[propName]; | ||
if (!value) { | ||
return; | ||
} | ||
delete component[propName]; | ||
if (isPage) { | ||
component[newPropName] = value; | ||
} | ||
else { | ||
let methods = component.methods; | ||
methods || (component.methods = methods = {}); | ||
methods[newPropName] = () => value; | ||
} | ||
} | ||
/** | ||
* Normalize component methods | ||
@@ -53,7 +74,8 @@ * | ||
if (Object.keys(methods).length) { | ||
componentInfo.methods = Object.assign( | ||
{}, methods, componentInfo.methods | ||
); | ||
let currMethods = componentInfo.methods || {}; | ||
componentInfo.methods = currMethods; | ||
Object.assign(currMethods, methods); | ||
} | ||
return componentInfo; | ||
} |
/** | ||
* @file Component props helper | ||
* @file OKAM component props helper | ||
* @author sparklewhy@gmail.com | ||
@@ -72,19 +72,1 @@ */ | ||
} | ||
/** | ||
* Normalize component props data using mini program syntax | ||
* | ||
* @param {Object} props the props data to normalize | ||
* @return {?Object} | ||
*/ | ||
export function normalizeProps(props) { | ||
Object.keys(props).forEach(k => { | ||
let propValue = props[k]; | ||
if (propValue && propValue.default !== undefined) { | ||
propValue.value = propValue.default; | ||
delete propValue.default; | ||
} | ||
}); | ||
return props; | ||
} | ||
@@ -63,3 +63,4 @@ /** | ||
else if (!target.hasOwnProperty(k)) { | ||
target[k] = sValue; | ||
target[k] = isPlainObject(sValue) | ||
? Object.assign({}, sValue) : sValue; | ||
} | ||
@@ -75,3 +76,3 @@ } | ||
* If the target and sources prop value is both function type, it'll create a new function, | ||
* the function will call sources first (parent), then call target(child). | ||
* the function will call sources first(parent), then call target(child). | ||
* | ||
@@ -78,0 +79,0 @@ * The mixin is shadow mixin, it means that only the first level props of the target will mixin. |
@@ -8,3 +8,22 @@ /** | ||
import Component from '../Component'; | ||
export default Component; | ||
import {createComponent} from '../helper/factory'; | ||
import {normalizeComponent} from '../helper/component'; | ||
import componentBase from '../base/component'; | ||
/** | ||
* Create component instance | ||
* | ||
* @param {Object} componentInfo the component information | ||
* @param {Object} refComponents the component reference used in the component, the | ||
* reference information is defined in the template | ||
* @return {Object} | ||
*/ | ||
export default function extendComponent(componentInfo, refComponents) { | ||
return createComponent( | ||
componentInfo, | ||
componentBase, | ||
normalizeComponent, | ||
refComponents | ||
); | ||
} | ||
116833
59
3985