forked from fanruan/fineui
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
500 lines
16 KiB
500 lines
16 KiB
import { |
|
Layout, |
|
AbsoluteLayout, |
|
emptyFn, |
|
shortcut, |
|
extend, |
|
isFunction, |
|
createWidget, |
|
Widget, |
|
isObject, |
|
Controller, |
|
isIE, |
|
getIEVersion, |
|
nextTick, |
|
isKey, |
|
isNull, |
|
DOM, |
|
debounce, |
|
KeyCode, |
|
EVENT_RESPONSE_TIME, |
|
Events, |
|
Actions |
|
} from "@/core"; |
|
import { BubbleCombo } from "@/case/combo/bubblecombo/combo.bubble"; |
|
import { Single } from "../0.single"; |
|
import { BubblePopupBarView, TextBubblePopupBarView } from "@/case/combo/bubblecombo/popup.bubble"; |
|
|
|
/** |
|
* guy |
|
* @class BasicButton |
|
* @extends Single |
|
* |
|
* 一般的button父级 |
|
*/ |
|
@shortcut() |
|
export class BasicButton extends Single { |
|
static xtype = "bi.basic_button"; |
|
|
|
static EVENT_CHANGE = "BasicButton.EVENT_CHANGE"; |
|
|
|
_defaultConfig() { |
|
const conf = super._defaultConfig(...arguments); |
|
|
|
return extend(conf, { |
|
_baseCls: `${conf._baseCls || ""} bi-basic-button${conf.invalid ? "" : " cursor-pointer"}${ |
|
isIE() && getIEVersion() < 10 ? " hack" : "" |
|
}`, |
|
// el: {} // 可以通过el来创建button元素 |
|
value: "", |
|
stopEvent: false, |
|
stopPropagation: false, |
|
selected: false, |
|
once: false, // 点击一次选中有效,再点无效 |
|
forceSelected: false, // 点击即选中, 选中了就不会被取消,与once的区别是forceSelected不影响事件的触发 |
|
forceNotSelected: false, // 无论怎么点击都不会被选中 |
|
disableSelected: false, // 使能选中 |
|
|
|
shadow: false, |
|
isShadowShowingOnSelected: false, // 选中状态下是否显示阴影 |
|
trigger: null, |
|
handler: emptyFn, |
|
bubble: null, |
|
debounce: true, |
|
}); |
|
} |
|
|
|
_init() { |
|
const opts = this.options; |
|
opts.selected = isFunction(opts.selected) |
|
? this.__watch(opts.selected, (context, newValue) => { |
|
this.setSelected(newValue); |
|
}) |
|
: opts.selected; |
|
super._init(arguments); |
|
|
|
if (opts.shadow) { |
|
this._createShadow(); |
|
} |
|
if (opts.level) { |
|
this.element.addClass(`button-${opts.level}`); |
|
} |
|
} |
|
|
|
_initRef() { |
|
if (this.options.selected === true) { |
|
this.setSelected(true); |
|
} |
|
// 延迟绑定事件,这样可以将自己绑定的事情优先执行 |
|
nextTick(() => { |
|
!this.isDestroyed() && this.bindEvent(); |
|
}); |
|
super._initRef.apply(this, arguments); |
|
} |
|
|
|
// 默认render方法 |
|
render() { |
|
return this.options.el; |
|
} |
|
|
|
_createShadow() { |
|
const o = this.options; |
|
|
|
const assertMask = () => { |
|
if (!this.$mask) { |
|
this.$mask = createWidget(isObject(o.shadow) ? o.shadow : {}, { |
|
type: Layout.xtype, |
|
cls: "bi-button-mask", |
|
}); |
|
this.$mask.invisible(); |
|
createWidget({ |
|
type: AbsoluteLayout.xtype, |
|
element: this, |
|
items: [ |
|
{ |
|
el: this.$mask, |
|
left: 0, |
|
right: 0, |
|
top: 0, |
|
bottom: 0, |
|
} |
|
], |
|
}); |
|
} |
|
}; |
|
|
|
this.element.mouseup(() => { |
|
if (!this._hover && !o.isShadowShowingOnSelected) { |
|
assertMask(); |
|
this.$mask.invisible(); |
|
} |
|
}); |
|
this.element.on(`mouseenter.${this.getName()}`, e => { |
|
if (this.element.__isMouseInBounds__(e)) { |
|
if (this.isEnabled() && !this._hover && (o.isShadowShowingOnSelected || !this.isSelected())) { |
|
assertMask(); |
|
this.$mask.visible(); |
|
} |
|
} |
|
}); |
|
this.element.on(`mousemove.${this.getName()}`, e => { |
|
if (!this.element.__isMouseInBounds__(e)) { |
|
if (this.isEnabled() && !this._hover) { |
|
assertMask(); |
|
this.$mask.invisible(); |
|
} |
|
} |
|
}); |
|
this.element.on(`mouseleave.${this.getName()}`, () => { |
|
if (this.isEnabled() && !this._hover) { |
|
assertMask(); |
|
this.$mask.invisible(); |
|
} |
|
}); |
|
} |
|
|
|
bindEvent() { |
|
const o = this.options; |
|
let hand = this.handle(); |
|
if (!hand) { |
|
return; |
|
} |
|
hand = hand.element; |
|
|
|
const getBubble = () => { |
|
const bubble = o.bubble; |
|
if (isFunction(bubble)) { |
|
return bubble(); |
|
} |
|
|
|
return bubble; |
|
}; |
|
|
|
const clk = e => { |
|
ev(e); |
|
if (!this.isEnabled() || !this.isValid()) { |
|
return; |
|
} |
|
if (this.isOnce() && this.isSelected()) { |
|
return; |
|
} |
|
if (isKey(o.bubble) || isFunction(o.bubble)) { |
|
if (isNull(this.combo)) { |
|
let popup; |
|
createWidget({ |
|
type: AbsoluteLayout.xtype, |
|
element: this, |
|
items: [ |
|
{ |
|
el: { |
|
type: BubbleCombo.xtype, |
|
trigger: "", |
|
// bubble的提示不需要一直存在在界面上 |
|
destroyWhenHide: true, |
|
ref: _ref => { |
|
this.combo = _ref; |
|
}, |
|
el: { |
|
type: Layout.xtype, |
|
height: "100%", |
|
}, |
|
popup: { |
|
type: TextBubblePopupBarView.xtype, |
|
text: getBubble(), |
|
ref: _ref => { |
|
popup = _ref; |
|
}, |
|
listeners: [ |
|
{ |
|
eventName: BubblePopupBarView.EVENT_CLICK_TOOLBAR_BUTTON, |
|
action: (...args) => { |
|
const [v] = args; |
|
this.combo.hideView(); |
|
if (v) { |
|
onClick.apply(this, args); |
|
} |
|
}, |
|
} |
|
], |
|
}, |
|
listeners: [ |
|
{ |
|
eventName: BubbleCombo.EVENT_BEFORE_POPUPVIEW, |
|
action() { |
|
popup.populate(getBubble()); |
|
}, |
|
} |
|
], |
|
}, |
|
left: 0, |
|
right: 0, |
|
bottom: 0, |
|
top: 0, |
|
} |
|
], |
|
}); |
|
} |
|
if (this.combo.isViewVisible()) { |
|
this.combo.hideView(); |
|
} else { |
|
this.combo.showView(); |
|
} |
|
|
|
return; |
|
} |
|
onClick.apply(this, arguments); |
|
}; |
|
|
|
const triggerArr = (o.trigger || "").split(","); |
|
triggerArr.forEach(trigger => { |
|
let mouseDown = false; |
|
let selected = false; |
|
let interval; |
|
switch (trigger) { |
|
case "mouseup": |
|
hand.mousedown(() => { |
|
mouseDown = true; |
|
}); |
|
hand.mouseup(e => { |
|
if (mouseDown === true) { |
|
clk(e); |
|
} |
|
mouseDown = false; |
|
ev(e); |
|
}); |
|
break; |
|
case "mousedown": |
|
// let mouseDown = false; |
|
hand.mousedown(e => { |
|
// if (e.button === 0) { |
|
Widget._renderEngine.createElement(document).bind(`mouseup.${this.getName()}`, e => { |
|
// if (e.button === 0) { |
|
if ( |
|
DOM.isExist(this) && |
|
!hand.__isMouseInBounds__(e) && |
|
mouseDown === true && |
|
!selected |
|
) { |
|
// self.setSelected(!self.isSelected()); |
|
this._trigger(); |
|
} |
|
mouseDown = false; |
|
Widget._renderEngine.createElement(document).unbind(`mouseup.${this.getName()}`); |
|
// } |
|
}); |
|
if (mouseDown === true) { |
|
return; |
|
} |
|
if (this.isSelected()) { |
|
selected = true; |
|
} else { |
|
clk(e); |
|
} |
|
mouseDown = true; |
|
ev(e); |
|
// } |
|
}); |
|
hand.mouseup(e => { |
|
// if (e.button === 0) { |
|
if (DOM.isExist(this) && mouseDown === true && selected === true) { |
|
clk(e); |
|
} |
|
mouseDown = false; |
|
selected = false; |
|
Widget._renderEngine.createElement(document).unbind(`mouseup.${this.getName()}`); |
|
// } |
|
}); |
|
break; |
|
case "dblclick": |
|
hand.dblclick(clk); |
|
break; |
|
case "lclick": |
|
hand.mousedown(e => { |
|
Widget._renderEngine.createElement(document).bind(`mouseup.${this.getName()}`, () => { |
|
interval && clearInterval(interval); |
|
interval = null; |
|
mouseDown = false; |
|
Widget._renderEngine.createElement(document).unbind(`mouseup.${this.getName()}`); |
|
}); |
|
if (mouseDown === true) { |
|
return; |
|
} |
|
if (!this.isEnabled() || !this.isValid()) { |
|
return; |
|
} |
|
if (this.isOnce() && this.isSelected()) { |
|
return; |
|
} |
|
interval = setInterval(() => { |
|
clk(e); |
|
}, 180); |
|
mouseDown = true; |
|
ev(e); |
|
}); |
|
break; |
|
default: |
|
if (o.stopEvent || o.stopPropagation) { |
|
hand.mousedown(e => { |
|
ev(e); |
|
}); |
|
} |
|
hand.click(clk); |
|
// enter键等同于点击 |
|
o.attributes && |
|
o.attributes.zIndex >= 0 && |
|
hand.keyup(e => { |
|
if (e.keyCode === KeyCode.ENTER) { |
|
clk(e); |
|
} |
|
}); |
|
break; |
|
} |
|
}); |
|
|
|
// 之后的300ms点击无效 |
|
const onClick = o.debounce |
|
? debounce(this._doClick, EVENT_RESPONSE_TIME, { |
|
leading: true, |
|
trailing: false, |
|
}) |
|
: this._doClick; |
|
|
|
function ev(e) { |
|
if (o.stopEvent) { |
|
e.stopEvent(); |
|
} |
|
if (o.stopPropagation) { |
|
e.stopPropagation(); |
|
} |
|
} |
|
} |
|
|
|
_trigger(e) { |
|
const o = this.options; |
|
if (!this.isEnabled()) { |
|
return; |
|
} |
|
if (!this.isDisableSelected()) { |
|
this.isForceSelected() |
|
? this.setSelected(true) |
|
: this.isForceNotSelected() |
|
? this.setSelected(false) |
|
: this.setSelected(!this.isSelected()); |
|
} |
|
if (this.isValid()) { |
|
const v = this.getValue(); |
|
o.handler.call(this, v, this, e); |
|
this.fireEvent(Controller.EVENT_CHANGE, Events.CLICK, v, this, e); |
|
this.fireEvent(BasicButton.EVENT_CHANGE, v, this); |
|
if (o.action) { |
|
Actions.runAction(o.action, "click", o, this); |
|
} |
|
Actions.runGlobalAction("click", o, this); |
|
} |
|
} |
|
|
|
_doClick(e) { |
|
if (!this.isEnabled() || !this.isValid()) { |
|
return; |
|
} |
|
const isIntercepted = this.beforeClick(e); |
|
// 如果事件已经被消费掉了,就不再触发点击事件 |
|
if (isIntercepted) { |
|
return; |
|
} |
|
|
|
this._trigger(e); |
|
if (this.isEnabled() && this.isValid()) { |
|
this.doClick(e); |
|
} |
|
} |
|
|
|
/** |
|
* 子类可以得写这个方法,如果返回为 true,则可以阻止 handler 的触发 |
|
*/ |
|
beforeClick() {} |
|
|
|
doClick() {} |
|
|
|
handle() { |
|
return this; |
|
} |
|
|
|
hover() { |
|
this._hover = true; |
|
this.handle().element.addClass("hover"); |
|
if (this.options.shadow) { |
|
this.$mask && this.$mask.setVisible(true); |
|
} |
|
} |
|
|
|
dishover() { |
|
this._hover = false; |
|
this.handle().element.removeClass("hover"); |
|
if (this.options.shadow) { |
|
this.$mask && this.$mask.setVisible(false); |
|
} |
|
} |
|
|
|
setSelected(b) { |
|
const o = this.options; |
|
o.selected = b; |
|
if (b) { |
|
this.handle().element.addClass("active"); |
|
} else { |
|
this.handle().element.removeClass("active"); |
|
} |
|
if (o.shadow && !o.isShadowShowingOnSelected) { |
|
this.$mask && this.$mask.setVisible(false); |
|
} |
|
this.options.setSelected && this.options.setSelected.call(this, b); |
|
} |
|
|
|
isSelected() { |
|
return this.options.selected; |
|
} |
|
|
|
isOnce() { |
|
return this.options.once; |
|
} |
|
|
|
isForceSelected() { |
|
return this.options.forceSelected; |
|
} |
|
|
|
isForceNotSelected() { |
|
return this.options.forceNotSelected; |
|
} |
|
|
|
isDisableSelected() { |
|
return this.options.disableSelected; |
|
} |
|
|
|
setText(text) { |
|
this.options.text = text; |
|
this.options.setText && this.options.setText.call(this, text); |
|
} |
|
|
|
getText() { |
|
return this.options.text; |
|
} |
|
|
|
_setEnable(enable) { |
|
super._setEnable(...arguments); |
|
if (enable === true) { |
|
this.element.removeClass("base-disabled disabled"); |
|
} else if (enable === false) { |
|
this.element.addClass("base-disabled disabled"); |
|
} |
|
if (!enable) { |
|
if (this.options.shadow) { |
|
this.$mask && this.$mask.setVisible(false); |
|
} |
|
} |
|
} |
|
|
|
empty() { |
|
Widget._renderEngine.createElement(document).unbind(`mouseup.${this.getName()}`); |
|
super.empty(...arguments); |
|
} |
|
}
|
|
|