blob: 60b86766ddd1564d3ec45ea2336636b9bd996e45 [file] [log] [blame]
/**
* @file Base panel
* @author sushuang(sushuang@baidu.com)
*/
define(function (require) {
var $ = require('jquery');
var lib = require('../lib');
var Component = require('./Component');
var inner = lib.makeInner();
/**
* 行为规约:
* · enter
* · 用于“填入/刷新数据”等类似行为。
* · 可反复enter。
* · 第一次enter时触发_fillContent,可以用于进行某些初始化操作。
* · 每个实现类自己负责在_enter中调用和自身有“组合关系”的对象的enter。
* · clear
* · 可被用于“清空数据”等类似行为。并非dispose。
* · 可反复clear。
* · 实现类自己负责在_clear中调用和自身有“组合关系”的对象的clear。
* · new
* · 同Component的new创建实例,过程中触发_prepare和_init。
* · dispose
* · 同Component的dispose,只能执行一次,执行后再不可回复。
* · 一般初始化内部实例时使用_disposable功能,所以一般不需要单独写_dispose逻辑。
*
* 状态机示意:
* new {_prepare(), _init()}
* [NONE] ─────────────────────────────► [CREATED] ─►┐
* │ │
* dispose() {_dispose()} │ │
* [DISPOSED] ◄──┬◄─────────────────────────┴◄──┐ │
* │ │ │ enter() {
* │ enter() {_enter()} │ │ _fillContent()
* │ ┌──────────────────┐ │ │ }
* │ │ │ │ │
* ┌──────► [DATA_FILLED] ◄┘ ┌► [READY] ◄─┤
* │ │ │ │ │ │
* └───────────────┘ └────────────────┘ └───────►┘
* enter() {_enter()} clear() {_clear()} clear() {_clear()}
*
* @class
* @extends common/component/Component
*/
var BasePanel = inner.attach(Component.extend({
_define: {
viewModel: function () {
return {
/**
* @type {Object} @see lib.ob
*/
panelOpenStatus: null // 外部传入
};
},
viewModelPublic: ['panelOpenStatus']
},
/**
* 状态枚举常量。挂在prototype上是为了方便引用。
*
* @public
*/
PanelState: {
NONE: 'NONE',
CREATED: 'CREATED',
READY: 'READY',
DATA_FILLED: 'DATA_FILLED',
DISPOSED: 'DISPOSED'
},
/**
* 得到state
*
* @public
*/
getPanelState: function () {
/* eslint-disable xxx */
return inner(this)[STATE_PROP];
},
/**
* 子类不建议override此方法。
*
* @override
*/
_construct: function () {
setPanelState.call(this, this.PanelState.NONE);
var ret = this._applySuper('_construct', arguments);
setPanelState.call(this, this.PanelState.CREATED);
return ret;
},
/**
* 子类不建议override此方法。
*
* @override
*/
dispose: function () {
// CREATE, READY, DATA_FILLED都可使用此方法,不用进行前置状态检查。
var ret = this._applySuper('dispose', arguments);
setPanelState.call(this, this.PanelState.DISPOSED);
return ret;
},
/**
* 进入。可重复进入。
* 只有在第一次进入的时候,会触发 _fillContent。
*
* @public
* @param {Object=} options
*/
enter: function (options) {
// CREATE, READY, DATA_FILLED都可使用此方法,不用进行前置状态检查。
// 只有open才能enter
if (!this.isOpened()) {
return false;
}
if (this.getPanelState() === this.PanelState.CREATED) {
// 初始化内容
this._fillContent(options);
setPanelState.call(this, this.PanelState.READY);
}
this._enter(options);
setPanelState.call(this, this.PanelState.DATA_FILLED);
},
/**
* 第一次enter时会触发,一般用于进行初始化操作。
* 由子类实现。
*
* @protected
* @param {Object=} options
*/
_fillContent: $.noop,
/**
* 每次enter时被调用,可在其中对子panel进行enter。
* 由子类实现。
*
* @protected
* @param {Object=} options
*/
_enter: $.noop,
/**
* 清除。
*
* @public
*/
clear: function () {
// 前置状态检查
if (!checkPanelState.call(
this, [this.PanelState.DATA_FILLED, this.PanelState.READY]
)) {
return;
}
this._clear();
setPanelState.call(this, this.PanelState.READY);
},
/**
* 清除。
* 由子类实现。
*
* @protected
*/
_clear: $.noop,
/**
* 是否整体panel是打开状态
*
* @public
* @final
* @return {boolean}
*/
isOpened: function () {
var status = this._viewModel().panelOpenStatus;
return status
? status() === 'opened'
// 无panelOpenStatus时认为不提供open检测功能,永远open。
: true;
}
}));
/**
* 定为特殊的名字避免被子类覆盖
*
* @const
*/
var STATE_PROP = '__panelState__' + BasePanel.uid;
/**
* 写入state
*
* @inner
* @this {Object} 本BasePanel实例
*/
function setPanelState(state) {
inner(this)[STATE_PROP] = state;
}
/**
* 检查当前状态是否在给定的状态列表中。
*
* @inner
* @this {Object} 本panel实例。
* @param {Array.<string>} stateList 状态名列表,
* 如[this.PanelState.READY, ...]
* @return {boolean}
*/
function checkPanelState(stateList) {
return ~lib.arrayIndexOf(stateList, this.getPanelState());
}
return BasePanel;
});