Browse Source

KERNEL-14076 refact: es6 脚本识别循环依赖。完成 base 处理。

es6
Treecat 1 year ago
parent
commit
630be6aea0
  1. 61
      es6.js
  2. 12
      src/base/0.base.js
  3. 91
      src/base/1.pane.js
  4. 119
      src/base/collection/collection.js
  5. 249
      src/base/combination/bubble.js
  6. 475
      src/base/combination/combo.js
  7. 166
      src/base/combination/expander.js
  8. 85
      src/base/combination/group.button.js
  9. 55
      src/base/combination/group.combo.js
  10. 67
      src/base/combination/group.virtual.js
  11. 2
      src/base/combination/index.js
  12. 184
      src/base/combination/loader.js
  13. 48
      src/base/combination/navigation.js
  14. 159
      src/base/combination/searcher.js
  15. 163
      src/base/combination/switcher.js
  16. 55
      src/base/combination/tab.js
  17. 9
      src/base/combination/tree.button.js
  18. 57
      src/base/context.js
  19. 48
      src/base/el.js
  20. 175
      src/base/foundation/message.js
  21. 164
      src/base/grid/grid.js
  22. 9
      src/base/index.js
  23. 457
      src/base/layer/layer.drawer.js
  24. 552
      src/base/layer/layer.popover.js
  25. 875
      src/base/layer/layer.popup.js
  26. 259
      src/base/layer/layer.searcher.js
  27. 221
      src/base/list/listview.js
  28. 331
      src/base/list/virtualgrouplist.js
  29. 71
      src/base/list/virtuallist.js
  30. 149
      src/base/pager/pager.js
  31. 39
      src/base/single/0.single.js
  32. 64
      src/base/single/1.text.js
  33. 52
      src/base/single/a/a.js
  34. 19
      src/base/single/bar/bar.loading.js
  35. 333
      src/base/single/button/button.basic.js
  36. 2
      src/base/single/button/button.node.js
  37. 9
      src/base/single/button/buttons/button.icon.js
  38. 10
      src/base/single/button/buttons/button.image.js
  39. 41
      src/base/single/button/buttons/button.js
  40. 5
      src/base/single/button/buttons/button.text.js
  41. 34
      src/base/single/button/index.js
  42. 74
      src/base/single/button/listitem/blankiconicontextitem.js
  43. 75
      src/base/single/button/listitem/blankicontexticonitem.js
  44. 61
      src/base/single/button/listitem/blankicontextitem.js
  45. 67
      src/base/single/button/listitem/icontexticonitem.js
  46. 54
      src/base/single/button/listitem/icontextitem.js
  47. 56
      src/base/single/button/listitem/texticonitem.js
  48. 5
      src/base/single/button/listitem/textitem.js
  49. 67
      src/base/single/button/node/icontexticonnode.js
  50. 55
      src/base/single/button/node/icontextnode.js
  51. 55
      src/base/single/button/node/texticonnode.js
  52. 10
      src/base/single/button/node/textnode.js
  53. 67
      src/base/single/editor/editor.js
  54. 35
      src/base/single/editor/editor.multifile.js
  55. 109
      src/base/single/editor/editor.textarea.js
  56. 6
      src/base/single/editor/index.js
  57. 29
      src/base/single/html/html.js
  58. 7
      src/base/single/icon/icon.js
  59. 23
      src/base/single/iframe/iframe.js
  60. 20
      src/base/single/img/img.js
  61. 9
      src/base/single/input/checkbox/checkbox.image.js
  62. 29
      src/base/single/input/checkbox/checkbox.js
  63. 369
      src/base/single/input/file.js
  64. 12
      src/base/single/input/index.js
  65. 71
      src/base/single/input/input.js
  66. 9
      src/base/single/input/radio/radio.image.js
  67. 31
      src/base/single/input/radio/radio.js
  68. 16
      src/base/single/instruction/instruction.js
  69. 179
      src/base/single/label/abstract.label.js
  70. 10
      src/base/single/label/html.label.js
  71. 14
      src/base/single/label/icon.label.js
  72. 8
      src/base/single/label/index.js
  73. 7
      src/base/single/label/label.js
  74. 10
      src/base/single/link/link.js
  75. 19
      src/base/single/text.pure.js
  76. 8
      src/base/single/tip/0.tip.js
  77. 221
      src/base/single/tip/tip.toast.js
  78. 146
      src/base/single/tip/tip.tooltip.js
  79. 13
      src/base/single/trigger/trigger.js
  80. 72
      src/base/tree/customtree.js
  81. 3
      src/case/combo/bubblecombo/popup.bubble.js

61
es6.js

@ -8,6 +8,9 @@ const _ = require("lodash");
// const XTYPE_ONLY = false;
// const THIS_REPLACE = false;
const ConflictImport = [];
const CircularDependency = [];
function objHaveFunction(obj) {
return Object.keys(obj).some(key => {
const value = obj[key];
@ -44,6 +47,7 @@ async function saveAndFixCode(path, code) {
const prettierCode = prettier.format(_code, {
tabWidth: 4,
parser: 'babel',
printWidth: 120,
});
fs.writeFileSync(path, prettierCode);
@ -138,7 +142,13 @@ async function handleFile(srcName) {
const result = /BI\.(.*?)\s=\sBI\.inherit\(/.exec(sourceCode);
if (!result) {
console.log(`已经es6过,替换 xtype => ${srcName}`);
// console.log(`已经es6过,替换 xtype => ${srcName}`);
if (!/export class/.test(sourceCode)) {
console.log("忽略文件", srcName);
return;
}
// 处理 xtype
const noXtypeCode = sourceCode.replace(/type:\s?"bi\.(.*?)"/g, v => {
const matchedSentence = v.replace(/type:\s?/, "");
@ -181,12 +191,37 @@ async function handleFile(srcName) {
});
const tmpG = {};
_.forEach(G, (depts, module)=> {
const flag = _.some(crossPackages, crosspackage => module.indexOf(crosspackage) >= 0 && !module.startsWith("@"))
_.forEach(G, (depts, module) => {
const flag = _.some(crossPackages, crosspackage => module.indexOf(crosspackage) >= 0 && !module.startsWith("@"));
if (!flag) {
tmpG[module] = depts;
}
});
// 较验手工 import 错误
const map = {};
let conflict = false;
let circle = false;
_.forEach(tmpG, (imports, fromStr) => {
if (srcName.indexOf("base") >= 0) {
if (fromStr === "@/case" || fromStr === "@/base") {
circle = true;
}
}
_.forEach(imports, (bools, _import) => {
if (map[_import] && map[_import] !== fromStr) {
conflict = true;
}
map[_import] = fromStr;
});
});
conflict && ConflictImport.push(srcName);
circle && CircularDependency.push(srcName);
G = tmpG;
const noImportCode = noXtypeCode.replace(/import {([\s\S]*?)} from "(.*?)";/g, "");
@ -314,7 +349,7 @@ async function handleFile(srcName) {
// 换 super._defaultConfig
f = f.replace(
/super\._defaultConfig\.apply\(this,\sarguments\)/g,
"super._defaultConfig(...arguments)"
"super._defaultConfig(...arguments)",
);
// 换 super.xxx.apply
f = f.replace(/super\.(.*?)\.apply\(this,\sarguments\)/g, a => {
@ -427,19 +462,27 @@ async function traverse(srcName) {
const srcName = process.argv[2];
initDepts().then(() => {
initDepts().then(async () => {
const content = fs.readFileSync("src/core/2.base.js").toString();
let result = content.match(/export function (.*?)\(/g);
target.push(
...result.map(el =>
el.replace("export function ", "").replace("(", "")
)
el.replace("export function ", "").replace("(", ""),
),
);
result = content.match(/export const (.*?) =/g);
target.push(
...result.map(el => el.replace("export const ", "").replace(" =", ""))
...result.map(el => el.replace("export const ", "").replace(" =", "")),
);
traverse(srcName);
await traverse(srcName);
// 对数据处理
ConflictImport.forEach(el => {
console.log(`导入冲突 ${el}`);
});
CircularDependency.forEach(el => {
console.log(`出现循环依赖 ${el}`);
});
});

12
src/base/0.base.js

@ -20,14 +20,4 @@ const Drawers = new DrawerController();
const Broadcasts = new BroadcastController();
const StyleLoaders = new StyleLoaderManager();
export {
Resizers,
Layers,
Maskers,
Bubbles,
Tooltips,
Popovers,
Drawers,
Broadcasts,
StyleLoaders
};
export { Resizers, Layers, Maskers, Bubbles, Tooltips, Popovers, Drawers, Broadcasts, StyleLoaders };

91
src/base/1.pane.js

@ -1,3 +1,19 @@
import { Label, Text } from "./single";
import {
CenterAdaptLayout,
HorizontalAdaptLayout,
VerticalLayout,
Widget,
shortcut,
isNotEmptyString,
extend,
isNull,
isEmpty,
createWidget,
Providers
} from "@/core";
import { Layers } from "@/base";
/**
* 当没有元素时有提示信息的view
*
@ -6,8 +22,6 @@
* @extends BI.Widget
* @abstract
*/
import { Widget, shortcut, isNotEmptyString, extend, isNull, isEmpty, createWidget, Providers } from "../core";
import { Layers } from "./0.base";
@shortcut()
export class Pane extends Widget {
@ -31,32 +45,36 @@ export class Pane extends Widget {
createWidget({
type: "bi.absolute_center_adapt",
element: this,
items: [{
type: "bi.label",
ref: _ref => {
this._tipText = _ref;
},
cls: "bi-tips",
text: this.options.tipText,
height: 25,
}],
items: [
{
type: Label.xtype,
ref: _ref => {
this._tipText = _ref;
},
cls: "bi-tips",
text: this.options.tipText,
height: 25,
}
],
});
}
}
loading() {
const o = this.options;
const loadingAnimation = createWidget(Providers.getProvider("bi.provider.system").getLoading({
loadingSize: o.loadingSize,
context: this,
}));
const loadingAnimation = createWidget(
Providers.getProvider("bi.provider.system").getLoading({
loadingSize: o.loadingSize,
context: this,
})
);
// pane在同步方式下由items决定tipText的显示与否
// loading的异步情况下由loaded后对面板的populate的时机决定
this.setTipVisible(false);
if (o.overlap === true) {
if (!Layers.has(`${this.getName()}-loading`)) {
createWidget({
type: "bi.center_adapt",
type: CenterAdaptLayout.xtype,
cls: "loading-container",
items: this._getLoadingTipItems(loadingAnimation),
element: Layers.make(`${this.getName()}-loading`, this),
@ -66,7 +84,7 @@ export class Pane extends Widget {
} else if (isNull(this._loading)) {
loadingAnimation.element.css("zIndex", 1);
createWidget({
type: "bi.center_adapt",
type: CenterAdaptLayout.xtype,
element: this,
cls: "loading-container",
items: this._getLoadingTipItems(loadingAnimation),
@ -82,23 +100,28 @@ export class Pane extends Widget {
_getLoadingTipItems(loadingTip) {
const o = this.options;
const loadingTipItems = [{
type: "bi.horizontal_adapt",
items: [loadingTip],
}];
isNotEmptyString(o.loadingText) && loadingTipItems.push({
type: "bi.text",
text: o.loadingText,
tgap: this._getSize(10),
});
const loadingTipItems = [
{
type: HorizontalAdaptLayout.xtype,
items: [loadingTip],
}
];
isNotEmptyString(o.loadingText) &&
loadingTipItems.push({
type: Text.xtype,
text: o.loadingText,
tgap: this._getSize(10),
});
return [{
type: "bi.vertical",
ref: _ref => {
this._loading = _ref;
},
items: loadingTipItems,
}];
return [
{
type: VerticalLayout.xtype,
ref: _ref => {
this._loading = _ref;
},
items: loadingTipItems,
}
];
}
loaded() {

119
src/base/collection/collection.js

@ -1,3 +1,25 @@
import {
VerticalLayout,
AbsoluteLayout,
Widget,
shortcut,
extend,
emptyFn,
debounce,
_lazyCreateWidget,
isFunction,
SectionManager,
isNull,
each,
clamp,
toArray,
invert,
min,
max,
nextTick
} from "@/core";
import { Label } from "../single";
/**
* CollectionView
*
@ -5,7 +27,7 @@
* @class BI.CollectionView
* @extends BI.Widget
*/
import { Widget, shortcut, extend, emptyFn, debounce, _lazyCreateWidget, isFunction, SectionManager, isNull, each, clamp, toArray, invert, min, max, nextTick } from "../../core";
@shortcut()
export class CollectionView extends Widget {
_defaultConfig() {
@ -19,7 +41,7 @@ export class CollectionView extends Widget {
overflowX: true,
overflowY: true,
el: {
type: "bi.vertical",
type: VerticalLayout.xtype,
},
cellSizeAndPositionGetter: emptyFn,
horizontalOverscanSize: 0,
@ -45,7 +67,7 @@ export class CollectionView extends Widget {
this._scrollLock = false;
}, 1000 / 60);
this.container = _lazyCreateWidget({
type: "bi.absolute",
type: AbsoluteLayout.xtype,
});
this.element.scroll(() => {
if (this._scrollLock === true) {
@ -61,7 +83,8 @@ export class CollectionView extends Widget {
});
// 兼容一下
let scrollable = o.scrollable;
const scrollx = o.scrollx, scrolly = o.scrolly;
const scrollx = o.scrollx,
scrolly = o.scrolly;
if (overflowX === false) {
if (overflowY === false) {
scrollable = false;
@ -74,16 +97,18 @@ export class CollectionView extends Widget {
}
}
_lazyCreateWidget(el, {
type: "bi.vertical",
type: VerticalLayout.xtype,
element: this,
scrollable,
scrolly,
scrollx,
items: [this.container],
});
o.items = isFunction(o.items) ? this.__watch(o.items, (context, newValue) => {
this.populate(newValue);
}) : o.items;
o.items = isFunction(o.items)
? this.__watch(o.items, (context, newValue) => {
this.populate(newValue);
})
: o.items;
if (o.items.length > 0) {
this._calculateSizeAndPositionData();
this._populate();
@ -109,10 +134,16 @@ export class CollectionView extends Widget {
for (let index = 0, len = items.length; index < len; index++) {
const cellMetadatum = cellSizeAndPositionGetter(index);
if (isNull(cellMetadatum.height) || isNaN(cellMetadatum.height) ||
isNull(cellMetadatum.width) || isNaN(cellMetadatum.width) ||
isNull(cellMetadatum.x) || isNaN(cellMetadatum.x) ||
isNull(cellMetadatum.y) || isNaN(cellMetadatum.y)) {
if (
isNull(cellMetadatum.height) ||
isNaN(cellMetadatum.height) ||
isNull(cellMetadatum.width) ||
isNaN(cellMetadatum.width) ||
isNull(cellMetadatum.x) ||
isNaN(cellMetadatum.x) ||
isNull(cellMetadatum.y) ||
isNaN(cellMetadatum.y)
) {
throw Error();
}
@ -157,13 +188,21 @@ export class CollectionView extends Widget {
const bottom = Math.min(this._height, scrollTop + height + verticalOverscanSize);
if (right > 0 && bottom > 0) {
// 如果滚动的区间并没有超出渲染的范围
if (top >= this.renderRange.minY && bottom <= this.renderRange.maxY && left >= this.renderRange.minX && right <= this.renderRange.maxX) {
if (
top >= this.renderRange.minY &&
bottom <= this.renderRange.maxY &&
left >= this.renderRange.minX &&
right <= this.renderRange.maxX
) {
return;
}
const childrenToDisplay = this._cellRenderers(bottom - top, right - left, left, top);
const renderedCells = [], renderedKeys = {}, renderedWidgets = {};
const renderedCells = [],
renderedKeys = {},
renderedWidgets = {};
// 存储所有的left和top
let lefts = {}, tops = {};
let lefts = {},
tops = {};
for (let i = 0, len = childrenToDisplay.length; i < len; i++) {
const datum = childrenToDisplay[i];
lefts[datum.x] = datum.x;
@ -176,7 +215,10 @@ export class CollectionView extends Widget {
const leftMap = invert(lefts);
const topMap = invert(tops);
// 存储上下左右四个边界
const leftBorder = {}, rightBorder = {}, topBorder = {}, bottomBorder = {};
const leftBorder = {},
rightBorder = {},
topBorder = {},
bottomBorder = {};
function assertMinBorder(border, offset) {
if (isNull(border[offset])) {
border[offset] = Number.MAX_VALUE;
@ -197,18 +239,26 @@ export class CollectionView extends Widget {
// 这里只使用px
this.renderedCells[index].el.element.css("left", `${datum.x}px`);
this.renderedCells[index].el.element.css("top", `${datum.y}px`);
renderedCells.push(child = this.renderedCells[index]);
renderedCells.push((child = this.renderedCells[index]));
} else {
const item = itemFormatter(items[datum.index], datum.index);
child = _lazyCreateWidget(extend({
type: "bi.label",
width: datum.width,
height: datum.height,
}, item, {
cls: `${item.cls || ""} collection-cell${datum.y === 0 ? " first-row" : ""}${datum.x === 0 ? " first-col" : ""}`,
_left: datum.x,
_top: datum.y,
}));
child = _lazyCreateWidget(
extend(
{
type: Label.xtype,
width: datum.width,
height: datum.height,
},
item,
{
cls: `${item.cls || ""} collection-cell${datum.y === 0 ? " first-row" : ""}${
datum.x === 0 ? " first-col" : ""
}`,
_left: datum.x,
_top: datum.y,
}
)
);
renderedCells.push({
el: child,
left: `${datum.x}px`,
@ -242,7 +292,9 @@ export class CollectionView extends Widget {
renderedWidgets[i] = child;
}
// 已存在的, 需要添加的和需要删除的
const existSet = {}, addSet = {}, deleteArray = [];
const existSet = {},
addSet = {},
deleteArray = [];
each(renderedKeys, (i, key) => {
if (this.renderedKeys[i]) {
existSet[i] = key;
@ -289,7 +341,8 @@ export class CollectionView extends Widget {
const o = this.options;
const { overflowX } = this.options;
// 兼容一下
const scrollable = o.scrollable, scrollx = o.scrollx;
const scrollable = o.scrollable,
scrollx = o.scrollx;
if (overflowX === false) {
return false;
}
@ -299,7 +352,7 @@ export class CollectionView extends Widget {
if (scrollable === true || scrollable === "xy" || scrollable === "x") {
return true;
}
return false;
}
@ -307,7 +360,8 @@ export class CollectionView extends Widget {
const o = this.options;
const { overflowX } = this.options;
// 兼容一下
const scrollable = o.scrollable, scrolly = o.scrolly;
const scrollable = o.scrollable,
scrolly = o.scrolly;
if (overflowX === false) {
return false;
}
@ -317,7 +371,7 @@ export class CollectionView extends Widget {
if (scrollable === true || scrollable === "xy" || scrollable === "y") {
return true;
}
return false;
}
@ -344,8 +398,7 @@ export class CollectionView extends Widget {
try {
this.element.scrollTop(scrollTop);
this.element.scrollLeft(scrollLeft);
} catch (e) {
}
} catch (e) {}
this._calculateChildrenToRender();
}
setScrollLeft(scrollLeft) {

249
src/base/combination/bubble.js

@ -1,8 +1,26 @@
import { BubblePopupView } from "@/case/combo/bubblecombo/popup.bubble";
import {
VerticalLayout,
shortcut,
Widget,
Controller,
extend,
nextTick,
createWidget,
each,
defer,
debounce,
delay,
isNull,
isFunction,
contains,
bind
} from "@/core";
/**
* @class BI.Bubble
* @extends BI.Widget
*/
import { shortcut, Widget, Controller, extend, nextTick, createWidget, each, defer, debounce, delay, isNull, isFunction, contains, bind } from "../../core";
@shortcut()
export class Bubble extends Widget {
@ -23,7 +41,7 @@ export class Bubble extends Widget {
const conf = super._defaultConfig(...arguments);
return extend(conf, {
baseCls: (conf.baseCls || "") + " bi-popper",
baseCls: `${conf.baseCls || ""} bi-popper`,
attributes: {
tabIndex: -1,
},
@ -85,26 +103,32 @@ export class Bubble extends Widget {
}
});
this.element.on("mouseenter." + this.getName(), (e) => {
this.element.on(`mouseenter.${this.getName()}`, (e) => {
if (this.isEnabled() && this.isValid() && this.combo.isEnabled() && this.combo.isValid()) {
this.element.addClass(hoverClass);
}
});
this.element.on("mouseleave." + this.getName(), (e) => {
this.element.on(`mouseleave.${this.getName()}`, (e) => {
if (this.isEnabled() && this.isValid() && this.combo.isEnabled() && this.combo.isValid()) {
this.element.removeClass(hoverClass);
}
});
createWidget(extend({
element: this,
scrolly: false,
}, BI.LogicFactory.createLogic("vertical", extend(logic, {
items: [
{ el: this.combo }
],
}))));
isDefaultInit && (this._assertPopupView());
createWidget(
extend(
{
element: this,
scrolly: false,
},
BI.LogicFactory.createLogic(
"vertical",
extend(logic, {
items: [{ el: this.combo }],
})
)
)
);
isDefaultInit && this._assertPopupView();
}
_toggle(e) {
@ -129,39 +153,46 @@ export class Bubble extends Widget {
if (stopPropagation) {
e.stopPropagation();
}
}
};
let enterPopup = false;
const hide = (e) => {
if (this.isEnabled() && this.isValid() && this.combo.isEnabled() && this.combo.isValid() && toggle === true) {
if (
this.isEnabled() &&
this.isValid() &&
this.combo.isEnabled() &&
this.combo.isValid() &&
toggle === true
) {
this._hideView(e);
this.fireEvent(Controller.EVENT_CHANGE, BI.Events.COLLAPSE, "", this.combo);
this.fireEvent(Bubble.EVENT_COLLAPSE);
}
this.popupView && this.popupView.element.off("mouseenter." + this.getName()).off("mouseleave." + this.getName());
this.popupView &&
this.popupView.element.off(`mouseenter.${this.getName()}`).off(`mouseleave.${this.getName()}`);
enterPopup = false;
}
};
each(evs, (i, ev) => {
let debounced;
switch (ev) {
case "hover":
this.element.on("mouseenter." + this.getName(), (e) => {
this.element.on(`mouseenter.${this.getName()}`, (e) => {
if (this.isEnabled() && this.isValid() && this.combo.isEnabled() && this.combo.isValid()) {
this._popupView(e);
this.fireEvent(Controller.EVENT_CHANGE, BI.Events.EXPAND, "", this.combo);
this.fireEvent(Bubble.EVENT_EXPAND);
}
});
this.element.on("mouseleave." + this.getName(), (e) => {
this.element.on(`mouseleave.${this.getName()}`, (e) => {
if (this.popupView) {
this.popupView.element.on("mouseenter." + this.getName(), (e) => {
this.popupView.element.on(`mouseenter.${this.getName()}`, (e) => {
enterPopup = true;
this.popupView.element.on("mouseleave." + this.getName(), (e) => {
this.popupView.element.on(`mouseleave.${this.getName()}`, (e) => {
hide(e);
});
this.popupView.element.off("mouseenter." + this.getName());
this.popupView.element.off(`mouseenter.${this.getName()}`);
});
defer(() => {
if (!enterPopup) {
@ -172,61 +203,79 @@ export class Bubble extends Widget {
});
break;
case "click":
debounced = debounce((e) => {
if (this.combo.element.__isMouseInBounds__(e)) {
if (this.isEnabled() && this.isValid() && this.combo.isEnabled() && this.combo.isValid()) {
// if (!o.toggle && this.isViewVisible()) {
// return;
// }
toggle ? this._toggle(e) : this._popupView(e);
if (this.isViewVisible()) {
this.fireEvent(Controller.EVENT_CHANGE, BI.Events.EXPAND, "", this.combo);
this.fireEvent(Bubble.EVENT_EXPAND);
} else {
this.fireEvent(Controller.EVENT_CHANGE, BI.Events.COLLAPSE, "", this.combo);
this.fireEvent(Bubble.EVENT_COLLAPSE);
debounced = debounce(
(e) => {
if (this.combo.element.__isMouseInBounds__(e)) {
if (
this.isEnabled() &&
this.isValid() &&
this.combo.isEnabled() &&
this.combo.isValid()
) {
// if (!o.toggle && this.isViewVisible()) {
// return;
// }
toggle ? this._toggle(e) : this._popupView(e);
if (this.isViewVisible()) {
this.fireEvent(Controller.EVENT_CHANGE, BI.Events.EXPAND, "", this.combo);
this.fireEvent(Bubble.EVENT_EXPAND);
} else {
this.fireEvent(Controller.EVENT_CHANGE, BI.Events.COLLAPSE, "", this.combo);
this.fireEvent(Bubble.EVENT_COLLAPSE);
}
}
}
},
BI.EVENT_RESPONSE_TIME,
{
leading: true,
trailing: false,
}
}, BI.EVENT_RESPONSE_TIME, {
"leading": true,
"trailing": false,
});
this.element.off(ev + "." + this.getName()).on(ev + "." + this.getName(), (e) => {
);
this.element.off(`${ev}.${this.getName()}`).on(`${ev}.${this.getName()}`, (e) => {
debounced(e);
st(e);
});
break;
case "click-hover":
debounced = debounce((e) => {
if (this.combo.element.__isMouseInBounds__(e)) {
if (this.isEnabled() && this.isValid() && this.combo.isEnabled() && this.combo.isValid()) {
// if (this.isViewVisible()) {
// return;
// }
this._popupView(e);
if (this.isViewVisible()) {
this.fireEvent(Controller.EVENT_CHANGE, BI.Events.EXPAND, "", this.combo);
this.fireEvent(Bubble.EVENT_EXPAND);
debounced = debounce(
(e) => {
if (this.combo.element.__isMouseInBounds__(e)) {
if (
this.isEnabled() &&
this.isValid() &&
this.combo.isEnabled() &&
this.combo.isValid()
) {
// if (this.isViewVisible()) {
// return;
// }
this._popupView(e);
if (this.isViewVisible()) {
this.fireEvent(Controller.EVENT_CHANGE, BI.Events.EXPAND, "", this.combo);
this.fireEvent(Bubble.EVENT_EXPAND);
}
}
}
},
BI.EVENT_RESPONSE_TIME,
{
leading: true,
trailing: false,
}
}, BI.EVENT_RESPONSE_TIME, {
"leading": true,
"trailing": false,
});
this.element.off("click." + this.getName()).on("click." + this.getName(), (e) => {
);
this.element.off(`click.${this.getName()}`).on(`click.${this.getName()}`, (e) => {
debounced(e);
st(e);
});
this.element.on("mouseleave." + this.getName(), (e) => {
this.element.on(`mouseleave.${this.getName()}`, (e) => {
if (this.popupView) {
this.popupView.element.on("mouseenter." + this.getName(), (e) => {
this.popupView.element.on(`mouseenter.${this.getName()}`, (e) => {
enterPopup = true;
this.popupView.element.on("mouseleave." + this.getName(), (e) => {
this.popupView.element.on(`mouseleave.${this.getName()}`, (e) => {
hide(e);
});
this.popupView.element.off("mouseenter." + this.getName());
this.popupView.element.off(`mouseenter.${this.getName()}`);
});
delay(() => {
if (!enterPopup) {
@ -237,7 +286,7 @@ export class Bubble extends Widget {
});
break;
case "hover-click":
this.element.on("mouseenter." + this.getName(), (e) => {
this.element.on(`mouseenter.${this.getName()}`, (e) => {
if (this.isEnabled() && this.isValid() && this.combo.isEnabled() && this.combo.isValid()) {
this._popupView(e);
this.fireEvent(Controller.EVENT_CHANGE, BI.Events.EXPAND, "", this.combo);
@ -260,11 +309,15 @@ export class Bubble extends Widget {
_assertPopupView() {
const { showArrow, value } = this.options;
if (isNull(this.popupView)) {
this.popupView = createWidget(isFunction(this.options.popup) ? this.options.popup() : this.options.popup, {
type: "bi.bubble_popup_view",
showArrow,
value,
}, this);
this.popupView = createWidget(
isFunction(this.options.popup) ? this.options.popup() : this.options.popup,
{
type: BubblePopupView.xtype,
showArrow,
value,
},
this
);
this.popupView.on(Controller.EVENT_CHANGE, (type, value, obj, ...args) => {
if (type === BI.Events.CLICK) {
this.combo.setValue(this.getValue());
@ -283,12 +336,10 @@ export class Bubble extends Widget {
this._assertPopupView();
if (!this._rendered) {
createWidget({
type: "bi.vertical",
type: VerticalLayout.xtype,
scrolly: false,
element: isFunction(this.options.container) ? this.options.container() : (this.options.container || this),
items: [
{ el: this.popupView }
],
element: isFunction(this.options.container) ? this.options.container() : this.options.container || this,
items: [{ el: this.popupView }],
});
this._rendered = true;
}
@ -299,9 +350,14 @@ export class Bubble extends Widget {
// return;
// }
// BI-10290 公式combo双击公式内容会收起
if (e && ((skipTriggerChecker !== true && this.element.find(e.target).length > 0)
|| (this.popupView && this.popupView.element.find(e.target).length > 0)
|| e.target.className === "CodeMirror-cursor" || Widget._renderEngine.createElement(e.target).closest(".CodeMirror-hints").length > 0)) {// BI-9887 CodeMirror的公式弹框需要特殊处理下
if (
e &&
((skipTriggerChecker !== true && this.element.find(e.target).length > 0) ||
(this.popupView && this.popupView.element.find(e.target).length > 0) ||
e.target.className === "CodeMirror-cursor" ||
Widget._renderEngine.createElement(e.target).closest(".CodeMirror-hints").length > 0)
) {
// BI-9887 CodeMirror的公式弹框需要特殊处理下
const directions = this.options.direction.split(",");
if (contains(directions, "innerLeft") || contains(directions, "innerRight")) {
// popup可以出现在trigger内部的combo,滚动时不需要消失,而是调整位置
@ -344,13 +400,17 @@ export class Bubble extends Widget {
this.element.removeClass(this.options.comboClass);
Widget._renderEngine.createElement(document).unbind("mousedown." + this.getName()).unbind("mousewheel." + this.getName());
BI.EVENT_BLUR && hideWhenBlur && Widget._renderEngine.createElement(window).unbind("blur." + this.getName());
Widget._renderEngine
.createElement(document)
.unbind(`mousedown.${this.getName()}`)
.unbind(`mousewheel.${this.getName()}`);
BI.EVENT_BLUR && hideWhenBlur && Widget._renderEngine.createElement(window).unbind(`blur.${this.getName()}`);
this.fireEvent(Bubble.EVENT_AFTER_HIDEVIEW);
}
_popupView(e) {
const { adjustXOffset, showArrow, adjustYOffset, adjustLength, placement, hideWhenClickOutside, hideWhenBlur } = this.options;
const { adjustXOffset, showArrow, adjustYOffset, adjustLength, placement, hideWhenClickOutside, hideWhenBlur } =
this.options;
this._assertPopupViewRender();
this.fireEvent(Bubble.EVENT_BEFORE_POPUPVIEW);
// popupVisible是为了获取其宽高, 放到可视范围之外以防止在IE下闪一下
@ -365,11 +425,9 @@ export class Bubble extends Widget {
{
name: "offset",
options: {
offset: () => {
return [adjustXOffset, (showArrow ? 12 : 0) + (adjustYOffset + adjustLength)];
},
offset: () => [adjustXOffset, (showArrow ? 12 : 0) + (adjustYOffset + adjustLength)],
},
}
},
];
if (this.options.showArrow) {
modifiers.push({
@ -389,11 +447,14 @@ export class Bubble extends Widget {
// this.adjustHeight(e);
this.element.addClass(this.options.comboClass);
hideWhenClickOutside && Widget._renderEngine.createElement(document).unbind("mousedown." + this.getName());
BI.EVENT_BLUR && hideWhenBlur && Widget._renderEngine.createElement(window).unbind("blur." + this.getName());
hideWhenClickOutside && Widget._renderEngine.createElement(document).bind("mousedown." + this.getName(), bind(this._hideIf, this));
BI.EVENT_BLUR && hideWhenBlur && Widget._renderEngine.createElement(window).bind("blur." + this.getName(), bind(this._hideIf, this));
hideWhenClickOutside && Widget._renderEngine.createElement(document).unbind(`mousedown.${this.getName()}`);
BI.EVENT_BLUR && hideWhenBlur && Widget._renderEngine.createElement(window).unbind(`blur.${this.getName()}`);
hideWhenClickOutside &&
Widget._renderEngine.createElement(document).bind(`mousedown.${this.getName()}`, bind(this._hideIf, this));
BI.EVENT_BLUR &&
hideWhenBlur &&
Widget._renderEngine.createElement(window).bind(`blur.${this.getName()}`, bind(this._hideIf, this));
this.fireEvent(Bubble.EVENT_AFTER_POPUPVIEW);
}
@ -425,9 +486,7 @@ export class Bubble extends Widget {
}
}
adjustHeight() {
}
adjustHeight() {}
resetListHeight(h) {
this._assertPopupView();
@ -501,13 +560,13 @@ export class Bubble extends Widget {
}
destroyed() {
Widget._renderEngine.createElement(document)
.unbind("click." + this.getName())
.unbind("mousedown." + this.getName())
.unbind("mouseenter." + this.getName())
.unbind("mouseleave." + this.getName());
Widget._renderEngine.createElement(window)
.unbind("blur." + this.getName());
Widget._renderEngine
.createElement(document)
.unbind(`click.${this.getName()}`)
.unbind(`mousedown.${this.getName()}`)
.unbind(`mouseenter.${this.getName()}`)
.unbind(`mouseleave.${this.getName()}`);
Widget._renderEngine.createElement(window).unbind(`blur.${this.getName()}`);
this.popper && this.popper.destroy();
this.popper = null;
this.popupView && this.popupView._destroy();

475
src/base/combination/combo.js

@ -1,12 +1,25 @@
import { PopupView } from "../layer";
import { Bubble } from "./bubble";
import {
shortcut,
Widget,
Controller,
extend,
createWidget,
nextTick,
bind,
isNotNull,
isNull,
isFunction,
each
} from "@/core";
import { Resizers } from "@/base/0.base";
/**
* @class BI.Combo
* @extends BI.Widget
*/
import { shortcut, Widget, Controller, extend, createWidget, nextTick, bind, isNotNull, isNull, isFunction, each } from "../../core";
import { Bubble } from "./bubble";
import { Resizers } from "../0.base";
let needHideWhenAnotherComboOpen = {};
let currentOpenedCombos = {};
@ -29,7 +42,7 @@ export class Combo extends Bubble {
const conf = super._defaultConfig(...arguments);
return extend(conf, {
baseCls: (conf.baseCls || "") + " bi-combo" + (BI.isIE() ? " hack" : ""),
baseCls: `${conf.baseCls || ""} bi-combo${BI.isIE() ? " hack" : ""}`,
attributes: {
tabIndex: -1,
},
@ -96,42 +109,55 @@ export class Combo extends Bubble {
}
});
this.element.on("mouseenter." + this.getName(), (e) => {
this.element.on(`mouseenter.${this.getName()}`, e => {
if (this.isEnabled() && this.isValid() && this.combo.isEnabled() && this.combo.isValid()) {
this.element.addClass(hoverClass);
}
});
this.element.on("mouseleave." + this.getName(), (e) => {
this.element.on(`mouseleave.${this.getName()}`, e => {
if (this.isEnabled() && this.isValid() && this.combo.isEnabled() && this.combo.isValid()) {
this.element.removeClass(hoverClass);
}
});
createWidget(extend({
element: this,
scrolly: false,
}, BI.LogicFactory.createLogic("vertical", extend(logic, {
items: [
{ el: this.combo }
],
}))));
isDefaultInit && (this._assertPopupView());
Resizers.add(this.getName(), bind((e) => {
// 如果resize对象是combo的子元素,则不应该收起,或交由hideChecker去处理
if (this.isViewVisible()) {
isNotNull(e) ? this._hideIf(e) : this._hideView();
}
}, this));
createWidget(
extend(
{
element: this,
scrolly: false,
},
BI.LogicFactory.createLogic(
"vertical",
extend(logic, {
items: [{ el: this.combo }],
})
)
)
);
isDefaultInit && this._assertPopupView();
Resizers.add(
this.getName(),
bind(e => {
// 如果resize对象是combo的子元素,则不应该收起,或交由hideChecker去处理
if (this.isViewVisible()) {
isNotNull(e) ? this._hideIf(e) : this._hideView();
}
}, this)
);
}
_assertPopupView() {
const { showArrow, value, hideWhenClickOutside, hideWhenBlur } = this.options;
if (isNull(this.popupView)) {
this.popupView = createWidget(isFunction(this.options.popup) ? this.options.popup() : this.options.popup, {
type: "bi.popup_view",
showArrow,
value,
}, this);
this.popupView = createWidget(
isFunction(this.options.popup) ? this.options.popup() : this.options.popup,
{
type: PopupView.xtype,
showArrow,
value,
},
this
);
this.popupView.on(Controller.EVENT_CHANGE, (type, value, obj, ...args) => {
if (type === BI.Events.CLICK) {
this.combo.setValue(this.getValue());
@ -167,8 +193,12 @@ export class Combo extends Bubble {
delete needHideWhenAnotherComboOpen[this.getName()];
delete currentOpenedCombos[this.getName()];
hideWhenClickOutside && Widget._renderEngine.createElement(document).unbind("mousedown." + this.getName()).unbind("mousewheel." + this.getName());
BI.EVENT_BLUR && hideWhenBlur && Widget._renderEngine.createElement(window).unbind("blur." + this.getName());
hideWhenClickOutside &&
Widget._renderEngine
.createElement(document)
.unbind(`mousedown.${this.getName()}`)
.unbind(`mousewheel.${this.getName()}`);
BI.EVENT_BLUR && hideWhenBlur && Widget._renderEngine.createElement(window).unbind(`blur.${this.getName()}`);
this.fireEvent(Combo.EVENT_AFTER_HIDEVIEW, e);
}
@ -192,119 +222,272 @@ export class Combo extends Bubble {
this.adjustHeight(e);
this.element.addClass(this.options.comboClass);
hideWhenClickOutside && Widget._renderEngine.createElement(document).unbind("mousedown." + this.getName()).unbind("mousewheel." + this.getName());
hideWhenClickOutside && Widget._renderEngine.createElement(document).unbind("mousewheel." + this.getName());
BI.EVENT_BLUR && hideWhenBlur && Widget._renderEngine.createElement(window).unbind("blur." + this.getName());
hideWhenClickOutside &&
Widget._renderEngine
.createElement(document)
.unbind(`mousedown.${this.getName()}`)
.unbind(`mousewheel.${this.getName()}`);
hideWhenClickOutside && Widget._renderEngine.createElement(document).unbind(`mousewheel.${this.getName()}`);
BI.EVENT_BLUR && hideWhenBlur && Widget._renderEngine.createElement(window).unbind(`blur.${this.getName()}`);
hideWhenClickOutside && Widget._renderEngine.createElement(document).bind("mousewheel." + this.getName(), bind(this._hideIf, this));
hideWhenClickOutside && Widget._renderEngine.createElement(document).bind("mousedown." + this.getName(), bind(this._hideIf, this)).bind("mousewheel." + this.getName(), bind(this._hideIf, this));
BI.EVENT_BLUR && hideWhenBlur && Widget._renderEngine.createElement(window).bind("blur." + this.getName(), bind(this._hideIf, this));
hideWhenClickOutside &&
Widget._renderEngine.createElement(document).bind(`mousewheel.${this.getName()}`, bind(this._hideIf, this));
hideWhenClickOutside &&
Widget._renderEngine
.createElement(document)
.bind(`mousedown.${this.getName()}`, bind(this._hideIf, this))
.bind(`mousewheel.${this.getName()}`, bind(this._hideIf, this));
BI.EVENT_BLUR &&
hideWhenBlur &&
Widget._renderEngine.createElement(window).bind(`blur.${this.getName()}`, bind(this._hideIf, this));
this.fireEvent(Combo.EVENT_AFTER_POPUPVIEW);
}
adjustHeight(e) {
const { belowMouse, supportCSSTransform, container, direction, adjustXOffset, adjustYOffset, adjustLength, showArrow, isNeedAdjustHeight, offsetStyle } = this.options;
const {
belowMouse,
supportCSSTransform,
container,
direction,
adjustXOffset,
adjustYOffset,
adjustLength,
showArrow,
isNeedAdjustHeight,
offsetStyle,
} = this.options;
let p = {};
if (!this.popupView) {
return;
}
const isVisible = this.popupView.isVisible();
this.popupView.visible();
const combo = (belowMouse && isNotNull(e)) ? {
element: {
0: e.target,
offset: () => {
return {
left: e.pageX,
top: e.pageY,
};
},
bounds: () => {
// offset为其相对于父定位元素的偏移
return {
x: e.offsetX,
y: e.offsetY,
width: 0,
height: 24,
};
},
outerWidth: () => {
return 0;
},
outerHeight: () => {
return 24;
},
},
} : this.combo;
const positionRelativeElement = supportCSSTransform ? BI.DOM.getPositionRelativeContainingBlock(isNull(container) ? this.element[0] : Widget._renderEngine.createElement(isFunction(container) ? container() : container)[0]) : null;
const combo =
belowMouse && isNotNull(e)
? {
element: {
0: e.target,
offset: () => {
return {
left: e.pageX,
top: e.pageY,
};
},
bounds: () => {
// offset为其相对于父定位元素的偏移
return {
x: e.offsetX,
y: e.offsetY,
width: 0,
height: 24,
};
},
outerWidth: () => 0,
outerHeight: () => 24,
},
}
: this.combo;
const positionRelativeElement = supportCSSTransform
? BI.DOM.getPositionRelativeContainingBlock(
isNull(container)
? this.element[0]
: Widget._renderEngine.createElement(isFunction(container) ? container() : container)[0]
)
: null;
const TRIANGLE_LENGTH = 12;
switch (direction) {
case "bottom":
case "bottom,right":
p = BI.DOM.getComboPosition(combo, this.popupView, adjustXOffset, (adjustYOffset + adjustLength) + (showArrow ? TRIANGLE_LENGTH : 0), isNeedAdjustHeight, ["bottom", "top", "right", "left"], offsetStyle, positionRelativeElement);
break;
case "top":
case "top,right":
p = BI.DOM.getComboPosition(combo, this.popupView, adjustXOffset, (adjustYOffset + adjustLength) + (showArrow ? TRIANGLE_LENGTH : 0), isNeedAdjustHeight, ["top", "bottom", "right", "left"], offsetStyle, positionRelativeElement);
break;
case "left":
case "left,bottom":
p = BI.DOM.getComboPosition(combo, this.popupView, (adjustXOffset + adjustLength) + (showArrow ? TRIANGLE_LENGTH : 0), adjustYOffset, isNeedAdjustHeight, ["left", "right", "bottom", "top"], offsetStyle, positionRelativeElement);
break;
case "right":
case "right,bottom":
p = BI.DOM.getComboPosition(combo, this.popupView, (adjustXOffset + adjustLength) + (showArrow ? TRIANGLE_LENGTH : 0), adjustYOffset, isNeedAdjustHeight, ["right", "left", "bottom", "top"], offsetStyle, positionRelativeElement);
break;
case "top,left":
p = BI.DOM.getComboPosition(combo, this.popupView, adjustXOffset, (adjustYOffset + adjustLength) + (showArrow ? TRIANGLE_LENGTH : 0), isNeedAdjustHeight, ["top", "bottom", "left", "right"], offsetStyle, positionRelativeElement);
break;
case "bottom,left":
p = BI.DOM.getComboPosition(combo, this.popupView, adjustXOffset, (adjustYOffset + adjustLength) + (showArrow ? TRIANGLE_LENGTH : 0), isNeedAdjustHeight, ["bottom", "top", "left", "right"], offsetStyle, positionRelativeElement);
break;
case "left,top":
p = BI.DOM.getComboPosition(combo, this.popupView, (adjustXOffset + adjustLength) + (showArrow ? TRIANGLE_LENGTH : 0), adjustYOffset, isNeedAdjustHeight, ["left", "right", "top", "bottom"], offsetStyle, positionRelativeElement);
break;
case "right,top":
p = BI.DOM.getComboPosition(combo, this.popupView, (adjustXOffset + adjustLength) + (showArrow ? TRIANGLE_LENGTH : 0), adjustYOffset, isNeedAdjustHeight, ["right", "left", "top", "bottom"], offsetStyle, positionRelativeElement);
break;
case "right,innerRight":
p = BI.DOM.getComboPosition(combo, this.popupView, (adjustXOffset + adjustLength) + (showArrow ? TRIANGLE_LENGTH : 0), adjustYOffset, isNeedAdjustHeight, ["right", "left", "innerRight", "innerLeft", "bottom", "top"], offsetStyle, positionRelativeElement);
break;
case "right,innerLeft":
p = BI.DOM.getComboPosition(combo, this.popupView, (adjustXOffset + adjustLength) + (showArrow ? TRIANGLE_LENGTH : 0), adjustYOffset, isNeedAdjustHeight, ["right", "left", "innerLeft", "innerRight", "bottom", "top"], offsetStyle, positionRelativeElement);
break;
case "innerRight":
p = BI.DOM.getComboPosition(combo, this.popupView, (adjustXOffset + adjustLength) + (showArrow ? TRIANGLE_LENGTH : 0), adjustYOffset, isNeedAdjustHeight, ["innerRight", "innerLeft", "right", "left", "bottom", "top"], offsetStyle, positionRelativeElement);
break;
case "innerLeft":
p = BI.DOM.getComboPosition(combo, this.popupView, (adjustXOffset + adjustLength) + (showArrow ? TRIANGLE_LENGTH : 0), adjustYOffset, isNeedAdjustHeight, ["innerLeft", "innerRight", "left", "right", "bottom", "top"], offsetStyle, positionRelativeElement);
break;
case "top,custom":
case "custom,top":
p = BI.DOM.getTopAdaptPosition(combo, this.popupView, (adjustYOffset + adjustLength) + (showArrow ? TRIANGLE_LENGTH : 0), isNeedAdjustHeight);
p.dir = "top";
break;
case "custom,bottom":
case "bottom,custom":
p = BI.DOM.getBottomAdaptPosition(combo, this.popupView, (adjustYOffset + adjustLength) + (showArrow ? TRIANGLE_LENGTH : 0), isNeedAdjustHeight);
p.dir = "bottom";
break;
case "left,custom":
case "custom,left":
p = BI.DOM.getLeftAdaptPosition(combo, this.popupView, (adjustXOffset + adjustLength) + (showArrow ? TRIANGLE_LENGTH : 0));
delete p.top;
delete p.adaptHeight;
p.dir = "left";
break;
case "custom,right":
case "right,custom":
p = BI.DOM.getRightAdaptPosition(combo, this.popupView, (adjustXOffset + adjustLength) + (showArrow ? TRIANGLE_LENGTH : 0));
delete p.top;
delete p.adaptHeight;
p.dir = "right";
break;
default:
break;
case "bottom":
case "bottom,right":
p = BI.DOM.getComboPosition(
combo,
this.popupView,
adjustXOffset,
adjustYOffset + adjustLength + (showArrow ? TRIANGLE_LENGTH : 0),
isNeedAdjustHeight,
["bottom", "top", "right", "left"],
offsetStyle,
positionRelativeElement
);
break;
case "top":
case "top,right":
p = BI.DOM.getComboPosition(
combo,
this.popupView,
adjustXOffset,
adjustYOffset + adjustLength + (showArrow ? TRIANGLE_LENGTH : 0),
isNeedAdjustHeight,
["top", "bottom", "right", "left"],
offsetStyle,
positionRelativeElement
);
break;
case "left":
case "left,bottom":
p = BI.DOM.getComboPosition(
combo,
this.popupView,
adjustXOffset + adjustLength + (showArrow ? TRIANGLE_LENGTH : 0),
adjustYOffset,
isNeedAdjustHeight,
["left", "right", "bottom", "top"],
offsetStyle,
positionRelativeElement
);
break;
case "right":
case "right,bottom":
p = BI.DOM.getComboPosition(
combo,
this.popupView,
adjustXOffset + adjustLength + (showArrow ? TRIANGLE_LENGTH : 0),
adjustYOffset,
isNeedAdjustHeight,
["right", "left", "bottom", "top"],
offsetStyle,
positionRelativeElement
);
break;
case "top,left":
p = BI.DOM.getComboPosition(
combo,
this.popupView,
adjustXOffset,
adjustYOffset + adjustLength + (showArrow ? TRIANGLE_LENGTH : 0),
isNeedAdjustHeight,
["top", "bottom", "left", "right"],
offsetStyle,
positionRelativeElement
);
break;
case "bottom,left":
p = BI.DOM.getComboPosition(
combo,
this.popupView,
adjustXOffset,
adjustYOffset + adjustLength + (showArrow ? TRIANGLE_LENGTH : 0),
isNeedAdjustHeight,
["bottom", "top", "left", "right"],
offsetStyle,
positionRelativeElement
);
break;
case "left,top":
p = BI.DOM.getComboPosition(
combo,
this.popupView,
adjustXOffset + adjustLength + (showArrow ? TRIANGLE_LENGTH : 0),
adjustYOffset,
isNeedAdjustHeight,
["left", "right", "top", "bottom"],
offsetStyle,
positionRelativeElement
);
break;
case "right,top":
p = BI.DOM.getComboPosition(
combo,
this.popupView,
adjustXOffset + adjustLength + (showArrow ? TRIANGLE_LENGTH : 0),
adjustYOffset,
isNeedAdjustHeight,
["right", "left", "top", "bottom"],
offsetStyle,
positionRelativeElement
);
break;
case "right,innerRight":
p = BI.DOM.getComboPosition(
combo,
this.popupView,
adjustXOffset + adjustLength + (showArrow ? TRIANGLE_LENGTH : 0),
adjustYOffset,
isNeedAdjustHeight,
["right", "left", "innerRight", "innerLeft", "bottom", "top"],
offsetStyle,
positionRelativeElement
);
break;
case "right,innerLeft":
p = BI.DOM.getComboPosition(
combo,
this.popupView,
adjustXOffset + adjustLength + (showArrow ? TRIANGLE_LENGTH : 0),
adjustYOffset,
isNeedAdjustHeight,
["right", "left", "innerLeft", "innerRight", "bottom", "top"],
offsetStyle,
positionRelativeElement
);
break;
case "innerRight":
p = BI.DOM.getComboPosition(
combo,
this.popupView,
adjustXOffset + adjustLength + (showArrow ? TRIANGLE_LENGTH : 0),
adjustYOffset,
isNeedAdjustHeight,
["innerRight", "innerLeft", "right", "left", "bottom", "top"],
offsetStyle,
positionRelativeElement
);
break;
case "innerLeft":
p = BI.DOM.getComboPosition(
combo,
this.popupView,
adjustXOffset + adjustLength + (showArrow ? TRIANGLE_LENGTH : 0),
adjustYOffset,
isNeedAdjustHeight,
["innerLeft", "innerRight", "left", "right", "bottom", "top"],
offsetStyle,
positionRelativeElement
);
break;
case "top,custom":
case "custom,top":
p = BI.DOM.getTopAdaptPosition(
combo,
this.popupView,
adjustYOffset + adjustLength + (showArrow ? TRIANGLE_LENGTH : 0),
isNeedAdjustHeight
);
p.dir = "top";
break;
case "custom,bottom":
case "bottom,custom":
p = BI.DOM.getBottomAdaptPosition(
combo,
this.popupView,
adjustYOffset + adjustLength + (showArrow ? TRIANGLE_LENGTH : 0),
isNeedAdjustHeight
);
p.dir = "bottom";
break;
case "left,custom":
case "custom,left":
p = BI.DOM.getLeftAdaptPosition(
combo,
this.popupView,
adjustXOffset + adjustLength + (showArrow ? TRIANGLE_LENGTH : 0)
);
delete p.top;
delete p.adaptHeight;
p.dir = "left";
break;
case "custom,right":
case "right,custom":
p = BI.DOM.getRightAdaptPosition(
combo,
this.popupView,
adjustXOffset + adjustLength + (showArrow ? TRIANGLE_LENGTH : 0)
);
delete p.top;
delete p.adaptHeight;
p.dir = "right";
break;
default:
break;
}
if ("adaptHeight" in p) {
@ -313,17 +496,17 @@ export class Combo extends Bubble {
const width = this.combo.element.outerWidth();
const height = this.combo.element.outerHeight();
this.popupView.setDirection && this.popupView.setDirection(p.dir, {
width,
height,
offsetStyle,
adjustXOffset,
adjustYOffset,
offset: this.combo.element.offset(),
});
this.popupView.setDirection &&
this.popupView.setDirection(p.dir, {
width,
height,
offsetStyle,
adjustXOffset,
adjustYOffset,
offset: this.combo.element.offset(),
});
if (supportCSSTransform) {
const positonedRect = positionRelativeElement.getBoundingClientRect();
const scaleX = positonedRect.width / positionRelativeElement.offsetWidth;
@ -348,14 +531,14 @@ export class Combo extends Bubble {
}
destroyed() {
Widget._renderEngine.createElement(document)
.unbind("click." + this.getName())
.unbind("mousedown." + this.getName())
.unbind("mousewheel." + this.getName())
.unbind("mouseenter." + this.getName())
.unbind("mouseleave." + this.getName());
Widget._renderEngine.createElement(window)
.unbind("blur." + this.getName());
Widget._renderEngine
.createElement(document)
.unbind(`click.${this.getName()}`)
.unbind(`mousedown.${this.getName()}`)
.unbind(`mousewheel.${this.getName()}`)
.unbind(`mouseenter.${this.getName()}`)
.unbind(`mouseleave.${this.getName()}`);
Widget._renderEngine.createElement(window).unbind(`blur.${this.getName()}`);
Resizers.remove(this.getName());
this.popupView && this.popupView._destroy();
delete needHideWhenAnotherComboOpen[this.getName()];

166
src/base/combination/expander.js

@ -1,3 +1,17 @@
import {
VerticalLayout,
shortcut,
Widget,
Controller,
extend,
nextTick,
each,
debounce,
isNull,
createWidget
} from "@/core";
import { ButtonGroup } from "./group.button";
/**
*
* 某个可以展开的节点
@ -6,7 +20,6 @@
* @class BI.Expander
* @extends BI.Widget
*/
import { shortcut, Widget, Controller, extend, nextTick, each, debounce, isNull, createWidget } from "../../core";
@shortcut()
export class Expander extends Widget {
@ -67,22 +80,23 @@ export class Expander extends Widget {
}
});
this.element.hover(() => {
if (this.isEnabled() && this.isValid() && this.expander.isEnabled() && this.expander.isValid()) {
this.element.addClass(hoverClass);
}
}, () => {
if (this.isEnabled() && this.isValid() && this.expander.isEnabled() && this.expander.isValid()) {
this.element.removeClass(hoverClass);
this.element.hover(
() => {
if (this.isEnabled() && this.isValid() && this.expander.isEnabled() && this.expander.isValid()) {
this.element.addClass(hoverClass);
}
},
() => {
if (this.isEnabled() && this.isValid() && this.expander.isEnabled() && this.expander.isValid()) {
this.element.removeClass(hoverClass);
}
}
});
);
createWidget({
type: "bi.vertical",
type: VerticalLayout.xtype,
scrolly: false,
element: this,
items: [
{ el: this.expander }
],
items: [{ el: this.expander }],
});
isDefaultInit && this._assertPopupView();
if (this.expander.isOpened() === true) {
@ -106,44 +120,80 @@ export class Expander extends Widget {
const evs = this.options.trigger.split(",");
each(evs, (i, e) => {
switch (e) {
case "hover":
this.element[e]((e) => {
if (this.isEnabled() && this.isValid() && this.expander.isEnabled() && this.expander.isValid()) {
case "hover":
this.element[e](
e => {
if (
this.isEnabled() &&
this.isValid() &&
this.expander.isEnabled() &&
this.expander.isValid()
) {
this._popupView();
this.fireEvent(Controller.EVENT_CHANGE, BI.Events.EXPAND, "", this.expander);
this.fireEvent(Expander.EVENT_EXPAND);
}
}, () => {
if (this.isEnabled() && this.isValid() && this.expander.isEnabled() && this.expander.isValid() && toggle) {
},
() => {
if (
this.isEnabled() &&
this.isValid() &&
this.expander.isEnabled() &&
this.expander.isValid() &&
toggle
) {
this._hideView();
this.fireEvent(Controller.EVENT_CHANGE, BI.Events.COLLAPSE, "", this.expander);
this.fireEvent(Expander.EVENT_COLLAPSE);
}
});
break;
case "click":
if (e) {
this.element.off(e + "." + this.getName()).on(e + "." + this.getName(), debounce((e) => {
if (this.expander.element.__isMouseInBounds__(e)) {
if (this.isEnabled() && this.isValid() && this.expander.isEnabled() && this.expander.isValid()) {
toggle ? this._toggle() : this._popupView();
if (this.isExpanded()) {
this.fireEvent(Controller.EVENT_CHANGE, BI.Events.EXPAND, "", this.expander);
this.fireEvent(Expander.EVENT_EXPAND);
} else {
this.fireEvent(Controller.EVENT_CHANGE, BI.Events.COLLAPSE, "", this.expander);
this.fireEvent(Expander.EVENT_COLLAPSE);
}
);
break;
case "click":
if (e) {
this.element.off(`${e}.${this.getName()}`).on(
`${e}.${this.getName()}`,
debounce(
e => {
if (this.expander.element.__isMouseInBounds__(e)) {
if (
this.isEnabled() &&
this.isValid() &&
this.expander.isEnabled() &&
this.expander.isValid()
) {
toggle ? this._toggle() : this._popupView();
if (this.isExpanded()) {
this.fireEvent(
Controller.EVENT_CHANGE,
BI.Events.EXPAND,
"",
this.expander
);
this.fireEvent(Expander.EVENT_EXPAND);
} else {
this.fireEvent(
Controller.EVENT_CHANGE,
BI.Events.COLLAPSE,
"",
this.expander
);
this.fireEvent(Expander.EVENT_COLLAPSE);
}
}
}
},
BI.EVENT_RESPONSE_TIME,
{
leading: true,
trailing: false,
}
}, BI.EVENT_RESPONSE_TIME, {
"leading": true,
"trailing": false,
}));
}
break;
default:
break;
)
);
}
break;
default:
break;
}
});
}
@ -155,17 +205,23 @@ export class Expander extends Widget {
_assertPopupView() {
const { value } = this.options;
if (isNull(this.popupView)) {
this.popupView = createWidget(this.options.popup, {
type: "bi.button_group",
cls: "expander-popup",
layouts: [{
type: "bi.vertical",
hgap: 0,
vgap: 0,
}],
value,
}, this);
this.popupView.on(Controller.EVENT_CHANGE, (type, value, obj, ...args)=> {
this.popupView = createWidget(
this.options.popup,
{
type: ButtonGroup.xtype,
cls: "expander-popup",
layouts: [
{
type: VerticalLayout.xtype,
hgap: 0,
vgap: 0,
}
],
value,
},
this
);
this.popupView.on(Controller.EVENT_CHANGE, (type, value, obj, ...args) => {
this.fireEvent(Controller.EVENT_CHANGE, type, value, obj, ...args);
if (type === BI.Events.CLICK) {
// self.setValue(self.getValue());
@ -183,12 +239,10 @@ export class Expander extends Widget {
this._assertPopupView();
if (!this._rendered) {
createWidget({
type: "bi.vertical",
type: VerticalLayout.xtype,
scrolly: false,
element: this,
items: [
{ el: this.popupView }
],
items: [{ el: this.popupView }],
});
this._rendered = true;
}
@ -281,7 +335,7 @@ export class Expander extends Widget {
if (this.expander.getValue() === value) {
return this.expander;
}
return this.popupView && this.popupView.getNodeByValue(value);
}

85
src/base/combination/group.button.js

@ -1,9 +1,38 @@
import {
CenterLayout,
shortcut,
Widget,
Controller,
extend,
createWidget,
createWidgets,
each,
isFunction,
isKey,
isNotEmptyArray,
createItems,
isArray,
remove,
map,
stripEL,
makeArrayByArray,
clone,
deepClone,
formatEL,
isEmpty,
concat,
removeAt,
deepContains,
has,
any
} from "@/core";
import { TextButton } from "../single";
/**
* Created by GUY on 2015/6/26.
* @class BI.ButtonGroup
* @extends BI.Widget
*/
import { shortcut, Widget, Controller, extend, createWidget, createWidgets, each, isFunction, isKey, isNotEmptyArray, createItems, isArray, remove, map, stripEL, makeArrayByArray, clone, deepClone, formatEL, isEmpty, concat, removeAt, deepContains, has, any } from "../../core";
@shortcut()
export class ButtonGroup extends Widget {
@ -18,11 +47,13 @@ export class ButtonGroup extends Widget {
items: [],
value: "",
chooseType: BI.Selection.Single,
layouts: [{
type: "bi.center",
hgap: 0,
vgap: 0,
}],
layouts: [
{
type: CenterLayout.xtype,
hgap: 0,
vgap: 0,
}
],
});
}
@ -35,13 +66,17 @@ export class ButtonGroup extends Widget {
});
});
this.behaviors = behaviors;
const items = isFunction(optionsItems) ? this.__watch(optionsItems, (context, newValue) => {
this.populate(newValue);
}) : optionsItems;
const items = isFunction(optionsItems)
? this.__watch(optionsItems, (context, newValue) => {
this.populate(newValue);
})
: optionsItems;
this.populate(items);
this.options.value = isFunction(value) ? this.__watch(value, (context, newValue) => {
this.setValue(newValue);
}) : value;
this.options.value = isFunction(value)
? this.__watch(value, (context, newValue) => {
this.setValue(newValue);
})
: value;
if (isKey(value) || isNotEmptyArray(value)) {
this.setValue(value);
}
@ -50,9 +85,11 @@ export class ButtonGroup extends Widget {
_createBtns(items) {
let btns;
Widget.execWithContext(this, () => {
btns = createWidgets(createItems(items, {
type: "bi.text_button",
}));
btns = createWidgets(
createItems(items, {
type: TextButton.xtype,
})
);
});
return btns;
@ -99,13 +136,15 @@ export class ButtonGroup extends Widget {
const { layouts: optionsLayouts } = this.options;
const layouts = isArray(optionsLayouts) ? optionsLayouts : [optionsLayouts];
for (let i = layouts.length - 1; i > 0; i--) {
btns = map(btns, (k, it) => extend({}, layouts[i], {
items: [
extend({}, layouts[i].el, {
el: it,
})
],
}));
btns = map(btns, (k, it) =>
extend({}, layouts[i], {
items: [
extend({}, layouts[i].el, {
el: it,
})
],
})
);
}
return btns;
@ -146,7 +185,7 @@ export class ButtonGroup extends Widget {
_isSimpleLayout() {
const { layouts, items } = this.options;
return isArray(layouts) ? (layouts.length === 1 && !isArray(items[0])) : true;
return isArray(layouts) ? layouts.length === 1 && !isArray(items[0]) : true;
}
doBehavior() {

55
src/base/combination/group.combo.js

@ -1,9 +1,23 @@
import { TextButton } from "../single";
import { ButtonTree } from "./tree.button";
import {
VerticalLayout,
shortcut,
Widget,
Controller,
extend,
isEmpty,
each,
formatEL,
clone,
createWidget
} from "@/core";
import { Combo } from "./combo";
/**
* Created by GUY on 2015/8/10.
*/
import { shortcut, Widget, Controller, extend, isEmpty, each, formatEL, clone, createWidget } from "../../core";
@shortcut()
export class ComboGroup extends Widget {
static xtype = "bi.combo_group";
@ -22,16 +36,18 @@ export class ComboGroup extends Widget {
isNeedAdjustHeight: false,
isNeedAdjustWidth: false,
el: { type: "bi.text_button", text: "", value: "" },
el: { type: TextButton.xtype, text: "", value: "" },
items: [],
popup: {
el: {
type: "bi.button_tree",
type: ButtonTree.xtype,
chooseType: 0,
layouts: [{
type: "bi.vertical",
}],
layouts: [
{
type: VerticalLayout.xtype,
}
],
},
},
});
@ -42,7 +58,19 @@ export class ComboGroup extends Widget {
}
_populate(item) {
const { items, action, height, direction, isDefaultInit, isNeedAdjustHeight, isNeedAdjustWidth, adjustLength, popup, container, trigger } = this.options;
const {
items,
action,
height,
direction,
isDefaultInit,
isNeedAdjustHeight,
isNeedAdjustWidth,
adjustLength,
popup,
container,
trigger,
} = this.options;
const children = items;
if (isEmpty(children)) {
throw new Error("ComboGroup构造错误");
@ -65,7 +93,7 @@ export class ComboGroup extends Widget {
}
});
this.combo = createWidget({
type: "bi.combo",
type: Combo.xtype,
element: this,
container,
height,
@ -77,9 +105,12 @@ export class ComboGroup extends Widget {
adjustLength,
el: item,
popup: extend({}, popup, {
el: extend({
items: children,
}, popup.el),
el: extend(
{
items: children,
},
popup.el
),
}),
});
this.combo.on(Controller.EVENT_CHANGE, (type, value, obj, ...args) => {

67
src/base/combination/group.virtual.js

@ -1,32 +1,54 @@
import { shortcut, Widget, Controller, extend, isFunction, isKey, isArray, map, stripEL, deepClone, formatEL, isEmpty, each, createWidget } from "../../core";
import {
CenterLayout,
shortcut,
Widget,
Controller,
extend,
isFunction,
isKey,
isArray,
map,
stripEL,
deepClone,
formatEL,
isEmpty,
each,
createWidget
} from "@/core";
@shortcut()
export class VirtualGroup extends Widget {
static xtype = "bi.virtual_group";
static EVENT_CHANGE = "EVENT_CHANGE";
_defaultConfig() {
return extend(super._defaultConfig(...arguments), {
baseCls: "bi-virtual-group",
items: [],
layouts: [{
type: "bi.center",
hgap: 0,
vgap: 0,
}],
layouts: [
{
type: CenterLayout.xtype,
hgap: 0,
vgap: 0,
}
],
});
}
render() {
const { items: optionsItems, value } = this.options;
const items = isFunction(optionsItems) ? this.__watch(optionsItems, (context, newValue) => {
this.populate(newValue);
}) : optionsItems;
const items = isFunction(optionsItems)
? this.__watch(optionsItems, (context, newValue) => {
this.populate(newValue);
})
: optionsItems;
this.populate(items);
this.options.value = isFunction(value) ? this.__watch(value, (context, newValue) => {
this.setValue(newValue);
}) : value;
this.options.value = isFunction(value)
? this.__watch(value, (context, newValue) => {
this.setValue(newValue);
})
: value;
if (isKey(value)) {
this.setValue(value);
}
@ -34,7 +56,7 @@ export class VirtualGroup extends Widget {
_packageBtns(items) {
const o = this.options;
const map = this.buttonMap = {};
const map = (this.buttonMap = {});
const layouts = isArray(o.layouts) ? o.layouts : [o.layouts];
for (let i = layouts.length - 1; i > 0; i--) {
items = map(items, (k, it) => {
@ -43,19 +65,22 @@ export class VirtualGroup extends Widget {
return extend({}, layouts[i], {
items: [
extend({}, layouts[i].el, {
el: extend({
ref: (_ref) => {
if (isKey(map[el.value])) {
map[el.value] = _ref;
}
el: extend(
{
ref: _ref => {
if (isKey(map[el.value])) {
map[el.value] = _ref;
}
},
},
}, el),
el
),
})
],
});
});
}
return items;
}

2
src/base/combination/index.js

@ -9,4 +9,4 @@ export { Navigation } from "./navigation";
export { Searcher } from "./searcher";
export { Switcher } from "./switcher";
export { Tab } from "./tab";
export { ButtonTree } from "./tree.button";
export { ButtonTree } from "./tree.button";

184
src/base/combination/loader.js

@ -1,3 +1,22 @@
import { ButtonGroup } from "./group.button";
import { LoadingBar } from "../single";
import {
VerticalLayout,
shortcut,
Widget,
Controller,
extend,
createWidget,
isEmpty,
nextTick,
bind,
isFunction,
isNotEmptyArray,
isNumber,
isObject,
each
} from "@/core";
/**
* 加载控件
*
@ -5,12 +24,11 @@
* @class BI.Loader
* @extends BI.Widget
*/
import { shortcut, Widget, Controller, extend, createWidget, isEmpty, nextTick, bind, isFunction, isNotEmptyArray, isNumber, isObject, each } from "../../core";
@shortcut()
export class Loader extends Widget {
static xtype = "bi.loader";
static EVENT_CHANGE = "EVENT_CHANGE";
_defaultConfig() {
@ -26,7 +44,7 @@ export class Loader extends Widget {
// 下面是button_group的属性
el: {
type: "bi.button_group",
type: ButtonGroup.xtype,
},
items: [],
@ -45,32 +63,53 @@ export class Loader extends Widget {
_prevLoad() {
const o = this.options;
this.prev.setLoading();
o.itemsCreator.apply(this, [{ times: --this.times }, (...args) => {
this.prev.setLoaded();
this.prependItems.apply(this, args);
}]);
o.itemsCreator.apply(this, [
{ times: --this.times },
(...args) => {
this.prev.setLoaded();
this.prependItems.apply(this, args);
}
]);
}
_nextLoad() {
const o = this.options;
this.next.setLoading();
o.itemsCreator.apply(this, [{ times: ++this.times }, (...args) => {
this.next.setLoaded();
this.addItems.apply(this, args);
}]);
o.itemsCreator.apply(this, [
{ times: ++this.times },
(...args) => {
this.next.setLoaded();
this.addItems.apply(this, args);
}
]);
}
render() {
const { itemsCreator, prev, next, el, items: optionsItems, value, direction, logic, isDefaultInit } = this.options;
const {
itemsCreator,
prev,
next,
el,
items: optionsItems,
value,
direction,
logic,
isDefaultInit,
} = this.options;
if (itemsCreator === false) {
prev = false;
next = false;
}
if (prev !== false) {
this.prev = createWidget(extend({
type: "bi.loading_bar",
}, prev));
this.prev.on(Controller.EVENT_CHANGE, (type) => {
this.prev = createWidget(
extend(
{
type: LoadingBar.xtype,
},
prev
)
);
this.prev.on(Controller.EVENT_CHANGE, type => {
if (type === BI.Events.CLICK) {
this._prevLoad();
}
@ -78,13 +117,15 @@ export class Loader extends Widget {
}
this.button_group = createWidget(el, {
type: "bi.button_group",
type: ButtonGroup.xtype,
chooseType: 0,
items: optionsItems,
behaviors: {},
layouts: [{
type: "bi.vertical",
}],
layouts: [
{
type: VerticalLayout.xtype,
}
],
value,
});
this.button_group.on(Controller.EVENT_CHANGE, (type, value, obj, ...args) => {
@ -95,30 +136,58 @@ export class Loader extends Widget {
});
if (next !== false) {
this.next = createWidget(extend({
type: "bi.loading_bar",
}, next));
this.next.on(Controller.EVENT_CHANGE, (type) => {
this.next = createWidget(
extend(
{
type: LoadingBar.xtype,
},
next
)
);
this.next.on(Controller.EVENT_CHANGE, type => {
if (type === BI.Events.CLICK) {
this._nextLoad();
}
});
}
createWidget(extend({
element: this,
}, BI.LogicFactory.createLogic(BI.LogicFactory.createLogicTypeByDirection(direction), extend({
scrolly: true,
}, logic, {
items: BI.LogicFactory.createLogicItemsByDirection(direction, this.prev, this.button_group, this.next),
}))));
isDefaultInit && isEmpty(optionsItems) && nextTick(bind(() => {
isDefaultInit && isEmpty(optionsItems) && this._populate();
}, this));
const items = isFunction(optionsItems) ? this.__watch(optionsItems, (context, newValue) => {
this.populate(newValue);
}) : optionsItems;
createWidget(
extend(
{
element: this,
},
BI.LogicFactory.createLogic(
BI.LogicFactory.createLogicTypeByDirection(direction),
extend(
{
scrolly: true,
},
logic,
{
items: BI.LogicFactory.createLogicItemsByDirection(
direction,
this.prev,
this.button_group,
this.next
),
}
)
)
)
);
isDefaultInit &&
isEmpty(optionsItems) &&
nextTick(
bind(() => {
isDefaultInit && isEmpty(optionsItems) && this._populate();
}, this)
);
const items = isFunction(optionsItems)
? this.__watch(optionsItems, (context, newValue) => {
this.populate(newValue);
})
: optionsItems;
if (isNotEmptyArray(items)) {
this._populate(items);
}
@ -130,10 +199,12 @@ export class Loader extends Widget {
return this.count < count;
}
return !!hasPrev.apply(this, [{
times: this.times,
count: this.count,
}]);
return !!hasPrev.apply(this, [
{
times: this.times,
count: this.count,
}
]);
}
hasNext() {
@ -142,10 +213,12 @@ export class Loader extends Widget {
return this.count < count;
}
return !!hasNext.apply(this, [{
times: this.times,
count: this.count,
}]);
return !!hasNext.apply(this, [
{
times: this.times,
count: this.count,
}
]);
}
prependItems(items) {
@ -176,14 +249,17 @@ export class Loader extends Widget {
_populate(items) {
const o = this.options;
if (arguments.length === 0 && (isFunction(o.itemsCreator))) {
o.itemsCreator.apply(this, [{ times: 1 }, (...args) => {
if (args.length === 0) {
throw new Error("参数不能为空");
if (arguments.length === 0 && isFunction(o.itemsCreator)) {
o.itemsCreator.apply(this, [
{ times: 1 },
(...args) => {
if (args.length === 0) {
throw new Error("参数不能为空");
}
this.populate.apply(this, args);
o.onLoaded();
}
this.populate.apply(this, args);
o.onLoaded();
}]);
]);
return false;
}
@ -205,7 +281,7 @@ export class Loader extends Widget {
this.prev.invisible();
}
}
return true;
}

48
src/base/combination/navigation.js

@ -1,12 +1,28 @@
import { ButtonGroup } from "./group.button";
import {
CardLayout,
shortcut,
Widget,
Controller,
extend,
createWidget,
bind,
ShowListener,
isFunction,
each,
nextTick,
isKey,
values
} from "@/core";
/**
* Created by GUY on 2015/6/26.
*/
import { shortcut, Widget, Controller, extend, createWidget, bind, ShowListener, isFunction, each, nextTick, isKey, values } from "../../core";
@shortcut()
export class Navigation extends Widget {
static xtype = "bi.navigation";
static EVENT_CHANGE = "EVENT_CHANGE";
_defaultConfig() {
@ -27,18 +43,25 @@ export class Navigation extends Widget {
render() {
const { direction, logic, cardCreator, showIndex } = this.options;
this.tab = createWidget(this.options.tab, { type: "bi.button_group" });
this.tab = createWidget(this.options.tab, { type: ButtonGroup.xtype });
this.cardMap = {};
this.showIndex = 0;
this.layout = createWidget({
type: "bi.card",
type: CardLayout.xtype,
});
createWidget(extend({
element: this,
}, BI.LogicFactory.createLogic(BI.LogicFactory.createLogicTypeByDirection(direction), extend({}, logic, {
items: BI.LogicFactory.createLogicItemsByDirection(direction, this.tab, this.layout),
}))));
createWidget(
extend(
{
element: this,
},
BI.LogicFactory.createLogic(
BI.LogicFactory.createLogicTypeByDirection(direction),
extend({}, logic, {
items: BI.LogicFactory.createLogicItemsByDirection(direction, this.tab, this.layout),
})
)
)
);
new ShowListener({
eventObj: this.tab,
@ -48,7 +71,7 @@ export class Navigation extends Widget {
Widget.execWithContext(this, () => {
this.cardMap[v] = cardCreator(v);
});
return this.cardMap[v];
},
afterCardCreated: bind(this.afterCardCreated, this),
@ -73,7 +96,7 @@ export class Navigation extends Widget {
const { single } = this.options;
if (single === true) {
each(this.cardMap, (name, card) => {
if (name !== (`${currCardName}`)) {
if (name !== `${currCardName}`) {
this.layout.deleteCardByName(name);
delete this.cardMap[name];
}
@ -168,4 +191,3 @@ export class Navigation extends Widget {
super.destroy(arguments);
}
}

159
src/base/combination/searcher.js

@ -1,11 +1,7 @@
/**
* 搜索逻辑控件
*
* Created by GUY on 2015/9/28.
* @class BI.Searcher
* @extends BI.Widget
*/
import { SearchEditor } from "@/widget/editor/editor.search.js";
import { SearcherView } from "../layer";
import {
VerticalLayout,
shortcut,
Widget,
Controller,
@ -18,9 +14,17 @@ import {
nextTick,
isEmptyString,
isNull
} from "../../core";
} from "@/core";
import { ButtonGroup } from "./group.button";
import { Maskers } from "../0.base";
import { Maskers } from "@/base/0.base";
/**
* 搜索逻辑控件
*
* Created by GUY on 2015/9/28.
* @class BI.Searcher
* @extends BI.Widget
*/
@shortcut()
export class Searcher extends Widget {
@ -54,15 +58,16 @@ export class Searcher extends Widget {
},
el: {
type: "bi.search_editor",
type: SearchEditor.xtype,
},
popup: {
type: "bi.searcher_view",
type: SearcherView.xtype,
},
adapter: null,
masker: { // masker层
masker: {
// masker层
offset: {},
},
});
@ -72,11 +77,11 @@ export class Searcher extends Widget {
const { el, lgap, rgap, tgap, bgap, vgap, hgap, isDefaultInit } = this.options;
this.editor = createWidget(el, {
type: "bi.search_editor",
type: SearchEditor.xtype,
});
createWidget({
type: "bi.vertical",
type: VerticalLayout.xtype,
element: this,
lgap,
rgap,
@ -86,30 +91,30 @@ export class Searcher extends Widget {
hgap,
items: [this.editor],
});
isDefaultInit && (this._assertPopupView());
isDefaultInit && this._assertPopupView();
const search = debounce(bind(this._search, this), BI.EVENT_RESPONSE_TIME, {
"leading": true,
"trailing": false,
leading: true,
trailing: false,
});
this.editor.on(Controller.EVENT_CHANGE, (type) => {
this.editor.on(Controller.EVENT_CHANGE, type => {
switch (type) {
case BI.Events.STARTEDIT:
this._startSearch();
break;
case BI.Events.EMPTY:
this._stopSearch();
break;
case BI.Events.CHANGE:
search();
break;
case BI.Events.PAUSE:
if (endWith(this.getValue(), BI.BlankSplitChar)) {
this._pauseSearch();
}
break;
default:
break;
case BI.Events.STARTEDIT:
this._startSearch();
break;
case BI.Events.EMPTY:
this._stopSearch();
break;
case BI.Events.CHANGE:
search();
break;
case BI.Events.PAUSE:
if (endWith(this.getValue(), BI.BlankSplitChar)) {
this._pauseSearch();
}
break;
default:
break;
}
});
}
@ -118,8 +123,8 @@ export class Searcher extends Widget {
const { masker, popup, chooseType, isAutoSync, adapter } = this.options;
if ((masker && !Maskers.has(this.getName())) || (masker === false && !this.popupView)) {
this.popupView = createWidget(popup, {
type: "bi.searcher_view",
chooseType: chooseType,
type: SearcherView.xtype,
chooseType,
});
this.popupView.on(Controller.EVENT_CHANGE, (type, value, obj, ...args) => {
this.fireEvent(Controller.EVENT_CHANGE, type, value, obj, ...args);
@ -127,18 +132,18 @@ export class Searcher extends Widget {
if (isAutoSync) {
const values = adapter && adapter.getValue();
switch (chooseType) {
case ButtonGroup.CHOOSE_TYPE_SINGLE:
adapter && adapter.setValue([obj.getValue()]);
break;
case ButtonGroup.CHOOSE_TYPE_MULTI:
if (!obj.isSelected()) {
adapter && adapter.setValue(deepWithout(values, obj.getValue()));
}
values.push(obj.getValue());
adapter && adapter.setValue(values);
break;
default:
break;
case ButtonGroup.CHOOSE_TYPE_SINGLE:
adapter && adapter.setValue([obj.getValue()]);
break;
case ButtonGroup.CHOOSE_TYPE_MULTI:
if (!obj.isSelected()) {
adapter && adapter.setValue(deepWithout(values, obj.getValue()));
}
values.push(obj.getValue());
adapter && adapter.setValue(values);
break;
default:
break;
}
}
this.fireEvent(Searcher.EVENT_CHANGE, value, obj);
@ -149,10 +154,18 @@ export class Searcher extends Widget {
});
}
if (masker && !Maskers.has(this.getName())) {
Maskers.create(this.getName(), adapter, extend({
container: this,
render: this.popupView,
}, masker), this);
Maskers.create(
this.getName(),
adapter,
extend(
{
container: this,
render: this.popupView,
},
masker
),
this
);
}
}
@ -164,14 +177,14 @@ export class Searcher extends Widget {
this.popupView.startSearch && this.popupView.startSearch();
// 搜索前先清空dom
// BI.Maskers.get(this.getName()).empty();
nextTick((name) => {
nextTick(name => {
Maskers.show(name);
}, this.getName());
}
_pauseSearch() {
this._stop = true;
nextTick((name) => {
nextTick(name => {
Maskers.hide(name);
}, this.getName());
if (this._isSearching === true) {
@ -201,7 +214,8 @@ export class Searcher extends Widget {
if (isAutoSearch) {
const items = (adapter && ((adapter.getItems && adapter.getItems()) || adapter.attr("items"))) || [];
const finding = BI.Func.getSearchResult(items, keyword);
const match = finding.match, find = finding.find;
const match = finding.match,
find = finding.find;
this.popupView.populate(find, match, keyword);
isAutoSync && adapter && adapter.getValue && this.popupView.setValue(adapter.getValue());
this.fireEvent(Searcher.EVENT_SEARCHING);
@ -209,23 +223,26 @@ export class Searcher extends Widget {
return;
}
this.popupView.loading && this.popupView.loading();
onSearch({
times: 1,
keyword: keyword,
selectedValues: adapter && adapter.getValue(),
}, (searchResult, matchResult, ...arg) => {
if (!this._stop && keyword === this.editor.getValue()) {
const args = [searchResult, matchResult, ...arg];
if (args.length > 0) {
args.push(keyword);
onSearch(
{
times: 1,
keyword,
selectedValues: adapter && adapter.getValue(),
},
(searchResult, matchResult, ...arg) => {
if (!this._stop && keyword === this.editor.getValue()) {
const args = [searchResult, matchResult, ...arg];
if (args.length > 0) {
args.push(keyword);
}
Maskers.show(this.getName());
this.popupView.populate.apply(this.popupView, args);
isAutoSync && adapter && adapter.getValue && this.popupView.setValue(adapter.getValue());
this.popupView.loaded && this.popupView.loaded();
this.fireEvent(Searcher.EVENT_SEARCHING);
}
Maskers.show(this.getName());
this.popupView.populate.apply(this.popupView, args);
isAutoSync && adapter && adapter.getValue && this.popupView.setValue(adapter.getValue());
this.popupView.loaded && this.popupView.loaded();
this.fireEvent(Searcher.EVENT_SEARCHING);
}
});
);
}
_getLastSearchKeyword() {
@ -251,7 +268,7 @@ export class Searcher extends Widget {
}
stopSearch() {
this._stopSearch();// 先停止搜索,然后再去设置editor为空
this._stopSearch(); // 先停止搜索,然后再去设置editor为空
// important:停止搜索必须退出编辑状态,这里必须加上try(input框不显示时blur会抛异常)
try {
this.editor.blur();

163
src/base/combination/switcher.js

@ -1,3 +1,18 @@
import {
VerticalLayout,
shortcut,
Widget,
Controller,
extend,
nextTick,
createWidget,
each,
debounce,
isNull
} from "@/core";
import { ButtonGroup } from "./group.button";
import { Maskers } from "@/base/0.base";
/**
*
* 切换显示或隐藏面板
@ -6,13 +21,11 @@
* @class BI.Switcher
* @extends BI.Widget
*/
import { shortcut, Widget, Controller, extend, nextTick, createWidget, each, debounce, isNull } from "../../core";
import { Maskers } from "../0.base";
@shortcut()
export class Switcher extends Widget {
static xtype = "bi.switcher";
static EVENT_EXPAND = "EVENT_EXPAND";
static EVENT_COLLAPSE = "EVENT_COLLAPSE";
static EVENT_TRIGGER_CHANGE = "EVENT_TRIGGER_CHANGE";
@ -68,24 +81,25 @@ export class Switcher extends Widget {
}
});
this.element.hover(() => {
if (this.isEnabled() && this.switcher.isEnabled()) {
this.element.addClass(hoverClass);
}
}, () => {
if (this.isEnabled() && this.switcher.isEnabled()) {
this.element.removeClass(hoverClass);
this.element.hover(
() => {
if (this.isEnabled() && this.switcher.isEnabled()) {
this.element.addClass(hoverClass);
}
},
() => {
if (this.isEnabled() && this.switcher.isEnabled()) {
this.element.removeClass(hoverClass);
}
}
});
);
createWidget({
type: "bi.vertical",
type: VerticalLayout.xtype,
scrolly: false,
element: this,
items: [
{ el: this.switcher }
],
items: [{ el: this.switcher }],
});
isDefaultInit && (this._assertPopupView());
isDefaultInit && this._assertPopupView();
}
_toggle() {
@ -104,42 +118,62 @@ export class Switcher extends Widget {
const evs = this.options.trigger.split(",");
each(evs, (i, e) => {
switch (e) {
case "hover":
this.element[e]((e) => {
case "hover":
this.element[e](
e => {
if (this.isEnabled() && this.switcher.isEnabled()) {
this._popupView();
this.fireEvent(Controller.EVENT_CHANGE, BI.Events.EXPAND, "", this.switcher);
this.fireEvent(Switcher.EVENT_EXPAND);
}
}, () => {
},
() => {
if (this.isEnabled() && this.switcher.isEnabled() && toggle) {
this._hideView();
this.fireEvent(Controller.EVENT_CHANGE, BI.Events.COLLAPSE, "", this.switcher);
this.fireEvent(Switcher.EVENT_COLLAPSE);
}
});
break;
default :
if (e) {
this.element.off(e + "." + this.getName()).on(e + "." + this.getName(), debounce((e) => {
if (this.switcher.element.__isMouseInBounds__(e)) {
if (this.isEnabled() && this.switcher.isEnabled()) {
toggle ? this._toggle() : this._popupView();
if (this.isExpanded()) {
this.fireEvent(Controller.EVENT_CHANGE, BI.Events.EXPAND, "", this.switcher);
this.fireEvent(Switcher.EVENT_EXPAND);
} else {
this.fireEvent(Controller.EVENT_CHANGE, BI.Events.COLLAPSE, "", this.switcher);
this.fireEvent(Switcher.EVENT_COLLAPSE);
}
);
break;
default:
if (e) {
this.element.off(`${e}.${this.getName()}`).on(
`${e}.${this.getName()}`,
debounce(
e => {
if (this.switcher.element.__isMouseInBounds__(e)) {
if (this.isEnabled() && this.switcher.isEnabled()) {
toggle ? this._toggle() : this._popupView();
if (this.isExpanded()) {
this.fireEvent(
Controller.EVENT_CHANGE,
BI.Events.EXPAND,
"",
this.switcher
);
this.fireEvent(Switcher.EVENT_EXPAND);
} else {
this.fireEvent(
Controller.EVENT_CHANGE,
BI.Events.COLLAPSE,
"",
this.switcher
);
this.fireEvent(Switcher.EVENT_COLLAPSE);
}
}
}
},
BI.EVENT_RESPONSE_TIME,
{
leading: true,
trailing: false,
}
}, BI.EVENT_RESPONSE_TIME, {
"leading": true,
"trailing": false,
}));
}
break;
)
);
}
break;
}
});
}
@ -153,18 +187,24 @@ export class Switcher extends Widget {
_assertPopupView() {
const { popup, adapter, masker, value, direction } = this.options;
if (!this._created) {
this.popupView = createWidget(popup, {
type: "bi.button_group",
element: adapter && Maskers.create(this.getName(), adapter, extend({ container: this }, masker)),
cls: "switcher-popup",
layouts: [{
type: "bi.vertical",
hgap: 0,
vgap: 0,
}],
value,
}, this);
this.popupView.on(Controller.EVENT_CHANGE, (type, value, obj, ...args) => {
this.popupView = createWidget(
popup,
{
type: ButtonGroup.xtype,
element: adapter && Maskers.create(this.getName(), adapter, extend({ container: this }, masker)),
cls: "switcher-popup",
layouts: [
{
type: VerticalLayout.xtype,
hgap: 0,
vgap: 0,
}
],
value,
},
this
);
this.popupView.on(Controller.EVENT_CHANGE, (type, value, obj, ...args) => {
this.fireEvent(Controller.EVENT_CHANGE, type, value, obj, ...args);
if (type === BI.Events.CLICK) {
this.fireEvent(Switcher.EVENT_CHANGE, value, obj);
@ -172,12 +212,10 @@ export class Switcher extends Widget {
});
if (direction !== BI.Direction.Custom && !adapter) {
createWidget({
type: "bi.vertical",
type: VerticalLayout.xtype,
scrolly: false,
element: this,
items: [
{ el: this.popupView }
],
items: [{ el: this.popupView }],
});
}
this._created = true;
@ -190,9 +228,9 @@ export class Switcher extends Widget {
_hideView() {
this.fireEvent(Switcher.EVENT_BEFORE_HIDEVIEW);
const { adapter, switcherClass } = this.options;
adapter ? Maskers.hide(this.getName()) : (this.popupView && this.popupView.setVisible(false));
adapter ? Maskers.hide(this.getName()) : this.popupView && this.popupView.setVisible(false);
nextTick(() => {
adapter ? Maskers.hide(this.getName()) : (this.popupView && this.popupView.setVisible(false));
adapter ? Maskers.hide(this.getName()) : this.popupView && this.popupView.setVisible(false);
this.element.removeClass(switcherClass);
this.fireEvent(Switcher.EVENT_AFTER_HIDEVIEW);
});
@ -203,7 +241,7 @@ export class Switcher extends Widget {
this._assertPopupView();
this.fireEvent(Switcher.EVENT_BEFORE_POPUPVIEW);
adapter ? Maskers.show(this.getName()) : this.popupView.setVisible(true);
nextTick((name) => {
nextTick(name => {
adapter ? Maskers.show(name) : this.popupView.setVisible(true);
this.element.addClass(switcherClass);
this.fireEvent(Switcher.EVENT_AFTER_POPUPVIEW);
@ -248,8 +286,11 @@ export class Switcher extends Widget {
}
isViewVisible() {
return this.isEnabled() && this.switcher.isEnabled() &&
(this.options.adapter ? Maskers.isVisible(this.getName()) : (this.popupView && this.popupView.isVisible()));
return (
this.isEnabled() &&
this.switcher.isEnabled() &&
(this.options.adapter ? Maskers.isVisible(this.getName()) : this.popupView && this.popupView.isVisible())
);
}
isExpanded() {
@ -290,7 +331,7 @@ export class Switcher extends Widget {
if (this.switcher.getValue() === value) {
return this.switcher;
}
return this.popupView && this.popupView.getNodeByValue(value);
}

55
src/base/combination/tab.js

@ -1,7 +1,23 @@
import { ButtonGroup } from "./group.button";
import {
CardLayout,
shortcut,
Widget,
Controller,
ShowListener,
extend,
createWidget,
isObject,
each,
isFunction,
contains,
any,
isEqual
} from "@/core";
/**
* Created by GUY on 2015/6/26.
*/
import { shortcut, Widget, Controller, ShowListener, extend, createWidget, isObject, each, isFunction, contains, any, isEqual } from "../../core";
@shortcut()
export class Tab extends Widget {
@ -19,9 +35,7 @@ export class Tab extends Widget {
},
showIndex: false,
tab: false,
cardCreator: (v) => {
return createWidget();
},
cardCreator: v => createWidget(),
keepAlives: [],
});
}
@ -29,38 +43,46 @@ export class Tab extends Widget {
render() {
const { tab, direction, logic, cardCreator } = this.options;
if (isObject(tab)) {
this.tab = createWidget(this.options.tab, { type: "bi.button_group" });
this.tab = createWidget(this.options.tab, { type: ButtonGroup.xtype });
this.tab.on(Controller.EVENT_CHANGE, (type, value, obj, ...args) => {
this.fireEvent(Controller.EVENT_CHANGE, type, value, obj, ...args);
});
}
this.cardMap = {};
this.layout = createWidget({
type: "bi.card",
type: CardLayout.xtype,
});
createWidget(extend({
element: this,
}, BI.LogicFactory.createLogic(BI.LogicFactory.createLogicTypeByDirection(direction), extend({}, logic, {
items: BI.LogicFactory.createLogicItemsByDirection(direction, this.tab, this.layout),
}))));
createWidget(
extend(
{
element: this,
},
BI.LogicFactory.createLogic(
BI.LogicFactory.createLogicTypeByDirection(direction),
extend({}, logic, {
items: BI.LogicFactory.createLogicItemsByDirection(direction, this.tab, this.layout),
})
)
)
);
const listener = new ShowListener({
eventObj: this.tab,
cardLayout: this.layout,
cardCreator: (v) => {
cardCreator: v => {
Widget.execWithContext(this, () => {
this.cardMap[v] = cardCreator(v);
});
return this.cardMap[v];
},
afterCardShow: (v) => {
afterCardShow: v => {
this._deleteOtherCards(v);
this.curr = v;
},
});
listener.on(ShowListener.EVENT_CHANGE, (value) => {
listener.on(ShowListener.EVENT_CHANGE, value => {
this.fireEvent(Tab.EVENT_CHANGE, value, this);
});
}
@ -69,7 +91,7 @@ export class Tab extends Widget {
const { single } = this.options;
if (single === true) {
each(this.cardMap, (name, card) => {
if (name !== (currCardName + "") && this._keepAlive(name) !== true) {
if (name !== `${currCardName}` && this._keepAlive(name) !== true) {
this.layout.deleteCardByName(name);
delete this.cardMap[name];
}
@ -122,7 +144,7 @@ export class Tab extends Widget {
removeTab(cardname) {
any(this.cardMap, (name, card) => {
if (isEqual(name, (cardname + ""))) {
if (isEqual(name, `${cardname}`)) {
this.layout.deleteCardByName(name);
delete this.cardMap[name];
@ -179,5 +201,4 @@ export class Tab extends Widget {
this.cardMap = {};
super.destroy(arguments);
}
}

9
src/base/combination/tree.button.js

@ -1,10 +1,11 @@
import { ButtonGroup } from "./group.button";
import { shortcut, Widget, extend, isArray, each, isFunction, deepContains, concat, any, contains } from "@/core";
/**
* Created by GUY on 2015/8/10.
* @class BI.ButtonTree
* @extends BI.ButtonGroup
*/
import { shortcut, Widget, extend, isArray, each, isFunction, deepContains, concat, any, contains } from "../../core";
import { ButtonGroup } from "./group.button";
@shortcut()
export class ButtonTree extends ButtonGroup {
@ -119,7 +120,7 @@ export class ButtonTree extends ButtonGroup {
each(this.buttons, (i, item) => {
if (item.isEnabled() && !isFunction(item.setSelected)) {
btns = btns.concat(item.getNotSelectedButtons());
return;
}
if (item.isSelected && !item.isSelected()) {
@ -167,7 +168,7 @@ export class ButtonTree extends ButtonGroup {
if (item.isEnabled()) {
if (item.attr("id") === id) {
node = item;
return true;
} else if (isFunction(item.getNodeById)) {
node = item.getNodeById(id);

57
src/base/context.js

@ -1,47 +1,40 @@
/**
* 表示当前对象
*
* Created by GUY on 2015/9/7.
* @class BI.EL
* @extends BI.Widget
*/
BI.Context = BI.inherit(BI.Widget, {
props: {
context: "",
watch: {},
el: {},
items: [],
},
import { shortcut, Widget, createWidget, Controller } from "@/core";
render: function () {
var self = this, o = this.options;
@shortcut()
export class Context extends Widget {
static xtype = "bi.context";
props = { context: "", watch: {}, el: {}, items: [] };
render() {
const self = this,
o = this.options;
if (o.context) {
this.context = BI.useContext(o.context);
}
this.widget = BI.createWidget((o.items[0] || o.el)(this.context), {
this.widget = createWidget((o.items[0] || o.el)(this.context), {
element: this,
});
this.widget.on(BI.Controller.EVENT_CHANGE, function () {
self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
this.widget.on(Controller.EVENT_CHANGE, function () {
self.fireEvent(Controller.EVENT_CHANGE, arguments);
});
},
}
__initWatch: function () {
BI.Context.superclass.__initWatch.call(this);
var o = this.options;
__initWatch() {
super.__initWatch.call(this);
const o = this.options;
BI.watch(this.context, o.context, o.watch);
},
}
setValue: function (v) {
setValue(v) {
this.widget.setValue(v);
},
}
getValue: function () {
getValue() {
return this.widget.getValue();
},
}
populate: function () {
populate() {
this.widget.populate.apply(this, arguments);
},
});
BI.shortcut("bi.context", BI.Context);
}
}

48
src/base/el.js

@ -1,38 +1,36 @@
/**
* 表示当前对象
*
* Created by GUY on 2015/9/7.
* @class BI.EL
* @extends BI.Widget
*/
BI.EL = BI.inherit(BI.Widget, {
_defaultConfig: function () {
return BI.extend(BI.EL.superclass._defaultConfig.apply(this, arguments), {
import { shortcut, Widget, extend, createWidget, Controller } from "@/core";
@shortcut()
export class EL extends Widget {
static xtype = "bi.el";
_defaultConfig() {
return extend(super._defaultConfig(...arguments), {
baseCls: "bi-el",
el: {},
});
},
}
render: function () {
var self = this, o = this.options;
this.ele = BI.createWidget(o.el, {
render() {
const self = this,
o = this.options;
this.ele = createWidget(o.el, {
element: this,
});
this.ele.on(BI.Controller.EVENT_CHANGE, function () {
self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
this.ele.on(Controller.EVENT_CHANGE, function () {
self.fireEvent(Controller.EVENT_CHANGE, arguments);
});
},
}
setValue: function (v) {
setValue(v) {
this.ele.setValue(v);
},
}
getValue: function () {
getValue() {
return this.ele.getValue();
},
}
populate: function () {
populate() {
this.ele.populate.apply(this, arguments);
},
});
BI.shortcut("bi.el", BI.EL);
}
}

175
src/base/foundation/message.js

@ -3,26 +3,26 @@
* 弹出提示消息框用于模拟阻塞操作通过回调函数实现
* @class BI.Msg
*/
import { Widget, isString, isNull, isFunction, createWidget, remove, each } from "../../core"
import { Widget, isString, isNull, isFunction, createWidget, remove, each } from "../../core";
export const Msg = ((() => {
export const Msg = (() => {
let $mask, $pop;
let messageShows = [];
const messageShows = [];
let toastStack = [];
const toastStack = [];
return {
alert: function (title, message, callback) {
alert (title, message, callback) {
this._show(false, title, message, callback);
},
confirm: function (title, message, callback) {
confirm (title, message, callback) {
this._show(true, title, message, callback);
},
prompt: function (title, message, value, callback, min_width) {
prompt (title, message, value, callback, min_width) {
// BI.Msg.prompt(title, message, value, callback, min_width);
},
toast: function (message, options, context) {
toast (message, options, context) {
isString(options) && (options = { level: options });
options = options || {};
context = context || Widget._renderEngine.createElement("body");
@ -32,69 +32,81 @@ export const Msg = ((() => {
const toast = createWidget({
type: "bi.toast",
cls: "bi-message-animate bi-message-leave",
level: level,
autoClose: autoClose,
level,
autoClose,
closable: options.closable,
text: message,
listeners: [{
eventName: BI.Toast.EVENT_DESTORY,
action: function () {
remove(toastStack, toast.element);
let _height = BI.SIZE_CONSANTS.TOAST_TOP;
each(toastStack, function (i, element) {
element.css({ "top": _height });
_height += element.outerHeight() + 10;
});
callback();
},
}],
listeners: [
{
eventName: BI.Toast.EVENT_DESTORY,
action () {
remove(toastStack, toast.element);
let _height = BI.SIZE_CONSANTS.TOAST_TOP;
each(toastStack, (i, element) => {
element.css({ top: _height });
_height += element.outerHeight() + 10;
});
callback();
},
}
],
});
let height = BI.SIZE_CONSANTS.TOAST_TOP;
each(toastStack, function (i, element) {
each(toastStack, (i, element) => {
height += element.outerHeight() + 10;
});
createWidget({
type: "bi.absolute",
element: context,
items: [{
el: toast,
left: "50%",
top: height,
}],
items: [
{
el: toast,
left: "50%",
top: height,
}
],
});
toastStack.push(toast.element);
toast.element.css({ "margin-left": -1 * toast.element.outerWidth() / 2 });
toast.element.css({ "margin-left": (-1 * toast.element.outerWidth()) / 2 });
toast.element.removeClass("bi-message-leave").addClass("bi-message-enter");
autoClose && BI.delay(function () {
toast.element.removeClass("bi-message-enter").addClass("bi-message-leave");
toast.destroy?.();
}, 5000);
autoClose &&
BI.delay(() => {
toast.element.removeClass("bi-message-enter").addClass("bi-message-leave");
toast.destroy?.();
}, 5000);
return function () {
toast.element.removeClass("bi-message-enter").addClass("bi-message-leave");
toast.destroy?.();
};
},
_show: function (hasCancel, title, message, callback) {
isNull($mask) && ($mask = Widget._renderEngine.createElement("<div class=\"bi-z-index-mask\">").css({
position: "absolute",
zIndex: BI.zIndex_tip - 2,
top: 0,
left: 0,
right: 0,
bottom: 0,
opacity: 0.5,
}).appendTo("body"));
$pop = Widget._renderEngine.createElement("<div class=\"bi-message-depend\">").css({
position: "absolute",
zIndex: BI.zIndex_tip - 1,
top: 0,
left: 0,
right: 0,
bottom: 0,
}).appendTo("body");
function close () {
_show (hasCancel, title, message, callback) {
isNull($mask) &&
($mask = Widget._renderEngine
.createElement("<div class=\"bi-z-index-mask\">")
.css({
position: "absolute",
zIndex: BI.zIndex_tip - 2,
top: 0,
left: 0,
right: 0,
bottom: 0,
opacity: 0.5,
})
.appendTo("body"));
$pop = Widget._renderEngine
.createElement("<div class=\"bi-message-depend\">")
.css({
position: "absolute",
zIndex: BI.zIndex_tip - 1,
top: 0,
left: 0,
right: 0,
bottom: 0,
})
.appendTo("body");
function close() {
messageShows[messageShows.length - 1].destroy();
messageShows.pop();
if (messageShows.length === 0) {
@ -102,14 +114,14 @@ export const Msg = ((() => {
$mask = null;
}
}
let controlItems = [];
const controlItems = [];
if (hasCancel === true) {
controlItems.push({
el: {
type: "bi.button",
text: BI.i18nText("BI-Basic_Cancel"),
level: "ignore",
handler: function () {
handler () {
close();
if (isFunction(callback)) {
callback.apply(null, [false]);
@ -122,7 +134,7 @@ export const Msg = ((() => {
el: {
type: "bi.button",
text: BI.i18nText("BI-Basic_OK"),
handler: function () {
handler () {
close();
if (isFunction(callback)) {
callback.apply(null, [true]);
@ -139,8 +151,8 @@ export const Msg = ((() => {
attributes: {
tabIndex: 1,
},
mounted: function () {
this.element.keyup(function (e) {
mounted () {
this.element.keyup(e => {
if (e.keyCode === BI.KeyCode.ENTER) {
close();
if (isFunction(callback)) {
@ -157,9 +169,7 @@ export const Msg = ((() => {
});
try {
this.element.focus();
} catch (e) {
}
} catch (e) {}
},
cls: "bi-card",
items: {
@ -183,7 +193,7 @@ export const Msg = ((() => {
type: "bi.icon_button",
cls: "bi-message-close close-font",
// height: 50,
handler: function () {
handler () {
close();
if (isFunction(callback)) {
callback.apply(null, [false]);
@ -197,29 +207,32 @@ export const Msg = ((() => {
height: 40,
},
center: {
el: BI.isPlainObject(message) ? message : {
type: "bi.label",
vgap: 10,
hgap: 20,
whiteSpace: "normal",
text: message,
},
el: BI.isPlainObject(message)
? message
: {
type: "bi.label",
vgap: 10,
hgap: 20,
whiteSpace: "normal",
text: message,
},
},
south: {
el: {
type: "bi.absolute",
items: [{
el: {
type: "bi.right_vertical_adapt",
lgap: 10,
items: controlItems,
},
top: 0,
left: 20,
right: 20,
bottom: 0,
}],
items: [
{
el: {
type: "bi.right_vertical_adapt",
lgap: 10,
items: controlItems,
},
top: 0,
left: 20,
right: 20,
bottom: 0,
}
],
},
height: 44,
},
@ -233,4 +246,4 @@ export const Msg = ((() => {
messageShows[messageShows.length] = createWidget(conf);
},
};
})());
})();

164
src/base/grid/grid.js

@ -1,3 +1,22 @@
import {
VerticalLayout,
AbsoluteLayout,
Widget,
shortcut,
extend,
emptyFn,
debounce,
_lazyCreateWidget,
isFunction,
each,
isNumber,
ScalingCellSizeAndPositionManager,
clamp,
isEmpty,
nextTick
} from "@/core";
import { Label } from "../single";
/**
* GridView
*
@ -5,7 +24,7 @@
* @class BI.GridView
* @extends BI.Widget
*/
import { Widget, shortcut, extend, emptyFn, debounce, _lazyCreateWidget, isFunction, each, isNumber, ScalingCellSizeAndPositionManager, clamp, isEmpty, nextTick } from "../../core";
@shortcut()
export class GridView extends Widget {
_defaultConfig() {
@ -19,7 +38,7 @@ export class GridView extends Widget {
overflowX: true,
overflowY: true,
el: {
type: "bi.vertical",
type: VerticalLayout.xtype,
},
overscanColumnCount: 0,
overscanRowCount: 0,
@ -48,7 +67,7 @@ export class GridView extends Widget {
this._scrollLock = false;
}, 1000 / 60);
this.container = _lazyCreateWidget({
type: "bi.absolute",
type: AbsoluteLayout.xtype,
});
this.element.scroll(() => {
if (this._scrollLock === true) {
@ -64,7 +83,8 @@ export class GridView extends Widget {
});
// 兼容一下
let scrollable = o.scrollable;
const scrollx = o.scrollx, scrolly = o.scrolly;
const scrollx = o.scrollx,
scrolly = o.scrolly;
if (overflowX === false) {
if (overflowY === false) {
scrollable = false;
@ -77,16 +97,18 @@ export class GridView extends Widget {
}
}
_lazyCreateWidget(el, {
type: "bi.vertical",
type: VerticalLayout.xtype,
element: this,
scrollable,
scrolly,
scrollx,
items: [this.container],
});
o.items = isFunction(o.items) ? this.__watch(o.items, (context, newValue) => {
this.populate(newValue);
}) : o.items;
o.items = isFunction(o.items)
? this.__watch(o.items, (context, newValue) => {
this.populate(newValue);
})
: o.items;
if (o.items.length > 0) {
this._calculateSizeAndPositionData();
this._populate();
@ -109,7 +131,15 @@ export class GridView extends Widget {
}
_calculateSizeAndPositionData() {
const { columnCount, items, rowCount, columnWidthGetter, estimatedColumnSize, rowHeightGetter, estimatedRowSize } = this.options;
const {
columnCount,
items,
rowCount,
columnWidthGetter,
estimatedColumnSize,
rowHeightGetter,
estimatedRowSize,
} = this.options;
this.rowCount = 0;
this.columnCount = 0;
if (isNumber(columnCount)) {
@ -122,8 +152,16 @@ export class GridView extends Widget {
} else {
this.rowCount = items.length;
}
this._columnSizeAndPositionManager = new ScalingCellSizeAndPositionManager(this.columnCount, columnWidthGetter, estimatedColumnSize);
this._rowSizeAndPositionManager = new ScalingCellSizeAndPositionManager(this.rowCount, rowHeightGetter, estimatedRowSize);
this._columnSizeAndPositionManager = new ScalingCellSizeAndPositionManager(
this.columnCount,
columnWidthGetter,
estimatedColumnSize
);
this._rowSizeAndPositionManager = new ScalingCellSizeAndPositionManager(
this.rowCount,
rowHeightGetter,
estimatedRowSize
);
}
_getOverscanIndices(cellCount, overscanCellsCount, startIndex, stopIndex) {
@ -138,19 +176,30 @@ export class GridView extends Widget {
const { itemFormatter, items } = this.options;
const width = o.width, height = o.height, scrollLeft = clamp(o.scrollLeft, 0, this._getMaxScrollLeft()),
const width = o.width,
height = o.height,
scrollLeft = clamp(o.scrollLeft, 0, this._getMaxScrollLeft()),
scrollTop = clamp(o.scrollTop, 0, this._getMaxScrollTop()),
overscanColumnCount = o.overscanColumnCount, overscanRowCount = o.overscanRowCount;
overscanColumnCount = o.overscanColumnCount,
overscanRowCount = o.overscanRowCount;
if (height > 0 && width > 0) {
const visibleColumnIndices = this._columnSizeAndPositionManager.getVisibleCellRange(width, scrollLeft);
const visibleRowIndices = this._rowSizeAndPositionManager.getVisibleCellRange(height, scrollTop);
const renderedCells = [], renderedKeys = {}, renderedWidgets = {};
let minX = this._getMaxScrollLeft(), minY = this._getMaxScrollTop(), maxX = 0, maxY = 0;
const renderedCells = [],
renderedKeys = {},
renderedWidgets = {};
let minX = this._getMaxScrollLeft(),
minY = this._getMaxScrollTop(),
maxX = 0,
maxY = 0;
// 没有可见的单元格就干掉所有渲染过的
if (!isEmpty(visibleColumnIndices) && !isEmpty(visibleRowIndices)) {
const horizontalOffsetAdjustment = this._columnSizeAndPositionManager.getOffsetAdjustment(width, scrollLeft);
const horizontalOffsetAdjustment = this._columnSizeAndPositionManager.getOffsetAdjustment(
width,
scrollLeft
);
const verticalOffsetAdjustment = this._rowSizeAndPositionManager.getOffsetAdjustment(height, scrollTop);
this._renderedColumnStartIndex = visibleColumnIndices.start;
@ -158,9 +207,19 @@ export class GridView extends Widget {
this._renderedRowStartIndex = visibleRowIndices.start;
this._renderedRowStopIndex = visibleRowIndices.stop;
const overscanColumnIndices = this._getOverscanIndices(this.columnCount, overscanColumnCount, this._renderedColumnStartIndex, this._renderedColumnStopIndex);
const overscanColumnIndices = this._getOverscanIndices(
this.columnCount,
overscanColumnCount,
this._renderedColumnStartIndex,
this._renderedColumnStopIndex
);
const overscanRowIndices = this._getOverscanIndices(this.rowCount, overscanRowCount, this._renderedRowStartIndex, this._renderedRowStopIndex);
const overscanRowIndices = this._getOverscanIndices(
this.rowCount,
overscanRowCount,
this._renderedRowStartIndex,
this._renderedRowStopIndex
);
const columnStartIndex = overscanColumnIndices.overscanStartIndex;
const columnStopIndex = overscanColumnIndices.overscanStopIndex;
@ -177,7 +236,12 @@ export class GridView extends Widget {
const bottom = maxRowDatum.offset + verticalOffsetAdjustment + maxRowDatum.size;
const right = maxColumnDatum.offset + horizontalOffsetAdjustment + maxColumnDatum.size;
// 如果滚动的区间并没有超出渲染的范围
if (top >= this.renderRange.minY && bottom <= this.renderRange.maxY && left >= this.renderRange.minX && right <= this.renderRange.maxX) {
if (
top >= this.renderRange.minY &&
bottom <= this.renderRange.maxY &&
left >= this.renderRange.minX &&
right <= this.renderRange.maxX
) {
return;
}
@ -195,23 +259,38 @@ export class GridView extends Widget {
this.renderedCells[index].el.setWidth(columnDatum.size);
this.renderedCells[index].el.setHeight(rowDatum.size);
// 这里只使用px
this.renderedCells[index].el.element.css("left", `${columnDatum.offset + horizontalOffsetAdjustment}px`);
this.renderedCells[index].el.element.css("top", `${rowDatum.offset + verticalOffsetAdjustment}px`);
this.renderedCells[index].el.element.css(
"left",
`${columnDatum.offset + horizontalOffsetAdjustment}px`
);
this.renderedCells[index].el.element.css(
"top",
`${rowDatum.offset + verticalOffsetAdjustment}px`
);
child = this.renderedCells[index].el;
renderedCells.push(this.renderedCells[index]);
} else {
const item = itemFormatter(items[rowIndex][columnIndex], rowIndex, columnIndex);
child = _lazyCreateWidget(extend({
type: "bi.label",
width: columnDatum.size,
height: rowDatum.size,
}, item, {
cls: `${item.cls || ""} grid-cell${rowIndex === 0 ? " first-row" : ""}${columnIndex === 0 ? " first-col" : ""}`,
_rowIndex: rowIndex,
_columnIndex: columnIndex,
_left: columnDatum.offset + horizontalOffsetAdjustment,
_top: rowDatum.offset + verticalOffsetAdjustment,
}), this);
child = _lazyCreateWidget(
extend(
{
type: Label.xtype,
width: columnDatum.size,
height: rowDatum.size,
},
item,
{
cls: `${item.cls || ""} grid-cell${rowIndex === 0 ? " first-row" : ""}${
columnIndex === 0 ? " first-col" : ""
}`,
_rowIndex: rowIndex,
_columnIndex: columnIndex,
_left: columnDatum.offset + horizontalOffsetAdjustment,
_top: rowDatum.offset + verticalOffsetAdjustment,
}
),
this
);
renderedCells.push({
el: child,
left: `${columnDatum.offset + horizontalOffsetAdjustment}px`,
@ -233,7 +312,9 @@ export class GridView extends Widget {
}
}
// 已存在的, 需要添加的和需要删除的
const existSet = {}, addSet = {}, deleteArray = [];
const existSet = {},
addSet = {},
deleteArray = [];
each(renderedKeys, (i, key) => {
if (this.renderedKeys[i]) {
existSet[i] = key;
@ -281,7 +362,7 @@ export class GridView extends Widget {
if (scrollable === true || scrollable === "xy" || scrollable === "x") {
return true;
}
return false;
}
@ -298,16 +379,22 @@ export class GridView extends Widget {
if (scrollable === true || scrollable === "xy" || scrollable === "y") {
return true;
}
return false;
}
_getMaxScrollLeft() {
return Math.max(0, this._getContainerWidth() - this.options.width + (this._isOverflowX() ? BI.DOM.getScrollWidth() : 0));
return Math.max(
0,
this._getContainerWidth() - this.options.width + (this._isOverflowX() ? BI.DOM.getScrollWidth() : 0)
);
}
_getMaxScrollTop() {
return Math.max(0, this._getContainerHeight() - this.options.height + (this._isOverflowY() ? BI.DOM.getScrollWidth() : 0));
return Math.max(
0,
this._getContainerHeight() - this.options.height + (this._isOverflowY() ? BI.DOM.getScrollWidth() : 0)
);
}
_getContainerWidth() {
@ -333,8 +420,7 @@ export class GridView extends Widget {
try {
this.element.scrollTop(scrollTop);
this.element.scrollLeft(scrollLeft);
} catch (e) {
}
} catch (e) {}
this._calculateChildrenToRender();
}

9
src/base/index.js

@ -29,11 +29,4 @@ export * from "./combination";
export * from "./layer";
export * from "./list";
export * from "./single";
export {
Pane,
GridView,
Pager,
Msg,
CollectionView,
CustomTree
};
export { Pane, GridView, Pager, Msg, CollectionView, CustomTree };

457
src/base/layer/layer.drawer.js

@ -1,236 +1,253 @@
import { HTapeLayout, AbsoluteLayout, Layout, VerticalLayout, Widget, shortcut, isPlainObject, extend } from "@/core";
import { Label, IconButton } from "../single";
/**
* Popover弹出层
* @class BI.Popover
* @extends BI.Widget
*/
import { Widget, shortcut, isPlainObject, extend } from "../../core";
@shortcut()
export class Drawer extends Widget {
SIZE = {
SMALL: "small",
NORMAL: "normal",
BIG: "big",
}
props = {
baseCls: "bi-drawer bi-card",
size: "normal",
placement: "right", // top/bottom/left/right
header: null,
headerHeight: 40,
body: null,
closable: true, // BI-40839 是否显示右上角的关闭按钮
bodyHgap: 20,
bodyTgap: 10,
bodyBgap: 10,
}
static xtype = "bi.drawer";
static EVENT_CLOSE = "EVENT_CLOSE";
static EVENT_OPEN = "EVENT_OPEN";
_getSuitableSize() {
const { size, height, placement, width } = this.options;
let sizeValue = 0;
switch (size) {
case "big":
sizeValue = 736;
break;
case "small":
sizeValue = 200;
break;
case "normal":
default:
sizeValue = 378;
break;
}
if (placement === "top" || placement === "bottom") {
return {
height: height || sizeValue,
};
}
if (placement === "left" || placement === "right") {
return {
width: width || sizeValue,
};
}
}
render() {
const { header, headerHeight, closable, body, bodyHgap, bodyTgap, bodyBgap } = this.options;
const items = [{
el: {
type: "bi.htape",
cls: "bi-message-title bi-header-background",
items: [{
type: "bi.absolute",
items: [{
el: isPlainObject(header) ? extend({}, header, {
extraCls: "bi-font-bold",
}) : {
type: "bi.label",
cls: "bi-font-bold",
height: headerHeight,
text: header,
title: header,
textAlign: "left",
},
left: 20,
top: 0,
right: 0,
bottom: 0,
}],
}, {
el: closable ? {
type: "bi.icon_button",
cls: "bi-message-close close-font",
height: headerHeight,
handler: () => {
this.close();
},
} : {
type: "bi.layout",
},
width: 56,
}],
height: headerHeight,
},
height: headerHeight,
}, {
el: {
type: "bi.vertical",
scrolly: true,
cls: "drawer-body",
ref: _ref => {
this.body = _ref;
},
items: [{
el: body,
}],
},
hgap: bodyHgap,
tgap: bodyTgap,
bgap: bodyBgap,
}];
SIZE = {
SMALL: "small",
NORMAL: "normal",
BIG: "big",
};
props = {
baseCls: "bi-drawer bi-card",
size: "normal",
placement: "right", // top/bottom/left/right
header: null,
headerHeight: 40,
body: null,
closable: true, // BI-40839 是否显示右上角的关闭按钮
bodyHgap: 20,
bodyTgap: 10,
bodyBgap: 10,
};
static xtype = "bi.drawer";
static EVENT_CLOSE = "EVENT_CLOSE";
static EVENT_OPEN = "EVENT_OPEN";
_getSuitableSize() {
const { size, height, placement, width } = this.options;
let sizeValue = 0;
switch (size) {
case "big":
sizeValue = 736;
break;
case "small":
sizeValue = 200;
break;
case "normal":
default:
sizeValue = 378;
break;
}
if (placement === "top" || placement === "bottom") {
return {
height: height || sizeValue,
};
}
if (placement === "left" || placement === "right") {
return {
width: width || sizeValue,
};
}
}
render() {
const { header, headerHeight, closable, body, bodyHgap, bodyTgap, bodyBgap } = this.options;
const items = [
{
el: {
type: HTapeLayout.xtype,
cls: "bi-message-title bi-header-background",
items: [
{
type: AbsoluteLayout.xtype,
items: [
{
el: isPlainObject(header)
? extend({}, header, {
extraCls: "bi-font-bold",
})
: {
type: Label.xtype,
cls: "bi-font-bold",
height: headerHeight,
text: header,
title: header,
textAlign: "left",
},
left: 20,
top: 0,
right: 0,
bottom: 0,
}
],
},
{
el: closable
? {
type: IconButton.xtype,
cls: "bi-message-close close-font",
height: headerHeight,
handler: () => {
this.close();
},
}
: {
type: Layout.xtype,
},
width: 56,
}
],
height: headerHeight,
},
height: headerHeight,
},
{
el: {
type: VerticalLayout.xtype,
scrolly: true,
cls: "drawer-body",
ref: _ref => {
this.body = _ref;
},
items: [
{
el: body,
}
],
},
hgap: bodyHgap,
tgap: bodyTgap,
bgap: bodyBgap,
}
];
return extend({
type: "bi.vtape",
items,
}, this._getSuitableSize());
}
mounted() {
const { placement } = this.options;
switch (placement) {
case "right":
this.element.css({
top: 0,
left: "100%",
bottom: 0,
});
break;
case "left":
this.element.css({
top: 0,
right: "100%",
bottom: 0,
});
break;
case "top":
this.element.css({
left: 0,
right: 0,
bottom: "100%",
});
break;
case "bottom":
this.element.css({
left: 0,
right: 0,
top: "100%",
});
break;
default:
break;
}
}
return extend(
{
type: "bi.vtape",
items,
},
this._getSuitableSize()
);
}
mounted() {
const { placement } = this.options;
switch (placement) {
case "right":
this.element.css({
top: 0,
left: "100%",
bottom: 0,
});
break;
case "left":
this.element.css({
top: 0,
right: "100%",
bottom: 0,
});
break;
case "top":
this.element.css({
left: 0,
right: 0,
bottom: "100%",
});
break;
case "bottom":
this.element.css({
left: 0,
right: 0,
top: "100%",
});
break;
default:
break;
}
}
show(callback) {
const { placement } = this.options;
requestAnimationFrame(() => {
const size = this._getSuitableSize();
switch (placement) {
case "right":
this.element.css({
left: `calc(100% - ${size.width}px)`,
});
break;
case "left":
this.element.css({
right: `calc(100% - ${size.width}px)`,
});
break;
case "top":
this.element.css({
bottom: `calc(100% - ${size.height}px)`,
});
break;
case "bottom":
this.element.css({
top: `calc(100% - ${size.height}px)`,
});
break;
default:
break;
}
callback && callback();
});
}
show(callback) {
const { placement } = this.options;
requestAnimationFrame(() => {
const size = this._getSuitableSize();
switch (placement) {
case "right":
this.element.css({
left: `calc(100% - ${size.width}px)`,
});
break;
case "left":
this.element.css({
right: `calc(100% - ${size.width}px)`,
});
break;
case "top":
this.element.css({
bottom: `calc(100% - ${size.height}px)`,
});
break;
case "bottom":
this.element.css({
top: `calc(100% - ${size.height}px)`,
});
break;
default:
break;
}
callback && callback();
});
}
hide(callback) {
const { placement } = this.options;
requestAnimationFrame(() => {
switch (placement) {
case "right":
this.element.css({
left: "100%",
});
break;
case "left":
this.element.css({
right: "100%",
});
break;
case "top":
this.element.css({
bottom: "100%",
});
break;
case "bottom":
this.element.css({
top: "100%",
});
break;
default:
break;
}
setTimeout(callback, 300);
});
}
hide(callback) {
const { placement } = this.options;
requestAnimationFrame(() => {
switch (placement) {
case "right":
this.element.css({
left: "100%",
});
break;
case "left":
this.element.css({
right: "100%",
});
break;
case "top":
this.element.css({
bottom: "100%",
});
break;
case "bottom":
this.element.css({
top: "100%",
});
break;
default:
break;
}
setTimeout(callback, 300);
});
}
open() {
this.show(() => {
this.fireEvent(Drawer.EVENT_OPEN);
});
}
open() {
this.show(() => {
this.fireEvent(Drawer.EVENT_OPEN);
});
}
close() {
this.hide(() => {
this.fireEvent(Drawer.EVENT_CLOSE);
});
}
close() {
this.hide(() => {
this.fireEvent(Drawer.EVENT_CLOSE);
});
}
setZindex(zindex) {
this.element.css({ "z-index": zindex });
}
setZindex(zindex) {
this.element.css({ "z-index": zindex });
}
destroyed() {
}
destroyed() {}
}

552
src/base/layer/layer.popover.js

@ -1,279 +1,331 @@
import {
HTapeLayout,
AbsoluteLayout,
VerticalLayout,
Widget,
shortcut,
clamp,
isPlainObject,
extend,
isNotNull
} from "@/core";
import { Label, IconButton, Button } from "../single";
/**
* Popover弹出层
* @class BI.Popover
* @extends BI.Widget
*/
import { Widget, shortcut, clamp, isPlainObject, extend, isNotNull } from "../../core";
@shortcut()
export class Popover extends Widget {
_constant = {
SIZE: {
SMALL: "small",
NORMAL: "normal",
BIG: "big",
},
MAX_HEIGHT: 600,
}
props() {
return {
baseCls: "bi-popover bi-card bi-border-radius",
size: "normal", // small, normal, big
logic: {
dynamic: false,
},
header: null,
headerHeight: 40,
body: null,
footer: null,
footerHeight: 44,
closable: true, // BI-40839 是否显示右上角的关闭按钮
bodyHgap: BI.SIZE_CONSANTS.H_GAP_SIZE,
bodyTgap: BI.SIZE_CONSANTS.V_GAP_SIZE,
};
}
_constant = {
SIZE: {
SMALL: "small",
NORMAL: "normal",
BIG: "big",
},
MAX_HEIGHT: 600,
};
static xtype = "bi.popover";
static EVENT_CLOSE = "EVENT_CLOSE";
static EVENT_OPEN = "EVENT_OPEN";
static EVENT_CANCEL = "EVENT_CANCEL";
static EVENT_CONFIRM = "EVENT_CONFIRM";
props() {
return {
baseCls: "bi-popover bi-card bi-border-radius",
size: "normal", // small, normal, big
logic: {
dynamic: false,
},
header: null,
headerHeight: 40,
body: null,
footer: null,
footerHeight: 44,
closable: true, // BI-40839 是否显示右上角的关闭按钮
bodyHgap: BI.SIZE_CONSANTS.H_GAP_SIZE,
bodyTgap: BI.SIZE_CONSANTS.V_GAP_SIZE,
};
}
render() {
// var self = this;
const { header, headerHeight, closable, logic, footer, footerHeight, body, bodyTgap, bodyHgap } = this.options;
const c = this._constant;
this.startX = 0;
this.startY = 0;
const size = this._calculateSize();
this.tracker = new BI.MouseMoveTracker((deltaX, deltaY) => {
const W = Widget._renderEngine.createElement("body").width();
const H = Widget._renderEngine.createElement("body").height();
this.startX += deltaX;
this.startY += deltaY;
this.element.css({
left: `${clamp(this.startX, 0, W - this.element.width())}px`,
top: `${clamp(this.startY, 0, H - this.element.height())}px`,
});
// BI-12134 没有什么特别好的方法
BI.Resizers._resize({
target: this.element[0],
});
}, () => {
this.tracker.releaseMouseMoves();
}, _global);
const items = [{
el: {
type: "bi.htape",
cls: "bi-message-title bi-header-background",
items: [{
el: {
type: "bi.absolute",
ref: _ref => {
this.dragger = _ref;
},
items: [{
el: isPlainObject(header) ? extend({}, header, {
extraCls: "bi-font-bold",
}) : {
type: "bi.label",
cls: "bi-font-bold",
height: headerHeight,
text: header,
title: header,
textAlign: "left",
},
top: 0,
bottom: 0,
left: BI.SIZE_CONSANTS.H_GAP_SIZE,
right: closable ? 0 : BI.SIZE_CONSANTS.H_GAP_SIZE,
}],
},
}, closable ? {
el: {
type: "bi.icon_button",
cls: "bi-message-close close-font",
height: headerHeight,
handler: () => {
this.close();
},
},
width: 56,
} : null],
height: headerHeight,
},
height: headerHeight,
}, logic.dynamic ? {
el: {
type: "bi.vertical",
scrolly: true,
cls: "popover-body",
ref: _ref => {
this.body = _ref;
},
css: {
"max-height": this._getSuitableBodyHeight(c.MAX_HEIGHT - headerHeight - (footer ? footerHeight : 0) - bodyTgap),
"min-height": this._getSuitableBodyHeight(size.height - headerHeight - (footer ? footerHeight : 0) - bodyTgap),
},
items: [{
el: body,
}],
hgap: bodyHgap,
tgap: bodyTgap,
},
} : {
el: {
type: "bi.absolute",
items: [{
el: body,
left: bodyHgap,
top: bodyTgap,
right: bodyHgap,
bottom: 0,
}],
},
}];
if (footer) {
items.push({
el: {
type: "bi.absolute",
items: [{
el: footer,
left: BI.SIZE_CONSANTS.H_GAP_SIZE,
top: 0,
right: BI.SIZE_CONSANTS.H_GAP_SIZE,
bottom: 0,
}],
height: footerHeight,
},
height: footerHeight,
});
}
static xtype = "bi.popover";
static EVENT_CLOSE = "EVENT_CLOSE";
static EVENT_OPEN = "EVENT_OPEN";
static EVENT_CANCEL = "EVENT_CANCEL";
static EVENT_CONFIRM = "EVENT_CONFIRM";
return extend({
items,
width: this._getSuitableWidth(size.width),
}, logic.dynamic ? {
type: "bi.vertical",
scrolly: false,
} : {
type: "bi.vtape",
height: this._getSuitableHeight(size.height),
});
}
// mounted之后绑定事件
mounted() {
this.dragger.element.mousedown(e => {
if (this.options.draggable !== false) {
this.startX = this.element[0].offsetLeft;
this.startY = this.element[0].offsetTop;
this.tracker.captureMouseMoves(e);
}
});
}
render() {
// var self = this;
const { header, headerHeight, closable, logic, footer, footerHeight, body, bodyTgap, bodyHgap } = this.options;
const c = this._constant;
this.startX = 0;
this.startY = 0;
const size = this._calculateSize();
this.tracker = new BI.MouseMoveTracker(
(deltaX, deltaY) => {
const W = Widget._renderEngine.createElement("body").width();
const H = Widget._renderEngine.createElement("body").height();
this.startX += deltaX;
this.startY += deltaY;
this.element.css({
left: `${clamp(this.startX, 0, W - this.element.width())}px`,
top: `${clamp(this.startY, 0, H - this.element.height())}px`,
});
// BI-12134 没有什么特别好的方法
BI.Resizers._resize({
target: this.element[0],
});
},
() => {
this.tracker.releaseMouseMoves();
},
_global
);
const items = [
{
el: {
type: HTapeLayout.xtype,
cls: "bi-message-title bi-header-background",
items: [
{
el: {
type: AbsoluteLayout.xtype,
ref: _ref => {
this.dragger = _ref;
},
items: [
{
el: isPlainObject(header)
? extend({}, header, {
extraCls: "bi-font-bold",
})
: {
type: Label.xtype,
cls: "bi-font-bold",
height: headerHeight,
text: header,
title: header,
textAlign: "left",
},
top: 0,
bottom: 0,
left: BI.SIZE_CONSANTS.H_GAP_SIZE,
right: closable ? 0 : BI.SIZE_CONSANTS.H_GAP_SIZE,
}
],
},
},
closable
? {
el: {
type: IconButton.xtype,
cls: "bi-message-close close-font",
height: headerHeight,
handler: () => {
this.close();
},
},
width: 56,
}
: null
],
height: headerHeight,
},
height: headerHeight,
},
logic.dynamic
? {
el: {
type: VerticalLayout.xtype,
scrolly: true,
cls: "popover-body",
ref: _ref => {
this.body = _ref;
},
css: {
"max-height": this._getSuitableBodyHeight(
c.MAX_HEIGHT - headerHeight - (footer ? footerHeight : 0) - bodyTgap
),
"min-height": this._getSuitableBodyHeight(
size.height - headerHeight - (footer ? footerHeight : 0) - bodyTgap
),
},
items: [
{
el: body,
}
],
hgap: bodyHgap,
tgap: bodyTgap,
},
}
: {
el: {
type: AbsoluteLayout.xtype,
items: [
{
el: body,
left: bodyHgap,
top: bodyTgap,
right: bodyHgap,
bottom: 0,
}
],
},
}
];
if (footer) {
items.push({
el: {
type: AbsoluteLayout.xtype,
items: [
{
el: footer,
left: BI.SIZE_CONSANTS.H_GAP_SIZE,
top: 0,
right: BI.SIZE_CONSANTS.H_GAP_SIZE,
bottom: 0,
}
],
height: footerHeight,
},
height: footerHeight,
});
}
_getSuitableBodyHeight(height) {
const { headerHeight, footer, footerHeight, bodyTgap } = this.options;
return extend(
{
items,
width: this._getSuitableWidth(size.width),
},
logic.dynamic
? {
type: VerticalLayout.xtype,
scrolly: false,
}
: {
type: "bi.vtape",
height: this._getSuitableHeight(size.height),
}
);
}
// mounted之后绑定事件
mounted() {
this.dragger.element.mousedown(e => {
if (this.options.draggable !== false) {
this.startX = this.element[0].offsetLeft;
this.startY = this.element[0].offsetTop;
this.tracker.captureMouseMoves(e);
}
});
}
return clamp(height, 0, Widget._renderEngine.createElement("body")[0].clientHeight - headerHeight - (footer ? footerHeight : 0) - bodyTgap);
}
_getSuitableBodyHeight(height) {
const { headerHeight, footer, footerHeight, bodyTgap } = this.options;
_getSuitableHeight(height) {
return clamp(height, 0, Widget._renderEngine.createElement("body")[0].clientHeight);
}
return clamp(
height,
0,
Widget._renderEngine.createElement("body")[0].clientHeight -
headerHeight -
(footer ? footerHeight : 0) -
bodyTgap
);
}
_getSuitableWidth(width) {
return clamp(width, 0, Widget._renderEngine.createElement("body").width());
}
_getSuitableHeight(height) {
return clamp(height, 0, Widget._renderEngine.createElement("body")[0].clientHeight);
}
_calculateSize() {
const { size, width, height } = this.options;
const sizeValue = {};
if (isNotNull(size)) {
switch (size) {
case this._constant.SIZE.SMALL:
sizeValue.width = 450;
sizeValue.height = 200;
sizeValue.type = "small";
break;
case this._constant.SIZE.BIG:
sizeValue.width = 900;
sizeValue.height = 500;
sizeValue.type = "big";
break;
default:
sizeValue.width = 550;
sizeValue.height = 500;
sizeValue.type = "default";
}
}
_getSuitableWidth(width) {
return clamp(width, 0, Widget._renderEngine.createElement("body").width());
}
return {
width: width || sizeValue.width,
height: height || sizeValue.height,
type: sizeValue.type || "default",
};
}
setDraggable(b) {
this.options.draggable = b;
}
_calculateSize() {
const { size, width, height } = this.options;
const sizeValue = {};
if (isNotNull(size)) {
switch (size) {
case this._constant.SIZE.SMALL:
sizeValue.width = 450;
sizeValue.height = 200;
sizeValue.type = "small";
break;
case this._constant.SIZE.BIG:
sizeValue.width = 900;
sizeValue.height = 500;
sizeValue.type = "big";
break;
default:
sizeValue.width = 550;
sizeValue.height = 500;
sizeValue.type = "default";
}
}
hide() {
return {
width: width || sizeValue.width,
height: height || sizeValue.height,
type: sizeValue.type || "default",
};
}
setDraggable(b) {
this.options.draggable = b;
}
}
hide() {}
open() {
this.show();
this.fireEvent(Popover.EVENT_OPEN, arguments);
}
open() {
this.show();
this.fireEvent(Popover.EVENT_OPEN, arguments);
}
close() {
this.hide();
this.fireEvent(Popover.EVENT_CLOSE, arguments);
}
close() {
this.hide();
this.fireEvent(Popover.EVENT_CLOSE, arguments);
}
setZindex(zindex) {
this.element.css({ "z-index": zindex });
}
setZindex(zindex) {
this.element.css({ "z-index": zindex });
}
}
@shortcut()
export class BarPopover extends Popover {
static xtype = "bi.bar_popover";
static xtype = "bi.bar_popover";
_defaultConfig() {
return extend(super._defaultConfig(...arguments), {
btns: [BI.i18nText("BI-Basic_OK"), BI.i18nText("BI-Basic_Cancel")],
});
}
_defaultConfig() {
return extend(super._defaultConfig(...arguments), {
btns: [BI.i18nText("BI-Basic_OK"), BI.i18nText("BI-Basic_Cancel")],
});
}
beforeCreate() {
const { footer, warningTitle } = this.options;
footer || (this.options.footer = {
type: "bi.right_vertical_adapt",
lgap: 10,
items: [{
type: "bi.button",
text: this.options.btns[1],
value: 1,
level: "ignore",
handler: v => {
this.fireEvent(Popover.EVENT_CANCEL, v);
this.close(v);
},
}, {
type: "bi.button",
text: this.options.btns[0],
warningTitle,
value: 0,
handler: v => {
this.fireEvent(Popover.EVENT_CONFIRM, v);
this.close(v);
},
}],
});
}
beforeCreate() {
const { footer, warningTitle } = this.options;
footer ||
(this.options.footer = {
type: "bi.right_vertical_adapt",
lgap: 10,
items: [
{
type: Button.xtype,
text: this.options.btns[1],
value: 1,
level: "ignore",
handler: v => {
this.fireEvent(Popover.EVENT_CANCEL, v);
this.close(v);
},
},
{
type: Button.xtype,
text: this.options.btns[0],
warningTitle,
value: 0,
handler: v => {
this.fireEvent(Popover.EVENT_CONFIRM, v);
this.close(v);
},
}
],
});
}
}

875
src/base/layer/layer.popup.js

@ -1,432 +1,511 @@
import { ButtonGroup } from "../combination/group.button";
import {
VerticalLayout,
AbsoluteLayout,
Layout,
CenterLayout,
Widget,
shortcut,
extend,
Controller,
createWidget,
createItems,
clamp
} from "@/core";
/**
* 下拉框弹出层, zIndex在1000w
* @class BI.PopupView
* @extends BI.Widget
*/
import { Widget, shortcut, extend, Controller, createWidget, createItems, clamp } from "../../core";
@shortcut()
export class PopupView extends Widget {
_const = {
TRIANGLE_LENGTH: 12,
}
_const = {
TRIANGLE_LENGTH: 12,
};
static xtype = "bi.popup_view";
static EVENT_CHANGE = "EVENT_CHANGE";
static xtype = "bi.popup_view";
static EVENT_CHANGE = "EVENT_CHANGE";
_defaultConfig(props) {
return extend(super._defaultConfig(...arguments), {
_baseCls: `bi-popup-view${props.primary ? " bi-primary" : ""}`,
// 品牌色
primary: false,
maxWidth: "auto",
minWidth: 100,
// maxHeight: 200,
minHeight: 24,
lgap: 0,
rgap: 0,
tgap: 0,
bgap: 0,
vgap: 0,
hgap: 0,
innerVgap: 0,
innerHgap: 0,
showArrow: false,
direction: BI.Direction.Top, // 工具栏的方向
stopEvent: false, // 是否停止mousedown、mouseup事件
stopPropagation: false, // 是否停止mousedown、mouseup向上冒泡
logic: {
dynamic: true,
},
_defaultConfig(props) {
return extend(super._defaultConfig(...arguments), {
_baseCls: `bi-popup-view${props.primary ? " bi-primary" : ""}`,
// 品牌色
primary: false,
maxWidth: "auto",
minWidth: 100,
// maxHeight: 200,
minHeight: 24,
lgap: 0,
rgap: 0,
tgap: 0,
bgap: 0,
vgap: 0,
hgap: 0,
innerVgap: 0,
innerHgap: 0,
showArrow: false,
direction: BI.Direction.Top, // 工具栏的方向
stopEvent: false, // 是否停止mousedown、mouseup事件
stopPropagation: false, // 是否停止mousedown、mouseup向上冒泡
logic: {
dynamic: true,
},
tool: false, // 自定义工具栏
tabs: [], // 导航栏
buttons: [], // toolbar栏
tool: false, // 自定义工具栏
tabs: [], // 导航栏
buttons: [], // toolbar栏
el: {
type: "bi.button_group",
items: [],
chooseType: 0,
behaviors: {},
layouts: [{
type: "bi.vertical",
}],
},
});
}
render() {
const { minWidth, maxWidth, stopPropagation, stopEvent,
direction, logic, lgap, rgap, tgap, bgap, vgap, hgap, primary, showArrow } = this.options;
function fn (e) {
e.stopPropagation();
}
function stop (e) {
e.stopEvent();
el: {
type: ButtonGroup.xtype,
items: [],
chooseType: 0,
behaviors: {},
layouts: [
{
type: VerticalLayout.xtype,
}
],
},
});
}
render() {
const {
minWidth,
maxWidth,
stopPropagation,
stopEvent,
direction,
logic,
lgap,
rgap,
tgap,
bgap,
vgap,
hgap,
primary,
showArrow,
} = this.options;
function fn(e) {
e.stopPropagation();
}
function stop(e) {
e.stopEvent();
return false;
}
this.element.css({
"z-index": BI.zIndex_popup,
"min-width": BI.pixFormat(minWidth),
"max-width": BI.pixFormat(maxWidth),
}).bind({ click: fn });
return false;
}
this.element
.css({
"z-index": BI.zIndex_popup,
"min-width": BI.pixFormat(minWidth),
"max-width": BI.pixFormat(maxWidth),
})
.bind({ click: fn });
this.element.bind("mousewheel", fn);
this.element.bind("mousewheel", fn);
stopPropagation && this.element.bind({ mousedown: fn, mouseup: fn, mouseover: fn });
stopEvent && this.element.bind({ mousedown: stop, mouseup: stop, mouseover: stop });
this.tool = this._createTool();
this.tab = this._createTab();
this.view = this._createView();
this.toolbar = this._createToolBar();
stopPropagation && this.element.bind({ mousedown: fn, mouseup: fn, mouseover: fn });
stopEvent && this.element.bind({ mousedown: stop, mouseup: stop, mouseover: stop });
this.tool = this._createTool();
this.tab = this._createTab();
this.view = this._createView();
this.toolbar = this._createToolBar();
this.view.on(Controller.EVENT_CHANGE, (type, ...args) => {
this.fireEvent(Controller.EVENT_CHANGE, type, ...args);
if (type === BI.Events.CLICK) {
this.fireEvent(PopupView.EVENT_CHANGE);
}
});
this.view.on(Controller.EVENT_CHANGE, (type, ...args) => {
this.fireEvent(Controller.EVENT_CHANGE, type, ...args);
if (type === BI.Events.CLICK) {
this.fireEvent(PopupView.EVENT_CHANGE);
}
});
createWidget(extend({
element: this,
}, BI.LogicFactory.createLogic(BI.LogicFactory.createLogicTypeByDirection(direction), extend({}, logic, {
scrolly: false,
lgap,
rgap,
tgap,
bgap,
vgap,
hgap,
items: BI.LogicFactory.createLogicItemsByDirection(direction, extend({
cls: `list-view-outer bi-card list-view-shadow${primary ? " bi-primary" : ""}`,
}, BI.LogicFactory.createLogic(BI.LogicFactory.createLogicTypeByDirection(direction), extend({}, logic, {
items: BI.LogicFactory.createLogicItemsByDirection(direction, this.tool, this.tab, this.view, this.toolbar),
})))
),
}))));
if (showArrow) {
this.arrow = createWidget({
type: "bi.absolute",
cls: "bi-bubble-arrow",
items: [{
type: "bi.layout",
cls: "bubble-arrow",
}],
});
this.arrowWrapper = createWidget({
type: "bi.absolute",
cls: "bi-bubble-arrow-wrapper",
items: [{
el: this.arrow,
}],
});
// 因为三角符号的原因位置变大了,需要占位
this.placeholder = createWidget({
type: "bi.layout",
});
createWidget({
type: "bi.absolute",
element: this,
items: [{
el: this.arrowWrapper,
left: 0,
top: 0,
}, {
el: this.placeholder,
}],
});
}
}
_createView() {
const { el, value, minHeight, innerVgap, innerHgap } = this.options;
this.button_group = createWidget(el, { type: "bi.button_group", value });
this.button_group.element.css({
"min-height": BI.pixFormat(minHeight),
"padding-top": BI.pixFormat(innerVgap),
"padding-bottom": BI.pixFormat(innerVgap),
"padding-left": BI.pixFormat(innerHgap),
"padding-right": BI.pixFormat(innerHgap),
});
createWidget(
extend(
{
element: this,
},
BI.LogicFactory.createLogic(
BI.LogicFactory.createLogicTypeByDirection(direction),
extend({}, logic, {
scrolly: false,
lgap,
rgap,
tgap,
bgap,
vgap,
hgap,
items: BI.LogicFactory.createLogicItemsByDirection(
direction,
extend(
{
cls: `list-view-outer bi-card list-view-shadow${primary ? " bi-primary" : ""}`,
},
BI.LogicFactory.createLogic(
BI.LogicFactory.createLogicTypeByDirection(direction),
extend({}, logic, {
items: BI.LogicFactory.createLogicItemsByDirection(
direction,
this.tool,
this.tab,
this.view,
this.toolbar
),
})
)
)
),
})
)
)
);
if (showArrow) {
this.arrow = createWidget({
type: AbsoluteLayout.xtype,
cls: "bi-bubble-arrow",
items: [
{
type: Layout.xtype,
cls: "bubble-arrow",
}
],
});
this.arrowWrapper = createWidget({
type: AbsoluteLayout.xtype,
cls: "bi-bubble-arrow-wrapper",
items: [
{
el: this.arrow,
}
],
});
// 因为三角符号的原因位置变大了,需要占位
this.placeholder = createWidget({
type: Layout.xtype,
});
createWidget({
type: AbsoluteLayout.xtype,
element: this,
items: [
{
el: this.arrowWrapper,
left: 0,
top: 0,
},
{
el: this.placeholder,
}
],
});
}
}
_createView() {
const { el, value, minHeight, innerVgap, innerHgap } = this.options;
this.button_group = createWidget(el, { type: ButtonGroup.xtype, value });
this.button_group.element.css({
"min-height": BI.pixFormat(minHeight),
"padding-top": BI.pixFormat(innerVgap),
"padding-bottom": BI.pixFormat(innerVgap),
"padding-left": BI.pixFormat(innerHgap),
"padding-right": BI.pixFormat(innerHgap),
});
return this.button_group;
}
return this.button_group;
}
_createTool() {
const { tool } = this.options;
if (false === tool) {
return;
}
_createTool() {
const { tool } = this.options;
if (false === tool) {
return;
}
return createWidget(tool);
}
return createWidget(tool);
}
_createTab() {
const { tabs, value } = this.options;
if (tabs.length === 0) {
return;
}
_createTab() {
const { tabs, value } = this.options;
if (tabs.length === 0) {
return;
}
return createWidget({
type: "bi.center",
cls: "list-view-tab",
height: 25,
items: tabs,
value,
});
}
return createWidget({
type: CenterLayout.xtype,
cls: "list-view-tab",
height: 25,
items: tabs,
value,
});
}
_createToolBar() {
const { buttons } = this.options;
if (buttons.length === 0) {
return;
}
_createToolBar() {
const { buttons } = this.options;
if (buttons.length === 0) {
return;
}
return createWidget({
type: "bi.center",
cls: "list-view-toolbar bi-high-light bi-split-top",
height: 24,
items: createItems(buttons, {
once: false,
shadow: true,
isShadowShowingOnSelected: true,
}),
});
}
return createWidget({
type: CenterLayout.xtype,
cls: "list-view-toolbar bi-high-light bi-split-top",
height: 24,
items: createItems(buttons, {
once: false,
shadow: true,
isShadowShowingOnSelected: true,
}),
});
}
setDirection(direction, position) {
const { showArrow, tgap, vgap, bgap, rgap, hgap, lgap } = this.options;
if (showArrow) {
let style = {}, wrapperStyle = {}, placeholderStyle = {};
const adjustXOffset = position.adjustXOffset || 0;
const adjustYOffset = position.adjustYOffset || 0;
const bodyBounds = Widget._renderEngine.createElement("body").bounds();
const bodyWidth = bodyBounds.width;
const bodyHeight = bodyBounds.height;
const popupWidth = this.element.outerWidth();
const popupHeight = this.element.outerHeight();
const offset = position.offset;
const offsetStyle = position.offsetStyle;
const middle = offsetStyle === "center" || offsetStyle === "middle";
setDirection(direction, position) {
const { showArrow, tgap, vgap, bgap, rgap, hgap, lgap } = this.options;
if (showArrow) {
let style = {},
wrapperStyle = {},
placeholderStyle = {};
const adjustXOffset = position.adjustXOffset || 0;
const adjustYOffset = position.adjustYOffset || 0;
const bodyBounds = Widget._renderEngine.createElement("body").bounds();
const bodyWidth = bodyBounds.width;
const bodyHeight = bodyBounds.height;
const popupWidth = this.element.outerWidth();
const popupHeight = this.element.outerHeight();
const offset = position.offset;
const offsetStyle = position.offsetStyle;
const middle = offsetStyle === "center" || offsetStyle === "middle";
const minLeft = Math.max(4, offset.left + 4 + popupWidth - bodyWidth);
const minRight = Math.max(4, popupWidth - (offset.left + 4));
const minTop = Math.max(4, offset.top + 4 + popupHeight - bodyHeight);
const minBottom = Math.max(4, popupHeight - (offset.top + 4));
const minLeft = Math.max(4, offset.left + 4 + popupWidth - bodyWidth);
const minRight = Math.max(4, popupWidth - (offset.left + 4));
const minTop = Math.max(4, offset.top + 4 + popupHeight - bodyHeight);
const minBottom = Math.max(4, popupHeight - (offset.top + 4));
const maxLeft = Math.min(popupWidth - 16 - 4, offset.left + position.width - 16 - 4);
const maxRight = Math.min(popupWidth - 16 - 4, bodyWidth - (offset.left + position.width - 16 - 4));
const maxTop = Math.min(popupHeight - 16 - 4, offset.top + position.height - 16 - 4);
const maxBottom = Math.min(popupHeight - 16 - 4, bodyHeight - (offset.top + position.height - 16 - 4));
switch (direction) {
case "bottom":
case "bottom,right":
direction = "bottom";
style = {
// 5表示留出一定的空间
left: clamp(((middle ? popupWidth : position.width) - adjustXOffset) / 2 - 8, minLeft, maxLeft),
};
wrapperStyle = {
top: tgap + vgap,
left: 0,
right: "",
bottom: "",
};
placeholderStyle = {
left: 0,
right: 0,
height: this._const.TRIANGLE_LENGTH,
top: -this._const.TRIANGLE_LENGTH,
bottom: "",
};
break;
case "bottom,left":
direction = "bottom";
style = {
right: clamp(((middle ? popupWidth : position.width) + adjustXOffset) / 2 - 8, minRight, maxRight),
};
wrapperStyle = {
top: bgap + vgap,
left: "",
right: 0,
bottom: "",
};
placeholderStyle = {
left: 0,
right: 0,
height: this._const.TRIANGLE_LENGTH,
top: -this._const.TRIANGLE_LENGTH,
bottom: "",
};
break;
case "top":
case "top,right":
direction = "top";
style = {
left: clamp(((middle ? popupWidth : position.width) - adjustXOffset) / 2 - 8, minLeft, maxLeft),
};
wrapperStyle = {
bottom: bgap + vgap,
left: 0,
right: "",
top: "",
};
placeholderStyle = {
left: 0,
right: 0,
height: this._const.TRIANGLE_LENGTH,
top: "",
bottom: -this._const.TRIANGLE_LENGTH,
};
break;
case "top,left":
direction = "top";
style = {
right: clamp(((middle ? popupWidth : position.width) + adjustXOffset) / 2 - 8, minRight, maxRight),
};
wrapperStyle = {
bottom: bgap + vgap,
right: 0,
left: "",
top: "",
};
placeholderStyle = {
left: 0,
right: 0,
height: this._const.TRIANGLE_LENGTH,
top: "",
bottom: -this._const.TRIANGLE_LENGTH,
};
break;
case "left":
case "left,bottom":
direction = "left";
style = {
top: clamp(((middle ? popupHeight : position.height) - adjustYOffset) / 2 - 8, minTop, maxTop),
};
wrapperStyle = {
right: rgap + hgap,
top: 0,
bottom: "",
left: "",
};
placeholderStyle = {
top: 0,
bottom: 0,
width: this._const.TRIANGLE_LENGTH,
right: -this._const.TRIANGLE_LENGTH,
left: "",
};
break;
case "left,top":
direction = "left";
style = {
bottom: clamp(((middle ? popupHeight : position.height) + adjustYOffset) / 2 - 8, minBottom, maxBottom),
};
wrapperStyle = {
right: rgap + hgap,
bottom: 0,
top: "",
left: "",
};
placeholderStyle = {
top: 0,
bottom: 0,
width: this._const.TRIANGLE_LENGTH,
right: -this._const.TRIANGLE_LENGTH,
left: "",
};
break;
case "right":
case "right,bottom":
direction = "right";
style = {
top: clamp(((middle ? popupHeight : position.height) - adjustYOffset) / 2 - 8, minTop, maxTop),
};
wrapperStyle = {
left: lgap + hgap,
top: 0,
bottom: "",
right: "",
};
placeholderStyle = {
top: 0,
bottom: 0,
width: this._const.TRIANGLE_LENGTH,
left: -this._const.TRIANGLE_LENGTH,
right: "",
};
break;
case "right,top":
direction = "right";
style = {
bottom: clamp(((middle ? popupHeight : position.height) + adjustYOffset) / 2 - 8, minBottom, maxBottom),
};
wrapperStyle = {
left: lgap + hgap,
bottom: 0,
top: "",
right: "",
};
placeholderStyle = {
top: 0,
bottom: 0,
width: this._const.TRIANGLE_LENGTH,
left: -this._const.TRIANGLE_LENGTH,
right: "",
};
break;
case "right,innerRight":
break;
case "right,innerLeft":
break;
case "innerRight":
break;
case "innerLeft":
break;
default:
break;
}
this.element
.removeClass("left")
.removeClass("right")
.removeClass("top")
.removeClass("bottom")
.addClass(direction);
this.arrow.element.css(style);
this.arrowWrapper.element.css(wrapperStyle);
this.placeholder.element.css(placeholderStyle);
}
}
const maxLeft = Math.min(popupWidth - 16 - 4, offset.left + position.width - 16 - 4);
const maxRight = Math.min(popupWidth - 16 - 4, bodyWidth - (offset.left + position.width - 16 - 4));
const maxTop = Math.min(popupHeight - 16 - 4, offset.top + position.height - 16 - 4);
const maxBottom = Math.min(popupHeight - 16 - 4, bodyHeight - (offset.top + position.height - 16 - 4));
switch (direction) {
case "bottom":
case "bottom,right":
direction = "bottom";
style = {
// 5表示留出一定的空间
left: clamp(((middle ? popupWidth : position.width) - adjustXOffset) / 2 - 8, minLeft, maxLeft),
};
wrapperStyle = {
top: tgap + vgap,
left: 0,
right: "",
bottom: "",
};
placeholderStyle = {
left: 0,
right: 0,
height: this._const.TRIANGLE_LENGTH,
top: -this._const.TRIANGLE_LENGTH,
bottom: "",
};
break;
case "bottom,left":
direction = "bottom";
style = {
right: clamp(
((middle ? popupWidth : position.width) + adjustXOffset) / 2 - 8,
minRight,
maxRight
),
};
wrapperStyle = {
top: bgap + vgap,
left: "",
right: 0,
bottom: "",
};
placeholderStyle = {
left: 0,
right: 0,
height: this._const.TRIANGLE_LENGTH,
top: -this._const.TRIANGLE_LENGTH,
bottom: "",
};
break;
case "top":
case "top,right":
direction = "top";
style = {
left: clamp(((middle ? popupWidth : position.width) - adjustXOffset) / 2 - 8, minLeft, maxLeft),
};
wrapperStyle = {
bottom: bgap + vgap,
left: 0,
right: "",
top: "",
};
placeholderStyle = {
left: 0,
right: 0,
height: this._const.TRIANGLE_LENGTH,
top: "",
bottom: -this._const.TRIANGLE_LENGTH,
};
break;
case "top,left":
direction = "top";
style = {
right: clamp(
((middle ? popupWidth : position.width) + adjustXOffset) / 2 - 8,
minRight,
maxRight
),
};
wrapperStyle = {
bottom: bgap + vgap,
right: 0,
left: "",
top: "",
};
placeholderStyle = {
left: 0,
right: 0,
height: this._const.TRIANGLE_LENGTH,
top: "",
bottom: -this._const.TRIANGLE_LENGTH,
};
break;
case "left":
case "left,bottom":
direction = "left";
style = {
top: clamp(((middle ? popupHeight : position.height) - adjustYOffset) / 2 - 8, minTop, maxTop),
};
wrapperStyle = {
right: rgap + hgap,
top: 0,
bottom: "",
left: "",
};
placeholderStyle = {
top: 0,
bottom: 0,
width: this._const.TRIANGLE_LENGTH,
right: -this._const.TRIANGLE_LENGTH,
left: "",
};
break;
case "left,top":
direction = "left";
style = {
bottom: clamp(
((middle ? popupHeight : position.height) + adjustYOffset) / 2 - 8,
minBottom,
maxBottom
),
};
wrapperStyle = {
right: rgap + hgap,
bottom: 0,
top: "",
left: "",
};
placeholderStyle = {
top: 0,
bottom: 0,
width: this._const.TRIANGLE_LENGTH,
right: -this._const.TRIANGLE_LENGTH,
left: "",
};
break;
case "right":
case "right,bottom":
direction = "right";
style = {
top: clamp(((middle ? popupHeight : position.height) - adjustYOffset) / 2 - 8, minTop, maxTop),
};
wrapperStyle = {
left: lgap + hgap,
top: 0,
bottom: "",
right: "",
};
placeholderStyle = {
top: 0,
bottom: 0,
width: this._const.TRIANGLE_LENGTH,
left: -this._const.TRIANGLE_LENGTH,
right: "",
};
break;
case "right,top":
direction = "right";
style = {
bottom: clamp(
((middle ? popupHeight : position.height) + adjustYOffset) / 2 - 8,
minBottom,
maxBottom
),
};
wrapperStyle = {
left: lgap + hgap,
bottom: 0,
top: "",
right: "",
};
placeholderStyle = {
top: 0,
bottom: 0,
width: this._const.TRIANGLE_LENGTH,
left: -this._const.TRIANGLE_LENGTH,
right: "",
};
break;
case "right,innerRight":
break;
case "right,innerLeft":
break;
case "innerRight":
break;
case "innerLeft":
break;
default:
break;
}
this.element
.removeClass("left")
.removeClass("right")
.removeClass("top")
.removeClass("bottom")
.addClass(direction);
this.arrow.element.css(style);
this.arrowWrapper.element.css(wrapperStyle);
this.placeholder.element.css(placeholderStyle);
}
}
getView() {
return this.view;
}
getView() {
return this.view;
}
populate(items) {
this.view.populate(...arguments);
}
populate(items) {
this.view.populate(...arguments);
}
resetWidth(w) {
this.options.width = w;
this.element.width(w);
}
resetWidth(w) {
this.options.width = w;
this.element.width(w);
}
resetHeight(h) {
const tbHeight = this.toolbar ? (this.toolbar.attr("height") || 24) : 0,
tabHeight = this.tab ? (this.tab.attr("height") || 24) : 0,
toolHeight = ((this.tool && this.tool.attr("height")) || 24) * ((this.tool && this.tool.isVisible()) ? 1 : 0);
const resetHeight = h - tbHeight - tabHeight - toolHeight - 2 * this.options.innerVgap;
this.view.resetHeight ? this.view.resetHeight(resetHeight) :
this.view.element.css({ "max-height": BI.pixFormat(resetHeight) });
}
resetHeight(h) {
const tbHeight = this.toolbar ? this.toolbar.attr("height") || 24 : 0,
tabHeight = this.tab ? this.tab.attr("height") || 24 : 0,
toolHeight = ((this.tool && this.tool.attr("height")) || 24) * (this.tool && this.tool.isVisible() ? 1 : 0);
const resetHeight = h - tbHeight - tabHeight - toolHeight - 2 * this.options.innerVgap;
this.view.resetHeight
? this.view.resetHeight(resetHeight)
: this.view.element.css({ "max-height": BI.pixFormat(resetHeight) });
}
setValue(selectedValues) {
this.tab && this.tab.setValue(selectedValues);
this.view.setValue(selectedValues);
}
setValue(selectedValues) {
this.tab && this.tab.setValue(selectedValues);
this.view.setValue(selectedValues);
}
getValue() {
return this.view.getValue();
}
getValue() {
return this.view.getValue();
}
}

259
src/base/layer/layer.searcher.js

@ -1,3 +1,7 @@
import { ButtonGroup } from "../combination";
import { VerticalLayout, Layout, shortcut, extend, createWidget, Controller, isNotEmptyArray } from "@/core";
import { Pane } from "../1.pane";
/**
* 搜索面板
*
@ -6,132 +10,135 @@
* @extends BI.Pane
*/
import { shortcut, extend, createWidget, Controller, isNotEmptyArray } from "../../core";
import { Pane } from "../1.pane";
@shortcut()
export class SearcherView extends Pane {
static xtype = "bi.searcher_view";
static EVENT_CHANGE = "EVENT_CHANGE";
_defaultConfig() {
const conf = super._defaultConfig(...arguments);
return extend(conf, {
baseCls: `${conf.baseCls || ""} bi-searcher-view bi-card`,
tipText: BI.i18nText("BI-No_Select"),
chooseType: BI.Selection.Single,
matcher: { // 完全匹配的构造器
type: "bi.button_group",
behaviors: {
redmark: () => true,
},
items: [],
layouts: [{
type: "bi.vertical",
}],
},
searcher: {
type: "bi.button_group",
behaviors: {
redmark: () => true,
},
items: [],
layouts: [{
type: "bi.vertical",
}],
},
});
}
render() {
const { matcher, chooseType, value, searcher } = this.options;
this.matcher = createWidget(matcher, {
type: "bi.button_group",
chooseType,
behaviors: {
redmark: () => true,
},
layouts: [{
type: "bi.vertical",
}],
value,
});
this.matcher.on(Controller.EVENT_CHANGE, (type, val, ob, ...args) => {
this.fireEvent(Controller.EVENT_CHANGE, type, val, ob, ...args);
if (type === BI.Events.CLICK) {
this.fireEvent(SearcherView.EVENT_CHANGE, val, ob);
}
});
this.spliter = createWidget({
type: "bi.vertical",
height: 1,
hgap: 10,
items: [{
type: "bi.layout",
height: 1,
cls: "searcher-view-spliter bi-background",
}],
});
this.searcher = createWidget(searcher, {
type: "bi.button_group",
chooseType,
behaviors: {
redmark: () => true,
},
layouts: [{
type: "bi.vertical",
}],
value,
});
this.searcher.on(Controller.EVENT_CHANGE, (type, val, ob, ...args) => {
this.fireEvent(Controller.EVENT_CHANGE, type, val, ob, ...args);
if (type === BI.Events.CLICK) {
this.fireEvent(BI.SearcherView.EVENT_CHANGE, val, ob);
}
});
createWidget({
type: "bi.vertical",
element: this,
items: [this.matcher, this.spliter, this.searcher],
});
}
startSearch() {
}
stopSearch() {
}
setValue(v) {
this.matcher.setValue(v);
this.searcher.setValue(v);
}
getValue() {
return this.matcher.getValue().concat(this.searcher.getValue());
}
populate(searchResult, matchResult, keyword) {
searchResult || (searchResult = []);
matchResult || (matchResult = []);
this.setTipVisible(searchResult.length + matchResult.length === 0);
this.spliter.setVisible(isNotEmptyArray(matchResult) && isNotEmptyArray(searchResult));
this.matcher.populate(matchResult, keyword);
this.searcher.populate(searchResult, keyword);
}
empty() {
this.searcher.empty();
this.matcher.empty();
}
hasMatched() {
return this.matcher.getAllButtons().length > 0;
}
static xtype = "bi.searcher_view";
static EVENT_CHANGE = "EVENT_CHANGE";
_defaultConfig() {
const conf = super._defaultConfig(...arguments);
return extend(conf, {
baseCls: `${conf.baseCls || ""} bi-searcher-view bi-card`,
tipText: BI.i18nText("BI-No_Select"),
chooseType: BI.Selection.Single,
matcher: {
// 完全匹配的构造器
type: ButtonGroup.xtype,
behaviors: {
redmark: () => true,
},
items: [],
layouts: [
{
type: VerticalLayout.xtype,
}
],
},
searcher: {
type: ButtonGroup.xtype,
behaviors: {
redmark: () => true,
},
items: [],
layouts: [
{
type: VerticalLayout.xtype,
}
],
},
});
}
render() {
const { matcher, chooseType, value, searcher } = this.options;
this.matcher = createWidget(matcher, {
type: ButtonGroup.xtype,
chooseType,
behaviors: {
redmark: () => true,
},
layouts: [
{
type: VerticalLayout.xtype,
}
],
value,
});
this.matcher.on(Controller.EVENT_CHANGE, (type, val, ob, ...args) => {
this.fireEvent(Controller.EVENT_CHANGE, type, val, ob, ...args);
if (type === BI.Events.CLICK) {
this.fireEvent(SearcherView.EVENT_CHANGE, val, ob);
}
});
this.spliter = createWidget({
type: VerticalLayout.xtype,
height: 1,
hgap: 10,
items: [
{
type: Layout.xtype,
height: 1,
cls: "searcher-view-spliter bi-background",
}
],
});
this.searcher = createWidget(searcher, {
type: ButtonGroup.xtype,
chooseType,
behaviors: {
redmark: () => true,
},
layouts: [
{
type: VerticalLayout.xtype,
}
],
value,
});
this.searcher.on(Controller.EVENT_CHANGE, (type, val, ob, ...args) => {
this.fireEvent(Controller.EVENT_CHANGE, type, val, ob, ...args);
if (type === BI.Events.CLICK) {
this.fireEvent(BI.SearcherView.EVENT_CHANGE, val, ob);
}
});
createWidget({
type: VerticalLayout.xtype,
element: this,
items: [this.matcher, this.spliter, this.searcher],
});
}
startSearch() {}
stopSearch() {}
setValue(v) {
this.matcher.setValue(v);
this.searcher.setValue(v);
}
getValue() {
return this.matcher.getValue().concat(this.searcher.getValue());
}
populate(searchResult, matchResult, keyword) {
searchResult || (searchResult = []);
matchResult || (matchResult = []);
this.setTipVisible(searchResult.length + matchResult.length === 0);
this.spliter.setVisible(isNotEmptyArray(matchResult) && isNotEmptyArray(searchResult));
this.matcher.populate(matchResult, keyword);
this.searcher.populate(searchResult, keyword);
}
empty() {
this.searcher.empty();
this.matcher.empty();
}
hasMatched() {
return this.matcher.getAllButtons().length > 0;
}
}

221
src/base/list/listview.js

@ -1,3 +1,5 @@
import { VerticalLayout, Widget, shortcut, extend, isFunction } from "@/core";
/**
* 边滚动边加载的列表控件
*
@ -5,7 +7,7 @@
* @class BI.ListView
* @extends BI.Widget
*/
import { Widget, shortcut, extend, isFunction } from "../../core";
@shortcut()
export class ListView extends Widget {
props() {
@ -25,119 +27,128 @@ export class ListView extends Widget {
this.cache = {};
}
static xtype = "bi.list_view";
static xtype = "bi.list_view";
render() {
const { el } = this.options;
render() {
const { el } = this.options;
return {
type: "bi.vertical",
items: [extend({
type: "bi.vertical",
scrolly: false,
ref: _ref => {
this.container = _ref;
},
}, el)],
element: this,
};
}
return {
type: VerticalLayout.xtype,
items: [
extend(
{
type: VerticalLayout.xtype,
scrolly: false,
ref: _ref => {
this.container = _ref;
},
},
el
)
],
element: this,
};
}
// mounted之后绑定事件
mounted() {
const o = this.options;
// 这里无法进行结构,因为存在赋值操作,如果使用结构则this.options的值不会跟随变化
o.items = isFunction(o.items) ? this.__watch(o.items, (context, newValue) => {
this.populate(newValue);
}) : o.items;
this._populate();
this.element.scroll(e => {
o.scrollTop = this.element.scrollTop();
this._calculateBlocksToRender();
});
let lastWidth = this.element.width(),
lastHeight = this.element.height();
BI.ResizeDetector.addResizeListener(this, () => {
if (!this.element.is(":visible")) {
return;
}
const width = this.element.width(),
height = this.element.height();
if (width !== lastWidth || height !== lastHeight) {
lastWidth = width;
lastHeight = height;
this._calculateBlocksToRender();
}
});
}
// mounted之后绑定事件
mounted() {
const o = this.options;
// 这里无法进行结构,因为存在赋值操作,如果使用结构则this.options的值不会跟随变化
o.items = isFunction(o.items)
? this.__watch(o.items, (context, newValue) => {
this.populate(newValue);
})
: o.items;
this._populate();
this.element.scroll(e => {
o.scrollTop = this.element.scrollTop();
this._calculateBlocksToRender();
});
let lastWidth = this.element.width(),
lastHeight = this.element.height();
BI.ResizeDetector.addResizeListener(this, () => {
if (!this.element.is(":visible")) {
return;
}
const width = this.element.width(),
height = this.element.height();
if (width !== lastWidth || height !== lastHeight) {
lastWidth = width;
lastHeight = height;
this._calculateBlocksToRender();
}
});
}
_renderMoreIf() {
const { scrollTop, overscanHeight, blockSize, items, itemFormatter } = this.options;
const height = this.element.height();
const minContentHeight = scrollTop + height + overscanHeight;
let index = (this.cache[this.renderedIndex] && (this.cache[this.renderedIndex].index + blockSize)) || 0;
let cnt = this.renderedIndex + 1;
let lastHeight;
_renderMoreIf() {
const { scrollTop, overscanHeight, blockSize, items, itemFormatter } = this.options;
const height = this.element.height();
const minContentHeight = scrollTop + height + overscanHeight;
let index = (this.cache[this.renderedIndex] && this.cache[this.renderedIndex].index + blockSize) || 0;
let cnt = this.renderedIndex + 1;
let lastHeight;
const getElementHeight = () => this.container.element.height();
const getElementHeight = () => this.container.element.height();
lastHeight = getElementHeight();
while ((lastHeight) < minContentHeight && index < items.length) {
const itemsArr = items.slice(index, index + blockSize);
// eslint-disable-next-line no-loop-func
this.container.addItems(itemsArr.map((item, i) => itemFormatter(item, index + i)), this);
const addedHeight = getElementHeight() - lastHeight;
this.cache[cnt] = {
index,
scrollTop: lastHeight,
height: addedHeight,
};
this.renderedIndex = cnt;
cnt++;
index += blockSize;
lastHeight = getElementHeight();
}
}
_calculateBlocksToRender() {
// BI-115750 不可见状态下依赖元素实际尺寸构造的线段树会分段错误,所以不进行后续计算和线段树的初始化。
// 这样从不可见状态变为可见状态能够重新触发线段树初始化
if (!this.element.is(":visible")) {
return;
}
this._renderMoreIf();
}
lastHeight = getElementHeight();
while (lastHeight < minContentHeight && index < items.length) {
const itemsArr = items.slice(index, index + blockSize);
// eslint-disable-next-line no-loop-func
this.container.addItems(
itemsArr.map((item, i) => itemFormatter(item, index + i)),
this
);
const addedHeight = getElementHeight() - lastHeight;
this.cache[cnt] = {
index,
scrollTop: lastHeight,
height: addedHeight,
};
this.renderedIndex = cnt;
cnt++;
index += blockSize;
lastHeight = getElementHeight();
}
}
_calculateBlocksToRender() {
// BI-115750 不可见状态下依赖元素实际尺寸构造的线段树会分段错误,所以不进行后续计算和线段树的初始化。
// 这样从不可见状态变为可见状态能够重新触发线段树初始化
if (!this.element.is(":visible")) {
return;
}
this._renderMoreIf();
}
_populate(items) {
const { scrollTop } = this.options;
if (items && this.options.items !== items) {
this.options.items = items;
}
this._calculateBlocksToRender();
this.element.scrollTop(scrollTop);
}
_populate(items) {
const { scrollTop } = this.options;
if (items && this.options.items !== items) {
this.options.items = items;
}
this._calculateBlocksToRender();
this.element.scrollTop(scrollTop);
}
restore() {
this.renderedIndex = -1;
this.container.empty();
this.cache = {};
}
restore() {
this.renderedIndex = -1;
this.container.empty();
this.cache = {};
}
scrollTo(scrollTop) {
this.options.scrollTop = scrollTop;
this._calculateBlocksToRender();
this.element.scrollTop(scrollTop);
}
scrollTo(scrollTop) {
this.options.scrollTop = scrollTop;
this._calculateBlocksToRender();
this.element.scrollTop(scrollTop);
}
populate(items) {
if (items && this.options.items !== items) {
this.restore();
}
this._populate(items);
}
populate(items) {
if (items && this.options.items !== items) {
this.restore();
}
this._populate(items);
}
beforeDestroy() {
BI.ResizeDetector.removeResizeListener(this);
this.restore();
}
beforeDestroy() {
BI.ResizeDetector.removeResizeListener(this);
this.restore();
}
}

331
src/base/list/virtualgrouplist.js

@ -1,3 +1,6 @@
import { VerticalLayout, Layout, Widget, shortcut, extend, isFunction, isNumber, PrefixIntervalTree } from "@/core";
import { VirtualGroup } from "../combination";
/**
* 同时用于virtualGroup和virtualList特性的虚拟列表
*
@ -6,7 +9,6 @@
* @extends BI.Widget
*/
import { Widget, shortcut, extend, isFunction, isNumber, PrefixIntervalTree } from "../../core";
@shortcut()
export class VirtualGroupList extends Widget {
props() {
@ -26,167 +28,190 @@ export class VirtualGroupList extends Widget {
this.renderedIndex = -1;
}
static xtype = "bi.virtual_group_list";
static xtype = "bi.virtual_group_list";
render() {
const { rowHeight, items, el } = this.options;
render() {
const { rowHeight, items, el } = this.options;
return {
type: "bi.vertical",
items: [{
type: "bi.layout",
ref: () => {
this.topBlank = this;
},
}, {
type: "bi.virtual_group",
height: rowHeight * items.length,
ref: () => {
this.container = this;
},
layouts: [extend({
type: "bi.vertical",
scrolly: false,
}, el)],
}, {
type: "bi.layout",
ref: () => {
this.bottomBlank = this;
},
}],
element: this,
};
}
// mounted之后绑定事件
mounted() {
// 这里无法进行结构,因为存在赋值操作,如果使用结构则this.options的值不会跟随变化
const o = this.options;
o.items = isFunction(o.items) ? this.__watch(o.items, (context, newValue) => {
this.populate(newValue);
}) : o.items;
this._populate();
this.ticking = false;
this.element.scroll(() => {
o.scrollTop = this.element.scrollTop();
if (!this.ticking) {
requestAnimationFrame(() => {
this._calculateBlocksToRender();
this.ticking = false;
});
this.ticking = true;
}
});
BI.ResizeDetector.addResizeListener(this, () => {
if (this.element.is(":visible")) {
this._calculateBlocksToRender();
}
});
}
return {
type: VerticalLayout.xtype,
items: [
{
type: Layout.xtype,
ref: () => {
this.topBlank = this;
},
},
{
type: VirtualGroup.xtype,
height: rowHeight * items.length,
ref: () => {
this.container = this;
},
layouts: [
extend(
{
type: VerticalLayout.xtype,
scrolly: false,
},
el
)
],
},
{
type: Layout.xtype,
ref: () => {
this.bottomBlank = this;
},
}
],
element: this,
};
}
// mounted之后绑定事件
mounted() {
// 这里无法进行结构,因为存在赋值操作,如果使用结构则this.options的值不会跟随变化
const o = this.options;
o.items = isFunction(o.items)
? this.__watch(o.items, (context, newValue) => {
this.populate(newValue);
})
: o.items;
this._populate();
this.ticking = false;
this.element.scroll(() => {
o.scrollTop = this.element.scrollTop();
if (!this.ticking) {
requestAnimationFrame(() => {
this._calculateBlocksToRender();
this.ticking = false;
});
this.ticking = true;
}
});
BI.ResizeDetector.addResizeListener(this, () => {
if (this.element.is(":visible")) {
this._calculateBlocksToRender();
}
});
}
_isAutoHeight() {
return !isNumber(this.options.rowHeight);
}
_isAutoHeight() {
return !isNumber(this.options.rowHeight);
}
_renderMoreIf() {
const { scrollTop, overscanHeight, blockSize, items, itemFormatter } = this.options;
const height = this.element.height();
const minContentHeight = scrollTop + height + overscanHeight;
let index = (this.renderedIndex + 1) * blockSize, cnt = this.renderedIndex + 1;
let lastHeight;
const getElementHeight = () => this.container.element.height() + this.topBlank.element.height() + this.bottomBlank.element.height();
lastHeight = this.renderedIndex === -1 ? 0 : getElementHeight();
while (lastHeight < minContentHeight && index < items.length) {
const itemsArr = items.slice(index, index + blockSize);
// eslint-disable-next-line no-loop-func
this.container[this.renderedIndex === -1 ? "populate" : "addItems"](itemsArr.map((item, i) => itemFormatter(item, index + i)), this);
const elementHeight = getElementHeight();
const addedHeight = elementHeight - lastHeight;
this.tree.set(cnt, addedHeight);
this.renderedIndex = cnt;
cnt++;
index += blockSize;
lastHeight = this.renderedIndex === -1 ? 0 : elementHeight;
}
}
_renderMoreIf() {
const { scrollTop, overscanHeight, blockSize, items, itemFormatter } = this.options;
const height = this.element.height();
const minContentHeight = scrollTop + height + overscanHeight;
let index = (this.renderedIndex + 1) * blockSize,
cnt = this.renderedIndex + 1;
let lastHeight;
const getElementHeight = () =>
this.container.element.height() + this.topBlank.element.height() + this.bottomBlank.element.height();
lastHeight = this.renderedIndex === -1 ? 0 : getElementHeight();
while (lastHeight < minContentHeight && index < items.length) {
const itemsArr = items.slice(index, index + blockSize);
// eslint-disable-next-line no-loop-func
this.container[this.renderedIndex === -1 ? "populate" : "addItems"](
itemsArr.map((item, i) => itemFormatter(item, index + i)),
this
);
const elementHeight = getElementHeight();
const addedHeight = elementHeight - lastHeight;
this.tree.set(cnt, addedHeight);
this.renderedIndex = cnt;
cnt++;
index += blockSize;
lastHeight = this.renderedIndex === -1 ? 0 : elementHeight;
}
}
_calculateBlocksToRender() {
// BI-115750 不可见状态下依赖元素实际尺寸构造的线段树会分段错误,所以不进行后续计算和线段树的初始化。
// 这样从不可见状态变为可见状态能够重新触发线段树初始化
if (!this.element.is(":visible")) {
return;
}
const { scrollTop, overscanHeight, blockSize, items, itemFormatter, rowHeight } = this.options;
this._isAutoHeight() && this._renderMoreIf();
const height = this.element.height();
const minContentHeightFrom = scrollTop - overscanHeight;
const minContentHeightTo = scrollTop + height + overscanHeight;
const start = this.tree.greatestLowerBound(minContentHeightFrom);
const end = this.tree.leastUpperBound(minContentHeightTo);
const itemsArr = [];
const topHeight = this.tree.sumTo(Math.max(-1, start - 1));
this.topBlank.setHeight(`${topHeight}px`);
if (this._isAutoHeight()) {
for (let i = (start < 0 ? 0 : start); i <= end && i <= this.renderedIndex; i++) {
const index = i * blockSize;
for (let j = index; j < index + blockSize && j < items.length; j++) {
itemsArr.push(items[j]);
}
}
this.bottomBlank.setHeight(`${this.tree.sumTo(this.renderedIndex) - this.tree.sumTo(Math.min(end, this.renderedIndex))}px`);
this.container.populate(itemsArr.map((item, i) => itemFormatter(item, (start < 0 ? 0 : start) * blockSize + i)));
} else {
for (let i = (start < 0 ? 0 : start); i <= end; i++) {
const index = i * blockSize;
for (let j = index; j < index + blockSize && j < items.length; j++) {
itemsArr.push(items[j]);
}
}
this.container.element.height(rowHeight * items.length - topHeight);
this.container.populate(itemsArr.map((item, i) => itemFormatter(item, (start < 0 ? 0 : start) * blockSize + i)));
}
}
_populate(items) {
const { blockSize, rowHeight, scrollTop } = this.options;
if (items && this.options.items !== items) {
// 重新populate一组items,需要重新对线段树分块
this.options.items = items;
this._restore();
}
this.tree = PrefixIntervalTree.uniform(Math.ceil(this.options.items.length / blockSize), this._isAutoHeight() ? 0 : rowHeight * blockSize);
_calculateBlocksToRender() {
// BI-115750 不可见状态下依赖元素实际尺寸构造的线段树会分段错误,所以不进行后续计算和线段树的初始化。
// 这样从不可见状态变为可见状态能够重新触发线段树初始化
if (!this.element.is(":visible")) {
return;
}
const { scrollTop, overscanHeight, blockSize, items, itemFormatter, rowHeight } = this.options;
this._isAutoHeight() && this._renderMoreIf();
const height = this.element.height();
const minContentHeightFrom = scrollTop - overscanHeight;
const minContentHeightTo = scrollTop + height + overscanHeight;
const start = this.tree.greatestLowerBound(minContentHeightFrom);
const end = this.tree.leastUpperBound(minContentHeightTo);
const itemsArr = [];
const topHeight = this.tree.sumTo(Math.max(-1, start - 1));
this.topBlank.setHeight(`${topHeight}px`);
if (this._isAutoHeight()) {
for (let i = start < 0 ? 0 : start; i <= end && i <= this.renderedIndex; i++) {
const index = i * blockSize;
for (let j = index; j < index + blockSize && j < items.length; j++) {
itemsArr.push(items[j]);
}
}
this.bottomBlank.setHeight(
`${this.tree.sumTo(this.renderedIndex) - this.tree.sumTo(Math.min(end, this.renderedIndex))}px`
);
this.container.populate(
itemsArr.map((item, i) => itemFormatter(item, (start < 0 ? 0 : start) * blockSize + i))
);
} else {
for (let i = start < 0 ? 0 : start; i <= end; i++) {
const index = i * blockSize;
for (let j = index; j < index + blockSize && j < items.length; j++) {
itemsArr.push(items[j]);
}
}
this.container.element.height(rowHeight * items.length - topHeight);
this.container.populate(
itemsArr.map((item, i) => itemFormatter(item, (start < 0 ? 0 : start) * blockSize + i))
);
}
}
_populate(items) {
const { blockSize, rowHeight, scrollTop } = this.options;
if (items && this.options.items !== items) {
// 重新populate一组items,需要重新对线段树分块
this.options.items = items;
this._restore();
}
this.tree = PrefixIntervalTree.uniform(
Math.ceil(this.options.items.length / blockSize),
this._isAutoHeight() ? 0 : rowHeight * blockSize
);
this._calculateBlocksToRender();
try {
this.element.scrollTop(scrollTop);
} catch (e) {
}
}
this._calculateBlocksToRender();
try {
this.element.scrollTop(scrollTop);
} catch (e) {}
}
_restore() {
this.renderedIndex = -1;
// 依赖于cache的占位元素也要初始化
this.topBlank.setHeight(0);
this.bottomBlank.setHeight(0);
}
_restore() {
this.renderedIndex = -1;
// 依赖于cache的占位元素也要初始化
this.topBlank.setHeight(0);
this.bottomBlank.setHeight(0);
}
// 暂时只支持固定行高的场景
scrollTo(scrollTop) {
this.options.scrollTop = scrollTop;
this._calculateBlocksToRender();
this.element.scrollTop(scrollTop);
}
// 暂时只支持固定行高的场景
scrollTo(scrollTop) {
this.options.scrollTop = scrollTop;
this._calculateBlocksToRender();
this.element.scrollTop(scrollTop);
}
restore() {
this.options.scrollTop = 0;
this._restore();
}
restore() {
this.options.scrollTop = 0;
this._restore();
}
populate(items) {
this._populate(items);
}
populate(items) {
this._populate(items);
}
beforeDestroy() {
BI.ResizeDetector.removeResizeListener(this);
this.restore();
}
beforeDestroy() {
BI.ResizeDetector.removeResizeListener(this);
this.restore();
}
}

71
src/base/list/virtuallist.js

@ -1,3 +1,5 @@
import { VerticalLayout, Layout, Widget, shortcut, isFunction, each, PrefixIntervalTree } from "@/core";
/**
* 虚拟列表
*
@ -6,7 +8,6 @@
* @extends BI.Widget
*/
import { Widget, shortcut, isFunction, each, PrefixIntervalTree } from "../../core";
@shortcut()
export class VirtualList extends Widget {
props() {
@ -29,33 +30,39 @@ export class VirtualList extends Widget {
render() {
return {
type: "bi.vertical",
items: [{
type: "bi.layout",
ref: _ref => {
this.topBlank = _ref;
},
}, {
type: "bi.vertical",
scrolly: false,
ref: _ref => {
this.container = _ref;
type: VerticalLayout.xtype,
items: [
{
type: Layout.xtype,
ref: _ref => {
this.topBlank = _ref;
},
},
}, {
type: "bi.layout",
ref: _ref => {
this.bottomBlank = _ref;
{
type: VerticalLayout.xtype,
scrolly: false,
ref: _ref => {
this.container = _ref;
},
},
}],
{
type: Layout.xtype,
ref: _ref => {
this.bottomBlank = _ref;
},
}
],
};
}
// mounted之后绑定事件
mounted() {
// 这里无法进行结构,因为存在赋值操作,如果使用结构则this.options的值不会跟随变化
const o = this.options;
o.items = isFunction(o.items) ? this.__watch(o.items, (context, newValue) => {
this.populate(newValue);
}) : o.items;
o.items = isFunction(o.items)
? this.__watch(o.items, (context, newValue) => {
this.populate(newValue);
})
: o.items;
this._populate();
this.element.scroll(e => {
o.scrollTop = this.element.scrollTop();
@ -72,14 +79,19 @@ export class VirtualList extends Widget {
const { scrollTop, overscanHeight, blockSize, items, itemFormatter } = this.options;
const height = this.element.height();
const minContentHeight = scrollTop + height + overscanHeight;
let index = (this.renderedIndex + 1) * blockSize, cnt = this.renderedIndex + 1;
let index = (this.renderedIndex + 1) * blockSize,
cnt = this.renderedIndex + 1;
let lastHeight;
const getElementHeight = () => this.container.element.height() + this.topBlank.element.height() + this.bottomBlank.element.height();
const getElementHeight = () =>
this.container.element.height() + this.topBlank.element.height() + this.bottomBlank.element.height();
lastHeight = getElementHeight();
while (lastHeight < minContentHeight && index < items.length) {
const itemsArr = items.slice(index, index + blockSize);
// eslint-disable-next-line no-loop-func
this.container.addItems(itemsArr.map((item, i) => itemFormatter(item, index + i)), this);
this.container.addItems(
itemsArr.map((item, i) => itemFormatter(item, index + i)),
this
);
const addedHeight = getElementHeight() - lastHeight;
this.tree.set(cnt, addedHeight);
this.renderedIndex = cnt;
@ -102,7 +114,8 @@ export class VirtualList extends Widget {
const minContentHeightTo = scrollTop + height + overscanHeight;
const start = this.tree.greatestLowerBound(minContentHeightFrom);
const end = this.tree.leastUpperBound(minContentHeightTo);
const needDestroyed = [], needMount = [];
const needDestroyed = [],
needMount = [];
for (let i = 0; i < start; i++) {
const index = i * blockSize;
if (!this.cache[i]) {
@ -132,7 +145,7 @@ export class VirtualList extends Widget {
const firstFragment = Widget._renderEngine.createFragment(),
lastFragment = Widget._renderEngine.createFragment();
let currentFragment = firstFragment;
for (let i = (start < 0 ? 0 : start); i <= end && i <= this.renderedIndex; i++) {
for (let i = start < 0 ? 0 : start; i <= end && i <= this.renderedIndex; i++) {
const index = i * blockSize;
if (!this.cache[i]) {
this.cache[i] = {};
@ -152,7 +165,9 @@ export class VirtualList extends Widget {
this.container.element.prepend(firstFragment);
this.container.element.append(lastFragment);
this.topBlank.setHeight(`${this.tree.sumTo(Math.max(-1, start - 1))}px`);
this.bottomBlank.setHeight(`${this.tree.sumTo(this.renderedIndex) - this.tree.sumTo(Math.min(end, this.renderedIndex))}px`);
this.bottomBlank.setHeight(
`${this.tree.sumTo(this.renderedIndex) - this.tree.sumTo(Math.min(end, this.renderedIndex))}px`
);
each(needMount, (i, child) => {
child && child._mount();
});
@ -170,8 +185,7 @@ export class VirtualList extends Widget {
this._calculateBlocksToRender();
try {
this.element.scrollTop(scrollTop);
} catch (e) {
}
} catch (e) {}
}
_clearChildren() {
@ -210,4 +224,3 @@ export class VirtualList extends Widget {
this.restore();
}
}

149
src/base/pager/pager.js

@ -1,3 +1,20 @@
import {
HorizontalLayout,
Widget,
shortcut,
extend,
emptyFn,
result,
isKey,
createWidget,
map,
stripEL,
formatEL,
Controller
} from "@/core";
import { Label } from "../single";
import { ButtonGroup } from "../combination";
/**
* 分页控件
*
@ -5,18 +22,20 @@
* @class BI.Pager
* @extends BI.Widget
*/
import { Widget, shortcut, extend, emptyFn, result, isKey, createWidget, map, stripEL, formatEL, Controller } from "../../core";
@shortcut()
export class Pager extends Widget {
_defaultConfig() {
return extend(super._defaultConfig(...arguments), {
baseCls: "bi-pager",
behaviors: {},
layouts: [{
type: "bi.horizontal",
hgap: 10,
vgap: 0,
}],
layouts: [
{
type: HorizontalLayout.xtype,
hgap: 10,
vgap: 0,
}
],
dynamicShow: true, // 是否动态显示上一页、下一页、首页、尾页, 若为false,则指对其设置使能状态
// dynamicShow为false时以下两个有用
@ -32,7 +51,8 @@ export class Pager extends Widget {
next: "下一页",
firstPage: 1,
lastPage: () => // 在万不得已时才会调用这个函数获取最后一页的页码, 主要作用于setValue方法
lastPage: () =>
// 在万不得已时才会调用这个函数获取最后一页的页码, 主要作用于setValue方法
1,
hasPrev: emptyFn, // pages不可用时有效
hasNext: emptyFn, // pages不可用时有效
@ -53,8 +73,11 @@ export class Pager extends Widget {
}
_populate() {
const o = this.options, view = [], dict = {};
const { dynamicShow, dynamicShowPrevNext, hasPrev, dynamicShowFirstLast, hasNext, behaviors, layouts, jump } = this.options;
const o = this.options,
view = [],
dict = {};
const { dynamicShow, dynamicShowPrevNext, hasPrev, dynamicShowFirstLast, hasNext, behaviors, layouts, jump } =
this.options;
this.empty();
const pages = result(o, "pages");
const curr = result(this, "currPage");
@ -73,7 +96,7 @@ export class Pager extends Widget {
}
// 计算当前组
dict.index = Math.ceil((curr + ((groups > 1 && groups !== pages) ? 1 : 0)) / (groups === 0 ? 1 : groups));
dict.index = Math.ceil((curr + (groups > 1 && groups !== pages ? 1 : 0)) / (groups === 0 ? 1 : groups));
// 当前页非首页,则输出上一页
if (((!dynamicShow && !dynamicShowPrevNext) || curr > 1) && prev !== false) {
@ -85,9 +108,12 @@ export class Pager extends Widget {
});
} else {
view.push({
el: extend({
disabled: pages === false ? hasPrev(curr) === false : !(curr > 1 && prev !== false),
}, prev),
el: extend(
{
disabled: pages === false ? hasPrev(curr) === false : !(curr > 1 && prev !== false),
},
prev
),
});
}
}
@ -101,7 +127,7 @@ export class Pager extends Widget {
});
if (dict.index > 1 && groups !== 0 && groups !== pages - 1) {
view.push({
type: "bi.label",
type: Label.xtype,
cls: "page-ellipsis",
text: "\u2026",
});
@ -111,16 +137,21 @@ export class Pager extends Widget {
// 输出当前页组
dict.poor = Math.floor((groups - 1) / 2);
dict.start = dict.index > 1 ? curr - dict.poor : 1;
dict.end = dict.index > 1 ? (function () {
const max = curr + (groups - dict.poor - 1);
dict.end =
dict.index > 1
? (function () {
const max = curr + (groups - dict.poor - 1);
return max > pages ? pages : max;
}()) : groups;
if (dict.end - dict.start < groups - 1) { // 最后一组状态
return max > pages ? pages : max;
}())
: groups;
if (dict.end - dict.start < groups - 1) {
// 最后一组状态
dict.start = dict.end - groups + 1;
}
let s = dict.start, e = dict.end;
if (first && last && (dict.index > 1 && groups !== 0) && (pages > groups && dict.end < pages && groups !== 0)) {
let s = dict.start,
e = dict.end;
if (first && last && dict.index > 1 && groups !== 0 && pages > groups && dict.end < pages && groups !== 0) {
s++;
e--;
}
@ -143,7 +174,7 @@ export class Pager extends Widget {
if (((!dynamicShow && !dynamicShowFirstLast) || (pages > groups && dict.end < pages && groups !== 0)) && last) {
if (pages > groups && dict.end < pages && groups !== 0 && groups !== pages - 1) {
view.push({
type: "bi.label",
type: Label.xtype,
cls: "page-ellipsis",
text: "\u2026",
});
@ -157,38 +188,47 @@ export class Pager extends Widget {
// 当前页不为尾页时,输出下一页
dict.flow = !prev && groups === 0;
if (((!dynamicShow && !dynamicShowPrevNext) && next) || (curr !== pages && next || dict.flow)) {
view.push((function () {
if (isKey(next)) {
if (pages === false) {
return { text: next, value: "next", disabled: hasNext(curr) === false };
}
if ((!dynamicShow && !dynamicShowPrevNext && next) || (curr !== pages && next) || dict.flow) {
view.push(
(function () {
if (isKey(next)) {
if (pages === false) {
return { text: next, value: "next", disabled: hasNext(curr) === false };
}
return (dict.flow && curr === pages)
?
{ text: next, value: "next", disabled: true }
:
{ text: next, value: "next", disabled: !(curr !== pages && next || dict.flow) };
}
return dict.flow && curr === pages
? { text: next, value: "next", disabled: true }
: { text: next, value: "next", disabled: !((curr !== pages && next) || dict.flow) };
}
return {
el: extend({
disabled: pages === false ? hasNext(curr) === false : !(curr !== pages && next || dict.flow),
}, next),
};
}()));
return {
el: extend(
{
disabled:
pages === false
? hasNext(curr) === false
: !((curr !== pages && next) || dict.flow),
},
next
),
};
})()
);
}
this.button_group = createWidget({
type: "bi.button_group",
type: ButtonGroup.xtype,
element: this,
items: map(view, (idx, v) => {
v = extend({
cls: "bi-list-item-select bi-border-radius",
height: 23,
hgap: v.el ? 0 : 10,
stopPropagation: true,
}, stripEL(v));
v = extend(
{
cls: "bi-list-item-select bi-border-radius",
height: 23,
hgap: v.el ? 0 : 10,
stopPropagation: true,
},
stripEL(v)
);
return formatEL(v);
}),
@ -220,10 +260,12 @@ export class Pager extends Widget {
this.currPage = v;
break;
}
jump.apply(this, [{
pages,
curr: this.currPage,
}]);
jump.apply(this, [
{
pages,
curr: this.currPage,
}
]);
this._populate();
this.fireEvent(Pager.EVENT_CHANGE, obj);
}
@ -251,7 +293,7 @@ export class Pager extends Widget {
hasNext(v) {
v || (v = 1);
const { pages, hasNext } = this.options;
return pages === false ? hasNext(v) : v < pages;
}
@ -263,7 +305,8 @@ export class Pager extends Widget {
if (pages === false) {
const lastPage = result(o, "lastPage");
let firstPage = 1;
this.currPage = v > lastPage ? lastPage : ((firstPage = result(o, "firstPage")), (v < firstPage ? firstPage : v));
this.currPage =
v > lastPage ? lastPage : ((firstPage = result(o, "firstPage")), v < firstPage ? firstPage : v);
} else {
v = v > pages ? pages : v;
this.currPage = v;

39
src/base/single/0.single.js

@ -1,3 +1,6 @@
import { Widget, shortcut, Actions, extend, isKey, isNotNull, isFunction, isPlainObject, isNull, delay } from "@/core";
import { Tooltips } from "@/base";
/**
* guy
* 这仅仅只是一个超类, 所有简单控件的基类
@ -10,13 +13,10 @@
* @abstract
*/
import { Widget, shortcut, Actions, extend, isKey, isNotNull, isFunction, isPlainObject, isNull, delay } from "../../core";
import { Tooltips } from "../0.base";
@shortcut()
export class Single extends Widget {
static xtype = "bi.single";
_defaultConfig() {
const conf = super._defaultConfig(...arguments);
@ -35,7 +35,7 @@ export class Single extends Widget {
const { action } = this.options;
const title = this.getTitle();
const showToolTip = (tooltipOpt) => {
const showToolTip = tooltipOpt => {
if (isKey(tooltipOpt.text) && !Tooltips.has(this.getName())) {
Tooltips.show(e, this.getName(), tooltipOpt, this, opt);
if (action) {
@ -43,7 +43,7 @@ export class Single extends Widget {
}
Actions.runGlobalAction("hover", this.options, this);
}
}
};
if (title instanceof Promise) {
this.requestingTitle = title;
@ -54,7 +54,6 @@ export class Single extends Widget {
} else {
showToolTip(this._getTooltipOptions(title));
}
}
_hideTooltip() {
@ -68,16 +67,17 @@ export class Single extends Widget {
_init() {
const { value } = this.options;
this.options.value = isFunction(value) ? this.__watch(value, (context, newValue) => {
this.setValue(newValue);
}) : value;
this.options.value = isFunction(value)
? this.__watch(value, (context, newValue) => {
this.setValue(newValue);
})
: value;
super._init(arguments);
}
_mounted() {
const { enableHover, title, warningTitle, belowMouse, container } = this.options;
if (enableHover || isKey(title) || isKey(warningTitle)
|| isFunction(title) || isFunction(warningTitle)) {
if (enableHover || isKey(title) || isKey(warningTitle) || isFunction(title) || isFunction(warningTitle)) {
this.enableHover({
belowMouse,
container,
@ -105,11 +105,12 @@ export class Single extends Widget {
tooltipOpt.level = this.getTipType() || "success";
// 由于以前的用法,存在大量disabled:true搭配warningTitle的情况,所以这里做一个兼容,disabled:true的情况下,依然优先显示warningTitle,避免只设置了warningTitle而没有设置title的情况
if (isNull(tipType) && !this.isEnabled()) {
tooltipOpt.text = (this.getWarningTitle() || title);
tooltipOpt.text = this.getWarningTitle() || title;
} else {
tooltipOpt.text = tooltipOpt.level === "success" ? title : (this.getWarningTitle() || title);
tooltipOpt.text = tooltipOpt.level === "success" ? title : this.getWarningTitle() || title;
}
}
return tooltipOpt;
}
@ -117,7 +118,7 @@ export class Single extends Widget {
opt || (opt = {});
let delayingTooltips;
if (!this._hoverBinded) {
this.element.unbind("mouseenter.title").on("mouseenter.title", (e) => {
this.element.unbind("mouseenter.title").on("mouseenter.title", e => {
this._e = e;
this.mouseOver = true;
if (this.getTipType() === "warning" || (isKey(this.getWarningTitle()) && !this.isEnabled())) {
@ -136,7 +137,7 @@ export class Single extends Widget {
}, 500);
}
});
this.element.unbind("mousemove.title").on("mousemove.title", (e) => {
this.element.unbind("mousemove.title").on("mousemove.title", e => {
this._e = e;
if (isNotNull(this.showTimeout)) {
clearTimeout(this.showTimeout);
@ -165,7 +166,7 @@ export class Single extends Widget {
}
}, 500);
});
this.element.unbind("mouseleave.title").on("mouseleave.title", (e) => {
this.element.unbind("mouseleave.title").on("mouseleave.title", e => {
this._e = null;
this.mouseOver = false;
this._clearTimeOut();
@ -179,9 +180,7 @@ export class Single extends Widget {
// 取消hover事件
this._clearTimeOut();
this._hideTooltip();
this.element.unbind("mouseenter.title")
.unbind("mousemove.title")
.unbind("mouseleave.title");
this.element.unbind("mouseenter.title").unbind("mousemove.title").unbind("mouseleave.title");
this._hoverBinded = false;
}

64
src/base/single/1.text.js

@ -1,10 +1,11 @@
import { Layout, DefaultLayout, shortcut } from "@/core";
import { Single } from "./0.single";
/**
* guy 表示一行数据通过position来定位位置的数据
* @class BI.Text
* @extends BI.Single
*/
import { shortcut } from "../../core";
import { Single } from "./0.single";
@shortcut()
export class Text extends Single {
@ -24,10 +25,29 @@ export class Text extends Single {
bgap: 0,
py: "",
highLight: false,
}
};
render() {
const { vgap, hgap, lgap, rgap, tgap, bgap, height, lineHeight, maxWidth, textAlign, whiteSpace, handler, disabled, invalid, text: optionsText, value, keyword, highLight } = this.options;
const {
vgap,
hgap,
lgap,
rgap,
tgap,
bgap,
height,
lineHeight,
maxWidth,
textAlign,
whiteSpace,
handler,
disabled,
invalid,
text: optionsText,
value,
keyword,
highLight,
} = this.options;
if (hgap + lgap > 0) {
this.element.css({
"padding-left": BI.pixFormat(hgap + lgap),
@ -58,21 +78,21 @@ export class Text extends Single {
this.element.css({ maxWidth: BI.pixFormat(maxWidth) });
}
this.element.css({
textAlign: textAlign,
textAlign,
whiteSpace: this._getTextWrap(),
textOverflow: whiteSpace === "nowrap" ? "ellipsis" : "",
overflow: whiteSpace === "nowrap" ? "" : (BI.isWidthOrHeight(height) ? "auto" : ""),
overflow: whiteSpace === "nowrap" ? "" : BI.isWidthOrHeight(height) ? "auto" : "",
});
if (handler && handler !== BI.emptyFn) {
this.text = BI.createWidget({
type: "bi.layout",
type: Layout.xtype,
tagName: "span",
});
this.text.element.click((e) => {
this.text.element.click(e => {
!disabled && !invalid && handler.call(this, this.getValue(), this, e);
});
BI.createWidget({
type: "bi.default",
type: DefaultLayout.xtype,
element: this,
items: [this.text],
});
@ -80,9 +100,11 @@ export class Text extends Single {
this.text = this;
}
const text = BI.isFunction(optionsText) ? this.__watch(optionsText, (context, newValue) => {
this.setText(newValue);
}) : optionsText;
const text = BI.isFunction(optionsText)
? this.__watch(optionsText, (context, newValue) => {
this.setText(newValue);
})
: optionsText;
// 只要不是undefined就可以显示text值,否则显示value
if (!BI.isUndefined(text)) {
this.setText(text);
@ -100,12 +122,12 @@ export class Text extends Single {
_getTextWrap() {
const { whiteSpace } = this.options;
switch (whiteSpace) {
case "nowrap":
return "pre";
case "normal":
return "pre-wrap";
default:
return whiteSpace;
case "nowrap":
return "pre";
case "normal":
return "pre-wrap";
default:
return whiteSpace;
}
}
@ -113,7 +135,7 @@ export class Text extends Single {
const { text: optionsText } = this.options;
const text = BI.isFunction(optionsText) ? optionsText() : optionsText;
return BI.isKey(text) ? Text.formatText(text + "") : text;
return BI.isKey(text) ? Text.formatText(`${text}`) : text;
}
_doRedMark(keyword) {
@ -162,10 +184,10 @@ export class Text extends Single {
}
const formatters = [];
Text.addTextFormatter = (formatter) => {
Text.addTextFormatter = formatter => {
formatters.push(formatter);
};
Text.formatText = (text) => {
Text.formatText = text => {
if (formatters.length > 0) {
for (let i = 0; i < formatters.length; i++) {
text = formatters[i](text);

52
src/base/single/a/a.js

@ -1,3 +1,6 @@
import { Text } from "../1.text";
import { shortcut, extend, createWidget } from "@/core";
/**
* 超链接
*
@ -6,32 +9,31 @@
* @extends BI.Text
* @abstract
*/
import { shortcut, extend, createWidget } from "../../../core";
import { Text } from "../1.text";
@shortcut()
export class A extends Text {
static xtype = "bi.a";
_defaultConfig() {
const conf = super._defaultConfig(...arguments);
return extend(conf, {
baseCls: `${conf.baseCls || ""} bi-a display-block`,
href: "",
target: "_blank",
el: null,
tagName: "a",
});
}
static xtype = "bi.a";
_defaultConfig() {
const conf = super._defaultConfig(...arguments);
return extend(conf, {
baseCls: `${conf.baseCls || ""} bi-a display-block`,
href: "",
target: "_blank",
el: null,
tagName: "a",
});
}
render() {
const { href, target, el } = this.options;
super.render();
this.element.attr({ href, target });
if (el) {
createWidget(el, {
element: this,
});
}
}
render() {
const { href, target, el } = this.options;
super.render();
this.element.attr({ href, target });
if (el) {
createWidget(el, {
element: this,
});
}
}
}

19
src/base/single/bar/bar.loading.js

@ -1,8 +1,9 @@
import { shortcut, emptyFn } from "@/core";
import { TextButton } from "../button";
import { Layout, CenterAdaptLayout, CardLayout, shortcut, emptyFn } from "@/core";
import { Single } from "../0.single";
@shortcut()
class LoadingBar extends Single {
export class LoadingBar extends Single {
static xtype = "bi.loading_bar";
_defaultConfig() {
@ -18,7 +19,7 @@ class LoadingBar extends Single {
render() {
this.loaded = BI.createWidget({
type: "bi.text_button",
type: TextButton.xtype,
cls: "loading-text bi-list-item-simple",
text: BI.i18nText("BI-Load_More"),
width: 120,
@ -29,27 +30,28 @@ class LoadingBar extends Single {
});
this.loading = BI.createWidget({
type: "bi.layout",
type: Layout.xtype,
width: this.options.height,
height: this.options.height,
cls: "loading-background cursor-default",
});
const loaded = BI.createWidget({
type: "bi.center_adapt",
type: CenterAdaptLayout.xtype,
items: [this.loaded],
});
const loading = BI.createWidget({
type: "bi.center_adapt",
type: CenterAdaptLayout.xtype,
items: [this.loading],
});
this.cardLayout = BI.createWidget({
type: "bi.card",
type: CardLayout.xtype,
element: this,
items: [
{
el: loaded,
cardName: "loaded",
}, {
},
{
el: loading,
cardName: "loading",
}
@ -80,4 +82,3 @@ class LoadingBar extends Single {
this.cardLayout.showCardByName("loading");
}
}

333
src/base/single/button/button.basic.js

@ -1,5 +1,17 @@
import {
Layout,
AbsoluteLayout,
emptyFn,
shortcut,
extend,
isFunction,
createWidget,
Widget,
isObject,
Controller
} from "@/core";
import { BubbleCombo } from "@/case/combo/bubblecombo/combo.bubble";
import { Single } from "../0.single";
import { emptyFn, shortcut, extend, isFunction, createWidget, Widget, isObject, Controller } from "../../../core";
/**
* guy
@ -18,7 +30,9 @@ export class BasicButton extends Single {
const conf = super._defaultConfig(...arguments);
return extend(conf, {
_baseCls: `${conf._baseCls || ""} bi-basic-button${conf.invalid ? "" : " cursor-pointer"}${(BI.isIE() && BI.getIEVersion() < 10) ? " hack" : ""}`,
_baseCls: `${conf._baseCls || ""} bi-basic-button${conf.invalid ? "" : " cursor-pointer"}${
BI.isIE() && BI.getIEVersion() < 10 ? " hack" : ""
}`,
// el: {} // 可以通过el来创建button元素
value: "",
stopEvent: false,
@ -40,9 +54,11 @@ export class BasicButton extends Single {
_init() {
const opts = this.options;
opts.selected = isFunction(opts.selected) ? this.__watch(opts.selected, (context, newValue) => {
this.setSelected(newValue);
}) : opts.selected;
opts.selected = isFunction(opts.selected)
? this.__watch(opts.selected, (context, newValue) => {
this.setSelected(newValue);
})
: opts.selected;
super._init(arguments);
if (opts.shadow) {
@ -75,20 +91,22 @@ export class BasicButton extends Single {
const assertMask = () => {
if (!this.$mask) {
this.$mask = createWidget(isObject(o.shadow) ? o.shadow : {}, {
type: "bi.layout",
type: Layout.xtype,
cls: "bi-button-mask",
});
this.$mask.invisible();
createWidget({
type: "bi.absolute",
type: AbsoluteLayout.xtype,
element: this,
items: [{
el: this.$mask,
left: 0,
right: 0,
top: 0,
bottom: 0,
}],
items: [
{
el: this.$mask,
left: 0,
right: 0,
top: 0,
bottom: 0,
},
],
});
}
};
@ -99,7 +117,7 @@ export class BasicButton extends Single {
this.$mask.invisible();
}
});
this.element.on(`mouseenter.${this.getName()}`, e => {
this.element.on(`mouseenter.${this.getName()}`, (e) => {
if (this.element.__isMouseInBounds__(e)) {
if (this.isEnabled() && !this._hover && (o.isShadowShowingOnSelected || !this.isSelected())) {
assertMask();
@ -107,7 +125,7 @@ export class BasicButton extends Single {
}
}
});
this.element.on(`mousemove.${this.getName()}`, e => {
this.element.on(`mousemove.${this.getName()}`, (e) => {
if (!this.element.__isMouseInBounds__(e)) {
if (this.isEnabled() && !this._hover) {
assertMask();
@ -140,7 +158,7 @@ export class BasicButton extends Single {
return bubble;
};
const clk = e => {
const clk = (e) => {
ev(e);
if (!this.isEnabled() || !this.isValid()) {
return;
@ -152,50 +170,56 @@ export class BasicButton extends Single {
if (BI.isNull(this.combo)) {
let popup;
createWidget({
type: "bi.absolute",
type: AbsoluteLayout.xtype,
element: this,
items: [{
el: {
type: "bi.bubble_combo",
trigger: "",
// bubble的提示不需要一直存在在界面上
destroyWhenHide: true,
ref: _ref => {
this.combo = _ref;
},
items: [
{
el: {
type: "bi.layout",
height: "100%",
},
popup: {
type: "bi.text_bubble_bar_popup_view",
text: getBubble(),
ref: _ref => {
popup = _ref;
type: BubbleCombo.xtype,
trigger: "",
// bubble的提示不需要一直存在在界面上
destroyWhenHide: true,
ref: (_ref) => {
this.combo = _ref;
},
el: {
type: Layout.xtype,
height: "100%",
},
listeners: [{
eventName: BI.BubblePopupBarView.EVENT_CLICK_TOOLBAR_BUTTON,
action: (...args) => {
const [v] = args;
this.combo.hideView();
if (v) {
onClick.apply(this, args);
}
popup: {
type: "bi.text_bubble_bar_popup_view",
text: getBubble(),
ref: (_ref) => {
popup = _ref;
},
}],
},
listeners: [{
eventName: BI.BubbleCombo.EVENT_BEFORE_POPUPVIEW,
action () {
popup.populate(getBubble());
listeners: [
{
eventName: BI.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,
},
left: 0,
right: 0,
bottom: 0,
top: 0,
}],
],
});
}
if (this.combo.isViewVisible()) {
@ -209,112 +233,119 @@ export class BasicButton extends Single {
onClick.apply(this, arguments);
};
const triggerArr = (o.trigger || "").split(",");
triggerArr.forEach(trigger => {
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 (BI.DOM.isExist(this) && !hand.__isMouseInBounds__(e) && mouseDown === true && !selected) {
// self.setSelected(!self.isSelected());
this._trigger();
case "mouseup":
hand.mousedown(() => {
mouseDown = true;
});
hand.mouseup((e) => {
if (mouseDown === true) {
clk(e);
}
mouseDown = false;
Widget._renderEngine.createElement(document).unbind(`mouseup.${this.getName()}`);
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 (
BI.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);
// }
});
if (mouseDown === true) {
return;
}
if (this.isSelected()) {
selected = true;
} else {
clk(e);
}
mouseDown = true;
ev(e);
// }
});
hand.mouseup(e => {
// if (e.button === 0) {
if (BI.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;
hand.mouseup((e) => {
// if (e.button === 0) {
if (BI.DOM.isExist(this) && mouseDown === true && selected === true) {
clk(e);
}
mouseDown = false;
selected = 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 => {
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);
});
}
hand.click(clk);
// enter键等同于点击
o.attributes && o.attributes.zIndex >= 0 && hand.keyup(e => {
if (e.keyCode === BI.KeyCode.ENTER) {
clk(e);
break;
default:
if (o.stopEvent || o.stopPropagation) {
hand.mousedown((e) => {
ev(e);
});
}
});
break;
hand.click(clk);
// enter键等同于点击
o.attributes &&
o.attributes.zIndex >= 0 &&
hand.keyup((e) => {
if (e.keyCode === BI.KeyCode.ENTER) {
clk(e);
}
});
break;
}
});
// 之后的300ms点击无效
const onClick = o.debounce ? BI.debounce(this._doClick, BI.EVENT_RESPONSE_TIME, {
leading: true,
trailing: false,
}) : this._doClick;
const onClick = o.debounce
? BI.debounce(this._doClick, BI.EVENT_RESPONSE_TIME, {
leading: true,
trailing: false,
})
: this._doClick;
function ev(e) {
if (o.stopEvent) {
@ -332,9 +363,11 @@ export class BasicButton extends Single {
return;
}
if (!this.isDisableSelected()) {
this.isForceSelected() ? this.setSelected(true) :
(this.isForceNotSelected() ? this.setSelected(false) :
this.setSelected(!this.isSelected()));
this.isForceSelected()
? this.setSelected(true)
: this.isForceNotSelected()
? this.setSelected(false)
: this.setSelected(!this.isSelected());
}
if (this.isValid()) {
const v = this.getValue();
@ -367,13 +400,9 @@ export class BasicButton extends Single {
/**
* 子类可以得写这个方法如果返回为 true则可以阻止 handler 的触发
*/
beforeClick() {
beforeClick() {}
}
doClick() {
}
doClick() {}
handle() {
return this;
@ -457,5 +486,3 @@ export class BasicButton extends Single {
super.empty(...arguments);
}
}

2
src/base/single/button/button.node.js

@ -1,5 +1,5 @@
import { BasicButton } from "./button.basic";
import { shortcut, extend, Controller } from "../../../core";
import { shortcut, extend, Controller } from "@/core";
/**
* 表示一个可以展开的节点, 不仅有选中状态而且有展开状态

9
src/base/single/button/buttons/button.icon.js

@ -1,5 +1,6 @@
import { Icon } from "../../icon/icon";
import { DefaultLayout, CenterAdaptLayout, shortcut, extend, isNumber, createWidget, isNull } from "@/core";
import { BasicButton } from "../button.basic";
import { shortcut, extend, isNumber, createWidget, isNull } from "../../../../core";
/**
* @class IconButton
@ -33,14 +34,14 @@ export class IconButton extends BasicButton {
textAlign: "center",
});
this.icon = createWidget({
type: "bi.icon",
type: Icon.xtype,
width: o.iconWidth,
height: o.iconHeight,
});
if (isNumber(o.height) && o.height > 0 && isNull(o.iconWidth) && isNull(o.iconHeight)) {
this.element.css("lineHeight", BI.pixFormat(o.height));
createWidget({
type: "bi.default",
type: DefaultLayout.xtype,
element: this,
hgap: o.hgap,
vgap: o.vgap,
@ -54,7 +55,7 @@ export class IconButton extends BasicButton {
this.element.css("lineHeight", "1");
createWidget({
element: this,
type: "bi.center_adapt",
type: CenterAdaptLayout.xtype,
hgap: o.hgap,
vgap: o.vgap,
lgap: o.lgap,

10
src/base/single/button/buttons/button.image.js

@ -1,6 +1,6 @@
import { Img } from "../../img/img";
import { CenterAdaptLayout, AdaptiveLayout, shortcut, extend, isNumber, createWidget } from "@/core";
import { BasicButton } from "../button.basic";
import { shortcut, extend, isNumber, createWidget } from "../../../../core";
/**
* 图片的button
@ -28,20 +28,20 @@ export class ImageButton extends BasicButton {
render() {
const o = this.options;
this.image = createWidget({
type: "bi.img",
type: Img.xtype,
width: o.iconWidth,
height: o.iconHeight,
src: o.src,
});
if (isNumber(o.iconWidth) || isNumber(o.iconHeight)) {
createWidget({
type: "bi.center_adapt",
type: CenterAdaptLayout.xtype,
element: this,
items: [this.image],
});
} else {
createWidget({
type: "bi.adaptive",
type: AdaptiveLayout.xtype,
element: this,
items: [this.image],
scrollable: false,

41
src/base/single/button/buttons/button.js

@ -1,5 +1,6 @@
import { CenterAdaptLayout, isNumber, shortcut, isPlainObject, createWidget } from "@/core";
import { Label, IconLabel } from "../../label";
import { BasicButton } from "../button.basic";
import { isNumber, shortcut, isPlainObject, createWidget } from "../../../../core";
function isVertical(position) {
return position === "top" || position === "bottom";
@ -19,7 +20,7 @@ const loadingCls = "button-loading-font anim-rotate";
export class Button extends BasicButton {
_const = {
iconWidth: 18,
}
};
static xtype = "bi.button";
static EVENT_CHANGE = "EVENT_CHANGE";
@ -34,14 +35,14 @@ export class Button extends BasicButton {
adaptiveHeight += props.iconGap || 0;
const tGap = props.tgap || props.vgap || 2;
const bGap = props.bgap || props.vgap || 2;
adaptiveHeight += (tGap + bGap);
adaptiveHeight += tGap + bGap;
}
const clearMinWidth = props.block === true || props.clear === true || props.plain;
return {
...conf,
baseCls: `${conf.baseCls || ""} bi-button${(BI.isIE() && BI.isIE9Below()) ? " hack" : ""}`,
baseCls: `${conf.baseCls || ""} bi-button${BI.isIE() && BI.isIE9Below() ? " hack" : ""}`,
attributes: {
tabIndex: 1,
},
@ -62,7 +63,7 @@ export class Button extends BasicButton {
whiteSpace: "nowrap",
textWidth: null,
textHeight: null,
hgap: props.clear ? 0 : (props.plain && !props.text ? 4 : 10),
hgap: props.clear ? 0 : props.plain && !props.text ? 4 : 10,
vgap: 0,
tgap: 0,
bgap: 0,
@ -79,7 +80,7 @@ export class Button extends BasicButton {
// bi.center_adapt 作用:让 hgap 不影响 iconGap。
createWidget({
type: "bi.center_adapt",
type: CenterAdaptLayout.xtype,
horizontalAlign: o.textAlign,
element: this,
ref: ref => {
@ -107,7 +108,8 @@ export class Button extends BasicButton {
const o = this.options;
// 由于button默认情况下有个边框,所以要主动算行高
let lineHeight, textHeight = o.textHeight;
let lineHeight,
textHeight = o.textHeight;
let hasBorder = false;
if (isNumber(o.height)) {
if (!isVertical(o.iconPosition)) {
@ -128,13 +130,13 @@ export class Button extends BasicButton {
const iconInvisible = !(o.loading || o.iconCls || o.icon || defaultRenderIcon);
let maxTextWidth = Math.max(o.minWidth, o.width);
maxTextWidth -= (o.hgap * 2 + o.iconGap);
maxTextWidth -= o.hgap * 2 + o.iconGap;
// 减去图标水平占位宽度
maxTextWidth -= iconInvisible || isVertical(o.iconPosition) ? 0 : this._const.iconWidth;
const textWidth = BI.isNull(o.textWidth) ? maxTextWidth : Math.min(o.textWidth, maxTextWidth);
this.text = createWidget({
type: "bi.label",
type: Label.xtype,
text: o.text,
whiteSpace: o.whiteSpace,
textAlign: o.textAlign,
@ -155,8 +157,8 @@ export class Button extends BasicButton {
this.icon = createWidget(o.icon);
} else {
this.icon = createWidget({
type: "bi.icon_label",
cls: o.loading ? loadingCls : (o.iconCls || o.icon),
type: IconLabel.xtype,
cls: o.loading ? loadingCls : o.iconCls || o.icon,
width: this._const.iconWidth,
height: BI.toPix(lineHeight, hasBorder ? 2 : 0),
lineHeight: BI.toPix(lineHeight, hasBorder ? 2 : 0),
@ -179,12 +181,14 @@ export class Button extends BasicButton {
items.reverse();
}
return [{
type: isVertical(o.iconPosition) ? "bi.vertical" : "bi.horizontal",
horizontalAlign: "center",
verticalAlign: "middle",
items,
}];
return [
{
type: isVertical(o.iconPosition) ? "bi.vertical" : "bi.horizontal",
horizontalAlign: "center",
verticalAlign: "middle",
items,
}
];
}
doClick() {
@ -272,4 +276,3 @@ export class Button extends BasicButton {
this.text.unHighLight(...arguments);
}
}

5
src/base/single/button/buttons/button.text.js

@ -1,5 +1,6 @@
import { Label } from "../../label";
import { BasicButton } from "../button.basic";
import { shortcut, extend, createWidget, isArray } from "../../../../core";
import { shortcut, extend, createWidget, isArray } from "@/core";
/**
* guy
@ -33,7 +34,7 @@ export class TextButton extends BasicButton {
render() {
const o = this.options;
this.text = createWidget({
type: "bi.label",
type: Label.xtype,
element: this,
textAlign: o.textAlign,
whiteSpace: o.whiteSpace,

34
src/base/single/button/index.js

@ -1,17 +1,17 @@
export { BasicButton } from "./button.basic";
export { NodeButton } from "./button.node";
export { Button } from "./buttons/button";
export { IconButton } from "./buttons/button.icon";
export { ImageButton } from "./buttons/button.image";
export { TextButton } from "./buttons/button.text";
export { BlankIconIconTextItem } from "./listitem/blankiconicontextitem";
export { BlankIconTextIconItem } from "./listitem/blankicontexticonitem";
export { BlankIconTextItem } from "./listitem/blankicontextitem";
export { IconTextIconItem } from "./listitem/icontexticonitem";
export { IconTextItem } from "./listitem/icontextitem";
export { TextIconItem } from "./listitem/texticonitem";
export { TextItem } from "./listitem/textitem";
export { IconTextIconNode } from "./node/icontexticonnode";
export { IconTextNode } from "./node/icontextnode";
export { TextIconNode } from "./node/texticonnode";
export { TextNode } from "./node/textnode";
export { BasicButton } from "./button.basic";
export { NodeButton } from "./button.node";
export { Button } from "./buttons/button";
export { IconButton } from "./buttons/button.icon";
export { ImageButton } from "./buttons/button.image";
export { TextButton } from "./buttons/button.text";
export { BlankIconIconTextItem } from "./listitem/blankiconicontextitem";
export { BlankIconTextIconItem } from "./listitem/blankicontexticonitem";
export { BlankIconTextItem } from "./listitem/blankicontextitem";
export { IconTextIconItem } from "./listitem/icontexticonitem";
export { IconTextItem } from "./listitem/icontextitem";
export { TextIconItem } from "./listitem/texticonitem";
export { TextItem } from "./listitem/textitem";
export { IconTextIconNode } from "./node/icontexticonnode";
export { IconTextNode } from "./node/icontextnode";
export { TextIconNode } from "./node/texticonnode";
export { TextNode } from "./node/textnode";

74
src/base/single/button/listitem/blankiconicontextitem.js

@ -1,5 +1,6 @@
import { VerticalAdaptLayout, Layout, shortcut, extend } from "@/core";
import { IconLabel, Label } from "../../label";
import { BasicButton } from "../button.basic";
import { shortcut, extend } from "../../../../core";
/**
* 带有一个占位
@ -34,42 +35,47 @@ export class BlankIconIconTextItem extends BasicButton {
const o = this.options;
return {
type: "bi.vertical_adapt",
type: VerticalAdaptLayout.xtype,
columnSize: [o.blankWidth, o.leftIconWrapperWidth || o.height, o.rightIconWrapperWidth || o.height, "fill"],
items: [{
type: "bi.layout",
width: o.blankWidth,
}, {
type: "bi.icon_label",
cls: o.iconCls1,
width: o.leftIconWrapperWidth || o.height,
height: o.height,
iconWidth: o.iconWidth,
iconHeight: o.iconHeight,
}, {
type: "bi.icon_label",
cls: o.iconCls2,
width: o.rightIconWrapperWidth || o.height,
height: o.height,
iconWidth: o.iconWidth,
iconHeight: o.iconHeight,
}, {
el: {
type: "bi.label",
ref: _ref => {
this.text = _ref;
},
textAlign: "left",
hgap: o.textHgap,
vgap: o.textVgap,
lgap: o.textLgap,
rgap: o.textRgap,
text: o.text,
value: o.value,
keyword: o.keyword,
items: [
{
type: Layout.xtype,
width: o.blankWidth,
},
{
type: IconLabel.xtype,
cls: o.iconCls1,
width: o.leftIconWrapperWidth || o.height,
height: o.height,
iconWidth: o.iconWidth,
iconHeight: o.iconHeight,
},
}],
{
type: IconLabel.xtype,
cls: o.iconCls2,
width: o.rightIconWrapperWidth || o.height,
height: o.height,
iconWidth: o.iconWidth,
iconHeight: o.iconHeight,
},
{
el: {
type: Label.xtype,
ref: _ref => {
this.text = _ref;
},
textAlign: "left",
hgap: o.textHgap,
vgap: o.textVgap,
lgap: o.textLgap,
rgap: o.textRgap,
text: o.text,
value: o.value,
keyword: o.keyword,
height: o.height,
},
}
],
};
}

75
src/base/single/button/listitem/blankicontexticonitem.js

@ -1,5 +1,6 @@
import { VerticalAdaptLayout, Layout, shortcut, extend } from "@/core";
import { IconLabel, Label } from "../../label";
import { BasicButton } from "../button.basic";
import { shortcut, extend } from "../../../../core";
/**
* guy
@ -35,42 +36,47 @@ export class BlankIconTextIconItem extends BasicButton {
const o = this.options;
return {
type: "bi.vertical_adapt",
type: VerticalAdaptLayout.xtype,
columnSize: [o.blankWidth, o.leftIconWrapperWidth || o.height, "fill", o.rightIconWrapperWidth || o.height],
items: [{
type: "bi.layout",
width: o.blankWidth,
}, {
type: "bi.icon_label",
cls: o.iconCls1,
width: o.leftIconWrapperWidth || o.height,
height: o.height,
iconWidth: o.iconWidth,
iconHeight: o.iconHeight,
}, {
el: {
type: "bi.label",
ref: _ref => {
this.text = _ref;
},
textAlign: "left",
hgap: o.textHgap,
vgap: o.textVgap,
lgap: o.textLgap,
rgap: o.textRgap,
text: o.text,
value: o.value,
keyword: o.keyword,
items: [
{
type: Layout.xtype,
width: o.blankWidth,
},
{
type: IconLabel.xtype,
cls: o.iconCls1,
width: o.leftIconWrapperWidth || o.height,
height: o.height,
iconWidth: o.iconWidth,
iconHeight: o.iconHeight,
},
{
el: {
type: Label.xtype,
ref: _ref => {
this.text = _ref;
},
textAlign: "left",
hgap: o.textHgap,
vgap: o.textVgap,
lgap: o.textLgap,
rgap: o.textRgap,
text: o.text,
value: o.value,
keyword: o.keyword,
height: o.height,
},
},
}, {
type: "bi.icon_label",
cls: o.iconCls2,
width: o.rightIconWrapperWidth || o.height,
height: o.height,
iconWidth: o.iconWidth,
iconHeight: o.iconHeight,
}],
{
type: IconLabel.xtype,
cls: o.iconCls2,
width: o.rightIconWrapperWidth || o.height,
height: o.height,
iconWidth: o.iconWidth,
iconHeight: o.iconHeight,
}
],
};
}
@ -115,4 +121,3 @@ export class BlankIconTextIconItem extends BasicButton {
return this.text.getText();
}
}

61
src/base/single/button/listitem/blankicontextitem.js

@ -1,5 +1,6 @@
import { VerticalAdaptLayout, Layout, extend, shortcut } from "@/core";
import { IconLabel, Label } from "../../label";
import { BasicButton } from "../button.basic";
import { extend, shortcut } from "../../../../core";
/**
* 带有一个占位
@ -33,36 +34,40 @@ export class BlankIconTextItem extends BasicButton {
const o = this.options;
return {
type: "bi.vertical_adapt",
type: VerticalAdaptLayout.xtype,
columnSize: [o.blankWidth, o.iconWrapperWidth || o.height, "fill"],
items: [{
type: "bi.layout",
width: o.blankWidth,
}, {
type: "bi.icon_label",
cls: o.iconCls,
width: o.iconWrapperWidth || o.height,
height: o.height,
iconWidth: o.iconWidth,
iconHeight: o.iconHeight,
}, {
el: {
type: "bi.label",
ref: _ref => {
this.text = _ref;
},
cls: "list-item-text",
textAlign: "left",
hgap: o.textHgap,
vgap: o.textVgap,
lgap: o.textLgap,
rgap: o.textRgap,
text: o.text,
value: o.value,
keyword: o.keyword,
items: [
{
type: Layout.xtype,
width: o.blankWidth,
},
{
type: IconLabel.xtype,
cls: o.iconCls,
width: o.iconWrapperWidth || o.height,
height: o.height,
iconWidth: o.iconWidth,
iconHeight: o.iconHeight,
},
}],
{
el: {
type: Label.xtype,
ref: _ref => {
this.text = _ref;
},
cls: "list-item-text",
textAlign: "left",
hgap: o.textHgap,
vgap: o.textVgap,
lgap: o.textLgap,
rgap: o.textRgap,
text: o.text,
value: o.value,
keyword: o.keyword,
height: o.height,
},
}
],
};
}

67
src/base/single/button/listitem/icontexticonitem.js

@ -1,5 +1,6 @@
import { VerticalAdaptLayout, extend, shortcut } from "@/core";
import { IconLabel, Label } from "../../label";
import { BasicButton } from "../button.basic";
import { extend, shortcut } from "../../../../core";
/**
* guy
@ -35,39 +36,43 @@ export class IconTextIconItem extends BasicButton {
const o = this.options;
return {
type: "bi.vertical_adapt",
type: VerticalAdaptLayout.xtype,
columnSize: [o.leftIconWrapperWidth || o.height, "fill", o.rightIconWrapperWidth || o.height],
items: [{
type: "bi.icon_label",
cls: o.iconCls1,
width: o.leftIconWrapperWidth || o.height,
height: o.height,
iconWidth: o.iconWidth,
iconHeight: o.iconHeight,
}, {
el: {
type: "bi.label",
ref: _ref => {
this.text = _ref;
},
textAlign: "left",
hgap: o.textHgap,
vgap: o.textVgap,
lgap: o.textLgap,
rgap: o.textRgap,
text: o.text,
value: o.value,
keyword: o.keyword,
items: [
{
type: IconLabel.xtype,
cls: o.iconCls1,
width: o.leftIconWrapperWidth || o.height,
height: o.height,
iconWidth: o.iconWidth,
iconHeight: o.iconHeight,
},
{
el: {
type: Label.xtype,
ref: _ref => {
this.text = _ref;
},
textAlign: "left",
hgap: o.textHgap,
vgap: o.textVgap,
lgap: o.textLgap,
rgap: o.textRgap,
text: o.text,
value: o.value,
keyword: o.keyword,
height: o.height,
},
},
}, {
type: "bi.icon_label",
cls: o.iconCls2,
width: o.rightIconWrapperWidth || o.height,
height: o.height,
iconWidth: o.iconWidth,
iconHeight: o.iconHeight,
}],
{
type: IconLabel.xtype,
cls: o.iconCls2,
width: o.rightIconWrapperWidth || o.height,
height: o.height,
iconWidth: o.iconWidth,
iconHeight: o.iconHeight,
}
],
};
}

54
src/base/single/button/listitem/icontextitem.js

@ -1,5 +1,6 @@
import { VerticalAdaptLayout, extend, shortcut } from "@/core";
import { IconLabel, Label } from "../../label";
import { BasicButton } from "../button.basic";
import { extend, shortcut } from "../../../../core";
/**
* guy
@ -34,33 +35,36 @@ export class IconTextItem extends BasicButton {
const o = this.options;
return {
type: "bi.vertical_adapt",
type: VerticalAdaptLayout.xtype,
columnSize: [o.iconWrapperWidth || o.height, "fill"],
items: [{
type: "bi.icon_label",
cls: o.iconCls,
width: o.iconWrapperWidth || o.height,
height: o.height,
iconWidth: o.iconWidth,
iconHeight: o.iconHeight,
}, {
el: {
type: "bi.label",
ref: _ref => {
this.text = _ref;
},
cls: "list-item-text",
textAlign: "left",
hgap: o.textHgap,
vgap: o.textVgap,
lgap: o.textLgap,
rgap: o.textRgap,
text: o.text,
value: o.value,
keyword: o.keyword,
items: [
{
type: IconLabel.xtype,
cls: o.iconCls,
width: o.iconWrapperWidth || o.height,
height: o.height,
iconWidth: o.iconWidth,
iconHeight: o.iconHeight,
},
}],
{
el: {
type: Label.xtype,
ref: _ref => {
this.text = _ref;
},
cls: "list-item-text",
textAlign: "left",
hgap: o.textHgap,
vgap: o.textVgap,
lgap: o.textLgap,
rgap: o.textRgap,
text: o.text,
value: o.value,
keyword: o.keyword,
height: o.height,
},
}
],
};
}

56
src/base/single/button/listitem/texticonitem.js

@ -1,5 +1,6 @@
import { VerticalAdaptLayout, extend, shortcut } from "@/core";
import { Label, IconLabel } from "../../label";
import { BasicButton } from "../button.basic";
import { extend, shortcut } from "../../../../core";
/**
*
@ -12,7 +13,7 @@ import { extend, shortcut } from "../../../../core";
@shortcut()
export class TextIconItem extends BasicButton {
static xtype = "bi.text_icon_item";
static EVENT_CHANGE = "EVENT_CHANGE"
static EVENT_CHANGE = "EVENT_CHANGE";
_defaultConfig() {
const conf = super._defaultConfig(...arguments);
@ -34,33 +35,36 @@ export class TextIconItem extends BasicButton {
const o = this.options;
return {
type: "bi.vertical_adapt",
type: VerticalAdaptLayout.xtype,
columnSize: ["fill", o.iconWrapperWidth || o.height],
items: [{
el: {
type: "bi.label",
ref: _ref => {
this.text = _ref;
items: [
{
el: {
type: Label.xtype,
ref: _ref => {
this.text = _ref;
},
cls: "list-item-text",
textAlign: "left",
hgap: o.textHgap,
vgap: o.textVgap,
lgap: o.textLgap,
rgap: o.textRgap,
text: o.text,
value: o.value,
keyword: o.keyword,
height: o.height,
},
cls: "list-item-text",
textAlign: "left",
hgap: o.textHgap,
vgap: o.textVgap,
lgap: o.textLgap,
rgap: o.textRgap,
text: o.text,
value: o.value,
keyword: o.keyword,
height: o.height,
},
}, {
type: "bi.icon_label",
cls: o.iconCls,
width: o.iconWrapperWidth || o.height,
height: o.height,
iconWidth: o.iconWidth,
iconHeight: o.iconHeight,
}],
{
type: IconLabel.xtype,
cls: o.iconCls,
width: o.iconWrapperWidth || o.height,
height: o.height,
iconWidth: o.iconWidth,
iconHeight: o.iconHeight,
}
],
};
}

5
src/base/single/button/listitem/textitem.js

@ -1,5 +1,6 @@
import { Label } from "../../label";
import { BasicButton } from "../button.basic";
import { extend, shortcut, createWidget } from "../../../../core";
import { extend, shortcut, createWidget } from "@/core";
/**
* guy
@ -31,7 +32,7 @@ export class TextItem extends BasicButton {
render() {
const o = this.options;
this.text = createWidget({
type: "bi.label",
type: Label.xtype,
element: this,
textAlign: o.textAlign,
whiteSpace: o.whiteSpace,

67
src/base/single/button/node/icontexticonnode.js

@ -1,5 +1,6 @@
import { VerticalAdaptLayout, extend, shortcut } from "@/core";
import { IconLabel, Label } from "../../label";
import { NodeButton } from "../button.node";
import { extend, shortcut } from "../../../../core";
/**
* guy
@ -32,39 +33,43 @@ export class IconTextIconNode extends NodeButton {
const o = this.options;
return {
type: "bi.vertical_adapt",
type: VerticalAdaptLayout.xtype,
columnSize: [o.leftIconWrapperWidth || o.height, "fill", o.rightIconWrapperWidth || o.height],
items: [{
type: "bi.icon_label",
cls: o.iconCls1,
width: o.leftIconWrapperWidth || o.height,
height: o.height,
iconWidth: o.iconWidth,
iconHeight: o.iconHeight,
}, {
el: {
type: "bi.label",
ref: _ref => {
this.text = _ref;
},
textAlign: "left",
hgap: o.textHgap,
vgap: o.textVgap,
lgap: o.textLgap,
rgap: o.textRgap,
text: o.text,
value: o.value,
keyword: o.keyword,
items: [
{
type: IconLabel.xtype,
cls: o.iconCls1,
width: o.leftIconWrapperWidth || o.height,
height: o.height,
iconWidth: o.iconWidth,
iconHeight: o.iconHeight,
},
{
el: {
type: Label.xtype,
ref: _ref => {
this.text = _ref;
},
textAlign: "left",
hgap: o.textHgap,
vgap: o.textVgap,
lgap: o.textLgap,
rgap: o.textRgap,
text: o.text,
value: o.value,
keyword: o.keyword,
height: o.height,
},
},
}, {
type: "bi.icon_label",
cls: o.iconCls2,
width: o.rightIconWrapperWidth || o.height,
height: o.height,
iconWidth: o.iconWidth,
iconHeight: o.iconHeight,
}],
{
type: IconLabel.xtype,
cls: o.iconCls2,
width: o.rightIconWrapperWidth || o.height,
height: o.height,
iconWidth: o.iconWidth,
iconHeight: o.iconHeight,
}
],
};
}

55
src/base/single/button/node/icontextnode.js

@ -1,5 +1,6 @@
import { VerticalAdaptLayout, extend, shortcut } from "@/core";
import { IconLabel, Label } from "../../label";
import { NodeButton } from "../button.node";
import { extend, shortcut } from "../../../../core";
/**
* guy
@ -31,33 +32,36 @@ export class IconTextNode extends NodeButton {
const o = this.options;
return {
type: "bi.vertical_adapt",
type: VerticalAdaptLayout.xtype,
columnSize: [o.iconWrapperWidth || o.height, "fill"],
items: [{
type: "bi.icon_label",
cls: o.iconCls,
width: o.iconWrapperWidth || o.height,
height: o.height,
iconWidth: o.iconWidth,
iconHeight: o.iconHeight,
}, {
el: {
type: "bi.label",
ref: _ref => {
this.text = _ref;
},
cls: "list-item-text",
textAlign: "left",
hgap: o.textHgap,
vgap: o.textVgap,
lgap: o.textLgap,
rgap: o.textRgap,
text: o.text,
value: o.value,
keyword: o.keyword,
items: [
{
type: IconLabel.xtype,
cls: o.iconCls,
width: o.iconWrapperWidth || o.height,
height: o.height,
iconWidth: o.iconWidth,
iconHeight: o.iconHeight,
},
}],
{
el: {
type: Label.xtype,
ref: _ref => {
this.text = _ref;
},
cls: "list-item-text",
textAlign: "left",
hgap: o.textHgap,
vgap: o.textVgap,
lgap: o.textLgap,
rgap: o.textRgap,
text: o.text,
value: o.value,
keyword: o.keyword,
height: o.height,
},
}
],
};
}
@ -94,4 +98,3 @@ export class IconTextNode extends NodeButton {
this.text.unRedMark(...arguments);
}
}

55
src/base/single/button/node/texticonnode.js

@ -1,5 +1,6 @@
import { VerticalAdaptLayout, extend, shortcut } from "@/core";
import { Label, IconLabel } from "../../label";
import { NodeButton } from "../button.node";
import { extend, shortcut } from "../../../../core";
/**
* Created by GUY on 2015/9/9.
@ -8,7 +9,6 @@ import { extend, shortcut } from "../../../../core";
*/
@shortcut()
export class TextIconNode extends NodeButton {
static EVENT_CHANGE = "EVENT_CHANGE";
static xtype = "bi.text_icon_node";
@ -31,33 +31,36 @@ export class TextIconNode extends NodeButton {
const o = this.options;
return {
type: "bi.vertical_adapt",
type: VerticalAdaptLayout.xtype,
columnSize: ["fill", o.iconWrapperWidth || o.height],
items: [{
el: {
type: "bi.label",
ref: _ref => {
this.text = _ref;
items: [
{
el: {
type: Label.xtype,
ref: _ref => {
this.text = _ref;
},
cls: "list-item-text",
textAlign: "left",
hgap: o.textHgap,
vgap: o.textVgap,
lgap: o.textLgap,
rgap: o.textRgap,
text: o.text,
value: o.value,
keyword: o.keyword,
height: o.height,
},
cls: "list-item-text",
textAlign: "left",
hgap: o.textHgap,
vgap: o.textVgap,
lgap: o.textLgap,
rgap: o.textRgap,
text: o.text,
value: o.value,
keyword: o.keyword,
height: o.height,
},
}, {
type: "bi.icon_label",
cls: o.iconCls,
width: o.iconWrapperWidth || o.height,
height: o.height,
iconWidth: o.iconWidth,
iconHeight: o.iconHeight,
}],
{
type: IconLabel.xtype,
cls: o.iconCls,
width: o.iconWrapperWidth || o.height,
height: o.height,
iconWidth: o.iconWidth,
iconHeight: o.iconHeight,
}
],
};
}

10
src/base/single/button/node/textnode.js

@ -1,5 +1,6 @@
import { Label } from "../../label";
import { NodeButton } from "../button.node";
import { extend, shortcut, createWidget } from "../../../../core";
import { extend, shortcut, createWidget } from "@/core";
/**
* guy
@ -10,10 +11,9 @@ import { extend, shortcut, createWidget } from "../../../../core";
*/
@shortcut()
export class TextNode extends NodeButton {
static xtype = "bi.text_node"
static EVENT_CHANGE = "EVENT_CHANGE"
static xtype = "bi.text_node";
static EVENT_CHANGE = "EVENT_CHANGE";
_defaultConfig() {
const conf = super._defaultConfig(...arguments);
@ -32,7 +32,7 @@ export class TextNode extends NodeButton {
render() {
const o = this.options;
this.text = createWidget({
type: "bi.label",
type: Label.xtype,
element: this,
textAlign: o.textAlign,
whiteSpace: o.whiteSpace,

67
src/base/single/editor/editor.js

@ -1,12 +1,25 @@
import { Input } from "../input";
import {
AbsoluteLayout,
shortcut,
Controller,
extend,
createWidget,
isKey,
isEmptyString,
isFunction,
isNull,
trim
} from "@/core";
import { Label } from "../label";
import { Single } from "../0.single";
import { Bubbles } from "@/base";
/**
* Created by GUY on 2015/4/15.
* @class BI.Editor
* @extends BI.Single
*/
import { shortcut, Controller, extend, createWidget, isKey, isEmptyString, isFunction, isNull, trim } from "../../../core";
import { Single } from "../0.single";
import { Input } from "../input/input";
import { Bubbles } from "../../0.base";
@shortcut()
export class Editor extends Single {
@ -57,19 +70,34 @@ export class Editor extends Single {
}
render() {
const { value, watermark, validationChecker, quitChecker, allowBlank, inputType, hgap, vgap, lgap, rgap, tgap, bgap } = this.options;
// 密码输入框设置autocomplete="new-password"的情况下Firefox和chrome不会自动填充密码
const autocomplete = this.options.autocomplete ? ` autocomplete=${this.options.autocomplete}` : "";
this.editor = this.addWidget(createWidget({
type: "bi.input",
element: `<input type='${inputType}'${autocomplete} />`,
root: true,
const {
value,
watermark,
validationChecker,
quitChecker,
allowBlank,
}));
inputType,
hgap,
vgap,
lgap,
rgap,
tgap,
bgap,
} = this.options;
// 密码输入框设置autocomplete="new-password"的情况下Firefox和chrome不会自动填充密码
const autocomplete = this.options.autocomplete ? ` autocomplete=${this.options.autocomplete}` : "";
this.editor = this.addWidget(
createWidget({
type: Input.xtype,
element: `<input type='${inputType}'${autocomplete} />`,
root: true,
value,
watermark,
validationChecker,
quitChecker,
allowBlank,
})
);
this.editor.element.css({
width: "100%",
height: "100%",
@ -82,7 +110,7 @@ export class Editor extends Single {
const items = [
{
el: {
type: "bi.absolute",
type: AbsoluteLayout.xtype,
ref: _ref => {
this.contentWrapper = _ref;
},
@ -104,7 +132,7 @@ export class Editor extends Single {
];
createWidget({
type: "bi.absolute",
type: AbsoluteLayout.xtype,
element: this,
items,
});
@ -157,9 +185,10 @@ export class Editor extends Single {
this.editor.on(Input.EVENT_RESTRICT, (...args) => {
this._checkWaterMark();
const tip = this._setErrorVisible(true);
tip && tip.element.fadeOut(100, () => {
tip.element.fadeIn(100);
});
tip &&
tip.element.fadeOut(100, () => {
tip.element.fadeIn(100);
});
this.fireEvent(Editor.EVENT_RESTRICT, ...args);
});
this.editor.on(Input.EVENT_EMPTY, (...args) => {
@ -224,7 +253,7 @@ export class Editor extends Single {
const { height, vgap, tgap } = this.options;
if (isNull(this.watermark)) {
this.watermark = createWidget({
type: "bi.label",
type: Label.xtype,
cls: "bi-water-mark",
text: this.options.watermark,
height: height - 2 * vgap - tgap,
@ -281,7 +310,7 @@ export class Editor extends Single {
if (isNull(this.watermark)) {
this._assertWaterMark();
createWidget({
type: "bi.absolute",
type: AbsoluteLayout.xtype,
element: this.contentWrapper,
items: [
{

35
src/base/single/editor/editor.multifile.js

@ -1,3 +1,6 @@
import { File } from "../input";
import { AbsoluteLayout, AdaptiveLayout, shortcut, Widget, createWidget, extend } from "@/core";
/**
* 多文件
*
@ -6,8 +9,6 @@
* @extends BI.Single
* @abstract
*/
import { shortcut, Widget, createWidget, extend } from "../../../core";
import { File } from "../input/file";
@shortcut()
export class MultifileEditor extends Widget {
@ -23,7 +24,7 @@ export class MultifileEditor extends Widget {
const conf = super._defaultConfig(...arguments);
return extend(conf, {
baseCls: (conf.baseCls || "") + " bi-multifile-editor",
baseCls: `${conf.baseCls || ""} bi-multifile-editor`,
multiple: false,
maxSize: -1, // 1024 * 1024
accept: "",
@ -34,7 +35,7 @@ export class MultifileEditor extends Widget {
render() {
const { name, url, multiple, accept, maxSize, maxLength, title, errorText } = this.options;
this.file = createWidget({
type: "bi.file",
type: File.xtype,
cls: "multifile-editor",
width: "100%",
height: "100%",
@ -64,19 +65,21 @@ export class MultifileEditor extends Widget {
});
createWidget({
type: "bi.absolute",
type: AbsoluteLayout.xtype,
element: this,
items: [{
el: {
type: "bi.adaptive",
scrollable: false,
items: [this.file],
},
top: 0,
right: 0,
left: 0,
bottom: 0,
}],
items: [
{
el: {
type: AdaptiveLayout.xtype,
scrollable: false,
items: [this.file],
},
top: 0,
right: 0,
left: 0,
bottom: 0,
}
],
});
}

109
src/base/single/editor/editor.textarea.js

@ -1,12 +1,29 @@
import {
Layout,
AbsoluteLayout,
AdaptiveLayout,
shortcut,
Widget,
Controller,
createWidget,
extend,
isEmptyString,
isKey,
isNotEmptyString,
isNotNull,
trim,
isFunction
} from "@/core";
import { Label } from "../label";
import { Single } from "../0.single";
import { Bubbles } from "@/base";
/**
*
* Created by GUY on 2016/1/18.
* @class BI.TextAreaEditor
* @extends BI.Single
*/
import { shortcut, Widget, Controller, createWidget, extend, isEmptyString, isKey, isNotEmptyString, isNotNull, trim, isFunction } from "../../../core";
import { Single } from "../0.single";
import { Bubbles } from "../../0.base";
@shortcut()
export class TextAreaEditor extends Single {
@ -27,9 +44,7 @@ export class TextAreaEditor extends Single {
adjustYOffset: conf.simple ? 0 : 2,
adjustXOffset: 0,
offsetStyle: "left",
validationChecker: () => {
return true;
},
validationChecker: () => true,
scrolly: true,
});
}
@ -37,32 +52,36 @@ export class TextAreaEditor extends Single {
render() {
const { scrolly, value, style } = this.options;
this.content = createWidget({
type: "bi.layout",
type: Layout.xtype,
tagName: "textarea",
width: "100%",
height: "100%",
cls: "bi-textarea textarea-editor-content display-block",
css: scrolly ? null : {
overflowY: "hidden",
},
css: scrolly
? null
: {
overflowY: "hidden",
},
});
this.content.element.css({ resize: "none" });
createWidget({
type: "bi.absolute",
type: AbsoluteLayout.xtype,
element: this,
items: [{
el: {
type: "bi.adaptive",
items: [this.content],
},
left: 4,
right: 4,
top: 2,
bottom: 2,
}],
items: [
{
el: {
type: AdaptiveLayout.xtype,
items: [this.content],
},
left: 4,
right: 4,
top: 2,
bottom: 2,
}
],
});
this.content.element.on("input propertychange", (e) => {
this.content.element.on("input propertychange", e => {
this._checkError();
this._checkWaterMark();
this.fireEvent(Controller.EVENT_CHANGE, BI.Events.CHANGE, this.getValue(), this);
@ -76,9 +95,9 @@ export class TextAreaEditor extends Single {
this._checkError();
this._focus();
this.fireEvent(TextAreaEditor.EVENT_FOCUS);
Widget._renderEngine.createElement(document).bind("mousedown." + this.getName(), (e) => {
Widget._renderEngine.createElement(document).bind(`mousedown.${this.getName()}`, e => {
if (BI.DOM.isExist(this) && !this.element.__isMouseInBounds__(e)) {
Widget._renderEngine.createElement(document).unbind("mousedown." + this.getName());
Widget._renderEngine.createElement(document).unbind(`mousedown.${this.getName()}`);
this.content.element.blur();
}
});
@ -90,16 +109,16 @@ export class TextAreaEditor extends Single {
this.fireEvent(TextAreaEditor.EVENT_CONFIRM);
}
this.fireEvent(TextAreaEditor.EVENT_BLUR);
Widget._renderEngine.createElement(document).unbind("mousedown." + this.getName());
Widget._renderEngine.createElement(document).unbind(`mousedown.${this.getName()}`);
});
this.content.element.keydown(() => {
// 水印快速消失
this._checkWaterMark();
});
this.content.element.keyup((e) => {
this.content.element.keyup(e => {
this.fireEvent(TextAreaEditor.EVENT_KEY_DOWN, e.keyCode);
});
this.content.element.click((e) => {
this.content.element.click(e => {
e.stopPropagation();
});
if (isKey(value)) {
@ -121,7 +140,7 @@ export class TextAreaEditor extends Single {
if (isNotEmptyString(watermark)) {
if (!this.watermark) {
this.watermark = createWidget({
type: "bi.label",
type: Label.xtype,
cls: "bi-water-mark textarea-watermark",
textAlign: "left",
whiteSpace: scrolly ? "normal" : "nowrap",
@ -133,7 +152,7 @@ export class TextAreaEditor extends Single {
height: height > 24 ? "" : height,
});
this.watermark.element.bind({
mousedown: (e) => {
mousedown: e => {
if (this.isEnabled()) {
this.focus();
} else {
@ -141,19 +160,21 @@ export class TextAreaEditor extends Single {
}
e.stopEvent();
},
click: (e) => {
click: e => {
e.stopPropagation();
},
});
createWidget({
type: "bi.absolute",
type: AbsoluteLayout.xtype,
element: this,
items: [{
el: this.watermark,
left: 0,
top: 0,
right: 0,
}],
items: [
{
el: this.watermark,
left: 0,
top: 0,
right: 0,
}
],
});
} else {
this.watermark.setText(watermark);
@ -232,9 +253,17 @@ export class TextAreaEditor extends Single {
setStyle(style) {
this.style = style;
this.element.css(style);
this.content.element.css(extend({}, style, {
color: style.color || BI.DOM.getContrastColor(BI.DOM.isRGBColor(style.backgroundColor) ? BI.DOM.rgb2hex(style.backgroundColor) : style.backgroundColor),
}));
this.content.element.css(
extend({}, style, {
color:
style.color ||
BI.DOM.getContrastColor(
BI.DOM.isRGBColor(style.backgroundColor)
? BI.DOM.rgb2hex(style.backgroundColor)
: style.backgroundColor
),
})
);
}
getStyle() {

6
src/base/single/editor/index.js

@ -1,3 +1,3 @@
export { Editor } from "./editor";
export { MultifileEditor } from "./editor.multifile";
export { TextAreaEditor } from "./editor.textarea";
export { Editor } from "./editor";
export { MultifileEditor } from "./editor.multifile";
export { TextAreaEditor } from "./editor.textarea";

29
src/base/single/html/html.js

@ -1,10 +1,11 @@
import { Layout, DefaultLayout, shortcut, isNumber, createWidget, isWidthOrHeight, isKey } from "@/core";
import { Single } from "../0.single";
/**
* guy 表示一行数据通过position来定位位置的数据
* @class BI.Html
* @extends BI.Single
*/
import { shortcut, isNumber, createWidget, isWidthOrHeight, isKey } from "../../../core";
import { Single } from "../0.single";
@shortcut()
export class Html extends Single {
@ -24,10 +25,26 @@ export class Html extends Single {
bgap: 0,
text: "",
highLight: false,
}
};
render() {
const { vgap, hgap, lgap, rgap, tgap, bgap, height, lineHeight, maxWidth, textAlign, whiteSpace, handler, text, value, highLight } = this.options;
const {
vgap,
hgap,
lgap,
rgap,
tgap,
bgap,
height,
lineHeight,
maxWidth,
textAlign,
whiteSpace,
handler,
text,
value,
highLight,
} = this.options;
if (hgap + lgap > 0) {
this.element.css({
"padding-left": BI.pixFormat(hgap + lgap),
@ -68,14 +85,14 @@ export class Html extends Single {
});
if (handler) {
this.text = createWidget({
type: "bi.layout",
type: Layout.xtype,
tagName: "span",
});
this.text.element.click(() => {
handler(this.getValue());
});
createWidget({
type: "bi.default",
type: DefaultLayout.xtype,
element: this,
items: [this.text],
});

7
src/base/single/icon/icon.js

@ -1,10 +1,11 @@
import { Single } from "../0.single";
import { shortcut, extend } from "@/core";
/**
* guy 图标
* @class BI.Icon
* @extends BI.Single
*/
import { shortcut, extend } from "../../../core";
import { Single } from "../0.single";
@shortcut()
export class Icon extends Single {
@ -15,7 +16,7 @@ export class Icon extends Single {
return extend(conf, {
tagName: "i",
baseCls: (conf.baseCls || "") + " x-icon b-font horizon-center display-block",
baseCls: `${conf.baseCls || ""} x-icon b-font horizon-center display-block`,
});
}

23
src/base/single/iframe/iframe.js

@ -1,11 +1,12 @@
import { Single } from "../0.single";
import { shortcut, extend } from "@/core";
/**
* @class Iframe
* @extends Single
* @abstract
* Created by GameJian on 2016/3/2.
*/
import { shortcut, extend } from "../../../core";
import { Single } from "../0.single";
@shortcut()
export class Iframe extends Single {
@ -13,9 +14,10 @@ export class Iframe extends Single {
_defaultConfig(config) {
const conf = super._defaultConfig(...arguments);
return extend(conf, {
tagName: "iframe",
baseCls: (conf.baseCls || "") + " bi-iframe",
baseCls: `${conf.baseCls || ""} bi-iframe`,
src: "",
name: "",
attributes: {},
@ -31,13 +33,16 @@ export class Iframe extends Single {
}
_initProps() {
super._initProps(...arguments)
super._initProps(...arguments);
const { src, name } = this.options;
this.options.attributes = extend({
frameborder: 0,
src,
name,
}, this.options.attributes);
this.options.attributes = extend(
{
frameborder: 0,
src,
name,
},
this.options.attributes
);
}
setSrc(src) {

20
src/base/single/img/img.js

@ -1,3 +1,6 @@
import { Single } from "../0.single";
import { shortcut, extend } from "@/core";
/**
* ͼƬ
*
@ -6,8 +9,6 @@
* @extends BI.Single
* @abstract
*/
import { shortcut, extend } from "../../../core";
import { Single } from "../0.single";
@shortcut()
export class Img extends Single {
@ -18,7 +19,7 @@ export class Img extends Single {
return extend(conf, {
tagName: "img",
baseCls: (conf.baseCls || "") + " bi-img display-block",
baseCls: `${conf.baseCls || ""} bi-img display-block`,
src: "",
attributes: config.src ? { src: config.src } : {},
width: "100%",
@ -27,13 +28,16 @@ export class Img extends Single {
}
_initProps() {
super._initProps(...arguments)
super._initProps(...arguments);
const { src } = this.options;
this.options.attributes = extend({
src,
}, this.options.attributes);
this.options.attributes = extend(
{
src,
},
this.options.attributes
);
}
setSrc(src) {
this.options.src = src;
this.element.attr("src", src);

9
src/base/single/input/checkbox/checkbox.image.js

@ -1,22 +1,23 @@
import { IconButton } from "../../button";
import { shortcut, extend } from "@/core";
/**
* guy
* @extends Single
* @type {*|void|Object}
*/
import { shortcut, extend } from "../../../../core";
import { IconButton } from "../../button";
@shortcut()
export class ImageCheckbox extends IconButton {
static xtype = "bi.image_checkbox";
static EVENT_CHANGE = IconButton.EVENT_CHANGE;
_defaultConfig() {
const conf = super._defaultConfig(...arguments);
return extend(conf, {
baseCls: (conf.baseCls || "") + " bi-image-checkbox check-box-icon",
baseCls: `${conf.baseCls || ""} bi-image-checkbox check-box-icon`,
selected: false,
handler: BI.emptyFn,
width: 16,

29
src/base/single/input/checkbox/checkbox.js

@ -1,10 +1,11 @@
import { CenterAdaptLayout, DefaultLayout, shortcut } from "@/core";
import { BasicButton } from "../../button";
/**
* guy
* @extends Single
* @type {*|void|Object}
*/
import { shortcut } from "../../../../core";
import { BasicButton } from "../../button";
@shortcut()
export class Checkbox extends BasicButton {
@ -20,22 +21,24 @@ export class Checkbox extends BasicButton {
height: 14,
iconWidth: 14,
iconHeight: 14,
}
};
render() {
const { iconWidth, iconHeight } = this.options;
return {
type: "bi.center_adapt",
items: [{
type: "bi.default",
ref: (_ref) => {
this.checkbox = _ref;
},
cls: "checkbox-content",
width: iconWidth,
height: iconHeight,
}],
type: CenterAdaptLayout.xtype,
items: [
{
type: DefaultLayout.xtype,
ref: _ref => {
this.checkbox = _ref;
},
cls: "checkbox-content",
width: iconWidth,
height: iconHeight,
}
],
};
}

369
src/base/single/input/file.js

@ -1,3 +1,6 @@
import { Msg } from "../../foundation/message";
import { shortcut, Widget, some, extend } from "@/core";
/**
* 文件
*
@ -6,27 +9,22 @@
* @extends BI.Single
* @abstract
*/
import { shortcut, Widget, some, extend } from "../../../core";
import { Msg } from "../../foundation/message";
const document = _global.document || {};
/**
* @description normalize input.files. create if not present, add item method if not present
* @param Object generated wrap object
* @return Object the wrap object itself
*/
const F = (((item) => {
return (input) => {
const files = input.files || [input];
if (!files.item) {
files.item = item;
}
const F = (item => input => {
const files = input.files || [input];
if (!files.item) {
files.item = item;
}
return files;
};
})((i) => {
return this[i];
}));
return files;
})(i => this[i]);
const event = {
@ -37,14 +35,14 @@ const event = {
* @param Function the callback to associate as event
* @return Object noswfupload.event
*/
add: document.addEventListener ?
(node, name, callback) => {
add: document.addEventListener
? (node, name, callback) => {
node.addEventListener(name, callback, false);
return this;
} :
(node, name, callback) => {
node.attachEvent("on" + name, callback);
}
: (node, name, callback) => {
node.attachEvent(`on${name}`, callback);
return this;
},
@ -56,14 +54,14 @@ const event = {
* @param Function the callback associated as event
* @return Object noswfupload.event
*/
del: document.removeEventListener ?
(node, name, callback) => {
del: document.removeEventListener
? (node, name, callback) => {
node.removeEventListener(name, callback, false);
return this;
} :
(node, name, callback) => {
node.detachEvent("on" + name, callback);
}
: (node, name, callback) => {
node.detachEvent(`on${name}`, callback);
return this;
},
@ -79,34 +77,41 @@ const event = {
event.returnValue = !(event.cancelBubble = true);
}
} else {
e.stopPropagation ? e.stopPropagation() : e.cancelBubble = true;
e.preventDefault ? e.preventDefault() : e.returnValue = false;
e.stopPropagation ? e.stopPropagation() : (e.cancelBubble = true);
e.preventDefault ? e.preventDefault() : (e.returnValue = false);
}
return false;
},
};
const sendFile = (((toString) => {
const sendFile = (toString => {
const split = "onabort.onerror.onloadstart.onprogress".split("."),
length = split.length,
CRLF = "\r\n";
let xhr = new XMLHttpRequest,
let xhr = new XMLHttpRequest(),
sendFile;
const multipart = (boundary, name, file) => {
return "--".concat(
boundary, CRLF,
"Content-Disposition: form-data; name=\"", name, "\"; filename=\"", _global.encodeURIComponent(file.fileName), "\"", CRLF,
"Content-Type: application/octet-stream", CRLF,
const multipart = (boundary, name, file) =>
"--".concat(
boundary,
CRLF,
"Content-Disposition: form-data; name=\"",
name,
"\"; filename=\"",
_global.encodeURIComponent(file.fileName),
"\"",
CRLF,
"Content-Type: application/octet-stream",
CRLF,
file.getAsBinary(), CRLF,
"--", boundary, "--", CRLF
CRLF,
file.getAsBinary(),
CRLF,
"--",
boundary,
"--",
CRLF
);
}
const isFunction = (Function) => {
return toString.call(Function) === "[object Function]";
}
const isFunction = Function => toString.call(Function) === "[object Function]";
// FireFox 3+, Safari 4 beta (Chrome 2 beta file is buggy and will not work)
if (xhr.upload || xhr.sendAsBinary) {
@ -116,32 +121,30 @@ const sendFile = (((toString) => {
if (isFunction(handler.onerror)) {
handler.onerror();
}
return;
return;
}
const xhr = new XMLHttpRequest,
upload = xhr.upload || {
addEventListener(event, callback) {
this["on" + event] = callback;
},
};
for (let i = 0;i < length;i++) {
const xhr = new XMLHttpRequest(),
upload = xhr.upload || {
addEventListener(event, callback) {
this[`on${event}`] = callback;
},
};
for (let i = 0; i < length; i++) {
upload.addEventListener(
split[i].substring(2),
// eslint-disable-next-line no-loop-func
(((event) => {
return (rpe) => {
if (isFunction(handler[event])) {
handler[event](rpe, xhr);
}
};
})(split[i])),
(event => rpe => {
if (isFunction(handler[event])) {
handler[event](rpe, xhr);
}
})(split[i]),
false
);
}
upload.addEventListener(
"load",
(rpe) => {
rpe => {
if (handler.onreadystatechange === false) {
if (isFunction(handler.onload)) {
handler.onload(rpe, xhr);
@ -155,15 +158,19 @@ const sendFile = (((toString) => {
} else {
setTimeout(callback, 15);
}
}
};
setTimeout(callback, 15);
}
},
false
);
xhr.open("post", BI.appendQuery(handler.url, {
filename: _global.encodeURIComponent(handler.file.fileName),
}), true);
xhr.open(
"post",
BI.appendQuery(handler.url, {
filename: _global.encodeURIComponent(handler.file.fileName),
}),
true
);
if (!xhr.upload) {
const rpe = { loaded: 0, total: handler.file.fileSize || handler.file.size, simulation: true };
rpe.interval = setInterval(() => {
@ -181,61 +188,61 @@ const sendFile = (((toString) => {
};
xhr.onreadystatechange = () => {
switch (xhr.readyState) {
case 2:
case 3:
if (rpe.total <= rpe.loaded) {
rpe.loaded = rpe.total;
}
upload.onprogress(rpe);
break;
case 4:
clearInterval(rpe.interval);
rpe.interval = 0;
case 2:
case 3:
if (rpe.total <= rpe.loaded) {
rpe.loaded = rpe.total;
upload.onprogress(rpe);
if (199 < xhr.status && xhr.status < 400) {
upload.onload({});
const attachO = BI.jsonDecode(xhr.responseText);
attachO.filename = handler.file.fileName;
if (handler.file.type.indexOf("image") !== -1) {
attachO.attach_type = "image";
}
handler.attach_array[current] = attachO;
} else {
upload.onerror({});
}
upload.onprogress(rpe);
break;
case 4:
clearInterval(rpe.interval);
rpe.interval = 0;
rpe.loaded = rpe.total;
upload.onprogress(rpe);
if (199 < xhr.status && xhr.status < 400) {
upload.onload({});
const attachO = BI.jsonDecode(xhr.responseText);
attachO.filename = handler.file.fileName;
if (handler.file.type.indexOf("image") !== -1) {
attachO.attach_type = "image";
}
break;
default:
break;
handler.attach_array[current] = attachO;
} else {
upload.onerror({});
}
break;
default:
break;
}
};
upload.onloadstart(rpe);
} else {
xhr.onreadystatechange = () => {
switch (xhr.readyState) {
case 4:
const attachO = BI.jsonDecode(xhr.responseText);
if (handler.file.type.indexOf("image") !== -1) {
attachO.attach_type = "image";
}
attachO.filename = handler.file.fileName;
if (handler.maxLength === 1) {
handler.attach_array[0] = attachO;
// handler.attach_array.push(attachO);
} else {
handler.attach_array[current] = attachO;
}
break;
default:
break;
case 4:
const attachO = BI.jsonDecode(xhr.responseText);
if (handler.file.type.indexOf("image") !== -1) {
attachO.attach_type = "image";
}
attachO.filename = handler.file.fileName;
if (handler.maxLength === 1) {
handler.attach_array[0] = attachO;
// handler.attach_array.push(attachO);
} else {
handler.attach_array[current] = attachO;
}
break;
default:
break;
}
};
if (isFunction(upload.onloadstart)) {
upload.onloadstart();
}
}
const boundary = "AjaxUploadBoundary" + (new Date).getTime();
xhr.setRequestHeader("Content-Type", "multipart/form-data; boundary=" + boundary);
const boundary = `AjaxUploadBoundary${new Date().getTime()}`;
xhr.setRequestHeader("Content-Type", `multipart/form-data; boundary=${boundary}`);
if (handler.file.getAsBinary) {
xhr[xhr.sendAsBinary ? "sendAsBinary" : "send"](multipart(boundary, handler.name, handler.file));
} else {
@ -246,7 +253,7 @@ const sendFile = (((toString) => {
form.append("FileData", handler.file);
xhr.send(form);
}
return handler;
};
} else {
@ -256,7 +263,10 @@ const sendFile = (((toString) => {
let iframe, form;
const url = handler.url.concat(-1 === handler.url.indexOf("?") ? "?" : "&", "AjaxUploadFrame=true"),
rpe = {
loaded: 1, total: 100, simulation: true, interval: setInterval(() => {
loaded: 1,
total: 100,
simulation: true,
interval: setInterval(() => {
if (rpe.loaded < rpe.total) {
++rpe.loaded;
}
@ -265,56 +275,62 @@ const sendFile = (((toString) => {
}
}, 100),
},
target = ["AjaxUpload", (new Date).getTime(), String(Math.random()).substring(2)].join("_");
const onload = () => {
iframe.onreadystatechange = iframe.onload = iframe.onerror = null;
form.parentNode.removeChild(form);
form = null;
clearInterval(rpe.interval);
// rpe.loaded = rpe.total;
const responseText = (iframe.contentWindow.document || iframe.contentWindow.contentDocument).body.innerHTML;
try {
const attachO = BI.jsonDecode(responseText);
if (handler.file.type.indexOf("image") !== -1) {
attachO.attach_type = "image";
}
target = ["AjaxUpload", new Date().getTime(), String(Math.random()).substring(2)].join("_");
const onload = () => {
iframe.onreadystatechange = iframe.onload = iframe.onerror = null;
form.parentNode.removeChild(form);
form = null;
clearInterval(rpe.interval);
// rpe.loaded = rpe.total;
const responseText = (iframe.contentWindow.document || iframe.contentWindow.contentDocument).body
.innerHTML;
try {
const attachO = BI.jsonDecode(responseText);
if (handler.file.type.indexOf("image") !== -1) {
attachO.attach_type = "image";
}
// attachO.fileSize = responseText.length;
try {
// decodeURIComponent特殊字符可能有问题, catch一下,保证能正常上传
attachO.filename = _global.decodeURIComponent(handler.file.fileName);
} catch (e) {
attachO.filename = handler.file.fileName;
}
if (handler.maxLength === 1) {
handler.attach_array[0] = attachO;
} else {
handler.attach_array[current] = attachO;
}
// attachO.fileSize = responseText.length;
try {
// decodeURIComponent特殊字符可能有问题, catch一下,保证能正常上传
attachO.filename = _global.decodeURIComponent(handler.file.fileName);
} catch (e) {
if (isFunction(handler.onerror)) {
handler.onerror(rpe, event || _global.event);
}
attachO.filename = handler.file.fileName;
}
if (isFunction(handler.onload)) {
handler.onload(rpe, { responseText: responseText });
if (handler.maxLength === 1) {
handler.attach_array[0] = attachO;
} else {
handler.attach_array[current] = attachO;
}
} catch (e) {
if (isFunction(handler.onerror)) {
handler.onerror(rpe, event || _global.event);
}
}
try { // IE < 8 does not accept enctype attribute ...
if (isFunction(handler.onload)) {
handler.onload(rpe, { responseText });
}
};
try {
// IE < 8 does not accept enctype attribute ...
const form = document.createElement("<form enctype=\"multipart/form-data\"></form>"),
iframe = handler.iframe || (handler.iframe = document.createElement("<iframe id=\"" + target + "\" name=\"" + target + "\" src=\"" + url + "\"></iframe>"));
iframe =
handler.iframe ||
(handler.iframe = document.createElement(
`<iframe id="${target}" name="${target}" src="${url}"></iframe>`
));
} catch (e) {
const form = document.createElement("form"),
iframe = handler.iframe || (handler.iframe = document.createElement("iframe"));
form.setAttribute("enctype", "multipart/form-data");
iframe.setAttribute("name", iframe.id = target);
iframe.setAttribute("name", (iframe.id = target));
iframe.setAttribute("src", url);
}
iframe.style.position = "absolute";
iframe.style.left = iframe.style.top = "-10000px";
iframe.onload = onload;
iframe.onerror = (event) => {
iframe.onerror = event => {
if (isFunction(handler.onerror)) {
handler.onerror(rpe, event || _global.event);
}
@ -329,16 +345,17 @@ const sendFile = (((toString) => {
++rpe.loaded;
}
handler.onloadprogress(rpe, {
readyState: {
loading: 2,
interactive: 3,
loaded: 4,
complete: 4,
}[iframe.readyState] || 1,
readyState:
{
loading: 2,
interactive: 3,
loaded: 4,
complete: 4,
}[iframe.readyState] || 1,
});
}
};
form.setAttribute("action", handler.url + "&filename=" + _global.encodeURIComponent(handler.file.fileName));
form.setAttribute("action", `${handler.url}&filename=${_global.encodeURIComponent(handler.file.fileName)}`);
form.setAttribute("target", iframe.id);
form.setAttribute("method", "post");
form.appendChild(handler.file);
@ -355,19 +372,19 @@ const sendFile = (((toString) => {
};
}
xhr = null;
return sendFile;
})(Object.prototype.toString));
})(Object.prototype.toString);
const sendFiles = (handler, maxSize, width, height) => {
const length = handler.files.length,
onload = handler.onload,
onloadstart = handler.onloadstart;
onload = handler.onload,
onloadstart = handler.onloadstart;
handler.current = 0;
handler.total = 0;
handler.sent = 0;
while (handler.current < length) {
handler.total += (handler.files[handler.current].fileSize || handler.files[handler.current].size);
handler.total += handler.files[handler.current].fileSize || handler.files[handler.current].size;
handler.current++;
}
handler.current = 0;
@ -375,7 +392,7 @@ const sendFiles = (handler, maxSize, width, height) => {
handler.file = handler.files[handler.current];
const callback = (rpe, xhr) => {
handler.onloadstart = null;
handler.sent += (handler.files[handler.current].fileSize || handler.files[handler.current].size);
handler.sent += handler.files[handler.current].fileSize || handler.files[handler.current].size;
if (++handler.current < length) {
handler.file = handler.files[handler.current];
sendFile(handler, maxSize, width, height).onload = callback;
@ -415,7 +432,7 @@ const sendFiles = (handler, maxSize, width, height) => {
}
return handler;
}
};
const r1 = /\.([^.]+)$/; // .png
const r2 = /\/([^/]+)$/; // image/png
@ -432,7 +449,7 @@ const fileTypeValidate = (fileName, fileType) => {
}
const mimes = fileType.split(",");
if (mimes[0] === fileType) {
mimes = (fileType + "").split(";");
mimes = `${fileType}`.split(";");
}
return some(mimes, (index, mime) => {
@ -446,7 +463,7 @@ const fileTypeValidate = (fileName, fileType) => {
return matches[1] === "*" ? true : fileName.toLowerCase().indexOf(matches[1]) > -1;
}
});
}
};
@shortcut()
export class File extends Widget {
@ -462,7 +479,7 @@ export class File extends Widget {
const conf = super._defaultConfig(...arguments);
return extend(conf, {
baseCls: (conf.baseCls || "") + " bi-file display-block",
baseCls: `${conf.baseCls || ""} bi-file display-block`,
tagName: "input",
attributes: {
type: "file",
@ -492,14 +509,14 @@ export class File extends Widget {
// create the noswfupload.wrap Object
// wrap.maxSize 文件大小限制
// wrap.maxLength 文件个数限制
const _wrap = this.wrap = this._wrap(this.element[0], maxSize);
const _wrap = (this.wrap = this._wrap(this.element[0], maxSize));
// fileType could contain whatever text but filter checks *.{extension}
// if present
// handlerszhe
_wrap.onloadstart = (...args) => {
this.fireEvent(File.EVENT_UPLOADSTART, ...args);
this.fireEvent(File.EVENT_UPLOADSTART, ...args);
};
_wrap.onprogress = (rpe, xhr) => {
@ -586,20 +603,26 @@ export class File extends Widget {
const validateFileType = fileTypeValidate(value, wrap.fileType);
if (!validateFileType) {
// 文件类型不支持
Msg.toast(errorText({
errorType: 0,
file: item,
}) || BI.i18nText("BI-Upload_File_Type_Error", wrap.fileType), { level: "error" });
Msg.toast(
errorText({
errorType: 0,
file: item,
}) || BI.i18nText("BI-Upload_File_Type_Error", wrap.fileType),
{ level: "error" }
);
this.fireEvent(File.EVENT_ERROR, {
errorType: 0,
file: item,
});
} else if (wrap.maxSize !== -1 && size && wrap.maxSize < size) {
// 文件大小不支持
Msg.toast(errorText({
errorType: 1,
file: item,
}) || BI.i18nText("BI-Upload_File_Size_Error", Math.ceil(wrap.maxSize / 1024 / 1024)), { level: "error" });
Msg.toast(
errorText({
errorType: 1,
file: item,
}) || BI.i18nText("BI-Upload_File_Size_Error", Math.ceil(wrap.maxSize / 1024 / 1024)),
{ level: "error" }
);
this.fireEvent(File.EVENT_ERROR, {
errorType: 1,
file: item,
@ -609,14 +632,15 @@ export class File extends Widget {
}
}
}
wrap.files.length > 0 && this.fireEvent(File.EVENT_CHANGE, {
files: wrap.files,
});
wrap.files.length > 0 &&
this.fireEvent(File.EVENT_CHANGE, {
files: wrap.files,
});
input.value = "";
wrap.dom.input.parentNode.replaceChild(input, wrap.dom.input);
wrap.dom.input = input;
event.add(wrap.dom.input, "change", callback);
}
};
event.add(wrap.dom.input, "change", callback);
return wrap;
@ -633,10 +657,9 @@ export class File extends Widget {
// wrap Object
return this._events({
// DOM namespace
dom: {
input: input, // input file
input, // input file
disabled: false, // internal use, checks input file state
},
name: input.name, // name to send for each file ($_FILES[{name}] in the server)
@ -655,7 +678,7 @@ export class File extends Widget {
// something like {onload:function(){alert("OK")},onerror:function(){alert("Error")}, etc ...}
upload(handler) {
if (handler) {
for (let key in handler) {
for (const key in handler) {
this[key] = handler[key];
}
}

12
src/base/single/input/index.js

@ -1,6 +1,6 @@
export { Input } from "./input";
export { File } from "./file";
export { Checkbox } from "./checkbox/checkbox";
export { ImageCheckbox } from "./checkbox/checkbox.image";
export { Radio } from "./radio/radio";
export { ImageRadio } from "./radio/radio.image";
export { Input } from "./input";
export { File } from "./file";
export { Checkbox } from "./checkbox/checkbox";
export { ImageCheckbox } from "./checkbox/checkbox.image";
export { Radio } from "./radio/radio";
export { ImageRadio } from "./radio/radio.image";

71
src/base/single/input/input.js

@ -1,11 +1,26 @@
import { Single } from "../0.single";
import {
shortcut,
Controller,
extend,
debounce,
bind,
isNull,
isEmptyString,
isKey,
delay,
trim,
isEqual,
nextTick,
isEndWithBlank
} from "@/core";
/**
* guy
* @class BI.Input 一个button和一行数 组成的一行listitem
* @extends BI.Single
* @type {*|void|Object}
*/
import { shortcut, Controller, extend, debounce, bind, isNull, isEmptyString, isKey, delay, trim, isEqual, nextTick, isEndWithBlank } from "../../../core";
import { Single } from "../0.single";
@shortcut()
export class Input extends Single {
@ -37,7 +52,7 @@ export class Input extends Single {
const conf = super._defaultConfig(...arguments);
return extend(conf, {
baseCls: (conf.baseCls || "") + " bi-input display-block overflow-dot",
baseCls: `${conf.baseCls || ""} bi-input display-block overflow-dot`,
tagName: "input",
validationChecker: BI.emptyFn,
quitChecker: BI.emptyFn, // 按确定键能否退出编辑
@ -49,37 +64,37 @@ export class Input extends Single {
let ctrlKey = false;
let keyCode = null;
let inputEventValid = false;
const _keydown = debounce((keyCode) => {
const _keydown = debounce(keyCode => {
this.onKeyDown(keyCode, ctrlKey);
this._keydown_ = false;
}, BI.EVENT_RESPONSE_TIME);
const _clk = debounce(bind(this._click, this), BI.EVENT_RESPONSE_TIME, {
"leading": true,
"trailing": false,
leading: true,
trailing: false,
});
this._focusDebounce = debounce(bind(this._focus, this), BI.EVENT_RESPONSE_TIME, {
"leading": true,
"trailing": false,
leading: true,
trailing: false,
});
this._blurDebounce = debounce(bind(this._blur, this), BI.EVENT_RESPONSE_TIME, {
"leading": true,
"trailing": false,
leading: true,
trailing: false,
});
this.element
.keydown((e) => {
.keydown(e => {
inputEventValid = false;
ctrlKey = e.ctrlKey || e.metaKey; // mac的cmd支持一下
keyCode = e.keyCode;
this.fireEvent(Input.EVENT_QUICK_DOWN, e);
})
.keyup((e) => {
.keyup(e => {
keyCode = null;
if (!(inputEventValid && e.keyCode === BI.KeyCode.ENTER)) {
this._keydown_ = true;
_keydown(e.keyCode);
}
})
.on("input propertychange", (e) => {
.on("input propertychange", e => {
// 输入内容全选并直接删光,如果按键没放开就失去焦点不会触发keyup,被focusout覆盖了
// 其中propertychange在元素属性发生改变的时候就会触发 是为了兼容IE8
// 通过keyCode判断会漏掉输入法点击输入(右键粘贴暂缓)
@ -91,17 +106,18 @@ export class Input extends Single {
keyCode = null;
}
})
.click((e) => {
.click(e => {
e.stopPropagation();
_clk();
})
.mousedown((e) => {
.mousedown(e => {
this.element.val(this.element.val());
})
.focus((e) => { // 可以不用冒泡
.focus(e => {
// 可以不用冒泡
this._focusDebounce();
})
.blur((e) => {
.blur(e => {
// DEC-14919 IE11在浏览器重新获得焦点之后会先触发focusout再触发focus,要保持先获得焦点再失去焦点的顺序不变,因此采用blur
this._blurDebounce();
});
@ -141,8 +157,8 @@ export class Input extends Single {
}
}
this.fireEvent(Input.EVENT_BLUR);
}
};
if (this._keydown_ === true) {
delay(blur, BI.EVENT_RESPONSE_TIME);
} else {
@ -166,8 +182,11 @@ export class Input extends Single {
this._checkValidationOnValueChange();
}
if (this.isValid() && trim(this.getValue()) !== "") {
if (trim(this.getValue()) !== this._lastValue && (!this._start || isNull(this._lastValue) || this._lastValue === "")
|| (this._pause === true && !/(\s|\u00A0)$/.test(this.getValue()))) {
if (
(trim(this.getValue()) !== this._lastValue &&
(!this._start || isNull(this._lastValue) || this._lastValue === "")) ||
(this._pause === true && !/(\s|\u00A0)$/.test(this.getValue()))
) {
this._start = true;
this._pause = false;
this.fireEvent(Controller.EVENT_CHANGE, BI.Events.STARTEDIT, this.getValue(), this);
@ -203,8 +222,12 @@ export class Input extends Single {
this.fireEvent(Controller.EVENT_CHANGE, BI.Events.PAUSE, "", this);
this.fireEvent(Input.EVENT_PAUSE);
this._defaultState();
} else if ((keyCode === BI.KeyCode.BACKSPACE || keyCode === BI.KeyCode.DELETE) &&
trim(this.getValue()) === "" && (lastValue !== null && trim(lastValue) !== "")) {
} else if (
(keyCode === BI.KeyCode.BACKSPACE || keyCode === BI.KeyCode.DELETE) &&
trim(this.getValue()) === "" &&
lastValue !== null &&
trim(lastValue) !== ""
) {
this.fireEvent(Controller.EVENT_CHANGE, BI.Events.STOPEDIT, this.getValue(), this);
this.fireEvent(Input.EVENT_STOP);
}
@ -250,7 +273,7 @@ export class Input extends Single {
}
const checker = validationChecker.apply(this, [trim(v)]);
if (checker instanceof Promise) {
checker.then((validate) => {
checker.then(validate => {
this.setValid(validate !== false);
callback && callback();
});

9
src/base/single/input/radio/radio.image.js

@ -1,22 +1,23 @@
import { IconButton } from "../../button";
import { shortcut, extend } from "@/core";
/**
* guy
* @extends Single
* @type {*|void|Object}
*/
import { shortcut, extend } from "../../../../core";
import { IconButton } from "../../button";
@shortcut()
export class ImageRadio extends IconButton {
static xtype = "bi.image_radio";
static EVENT_CHANGE = IconButton.EVENT_CHANGE;
_defaultConfig() {
const conf = super._defaultConfig(...arguments);
return extend(conf, {
baseCls: (conf.baseCls || "") + " bi-radio radio-icon",
baseCls: `${conf.baseCls || ""} bi-radio radio-icon`,
selected: false,
handler: BI.emptyFn,
width: 16,

31
src/base/single/input/radio/radio.js

@ -1,10 +1,11 @@
import { CenterAdaptLayout, Layout, shortcut } from "@/core";
import { BasicButton } from "../../button";
/**
* guy
* @extends Single
* @type {*|void|Object}
*/
import { shortcut } from "../../../../core";
import { BasicButton } from "../../button";
@shortcut()
export class Radio extends BasicButton {
@ -18,23 +19,25 @@ export class Radio extends BasicButton {
width: 16,
height: 16,
iconWidth: 16,
iconHeight: 16
}
iconHeight: 16,
};
render() {
const { iconWidth, iconHeight } = this.options;
return {
type: "bi.center_adapt",
items: [{
type: "bi.layout",
cls: "radio-content",
ref: (_ref) => {
this.radio = _ref;
},
width: iconWidth,
height: iconHeight,
}],
type: CenterAdaptLayout.xtype,
items: [
{
type: Layout.xtype,
cls: "radio-content",
ref: _ref => {
this.radio = _ref;
},
width: iconWidth,
height: iconHeight,
}
],
};
}

16
src/base/single/instruction/instruction.js

@ -1,4 +1,5 @@
import { shortcut, Widget, extend } from "../../../core";
import { Label } from "../label";
import { shortcut, Widget, extend } from "@/core";
@shortcut()
export class Instruction extends Widget {
@ -6,13 +7,14 @@ export class Instruction extends Widget {
_defaultConfig() {
const conf = super._defaultConfig(...arguments);
return extend(conf, {
baseCls: (conf.baseCls || "") + " bi-instruction",
baseCls: `${conf.baseCls || ""} bi-instruction`,
height: 20,
level: "error",
textAlign: "left",
whiteSpace: "nowrap",
hgap: 5
hgap: 5,
});
}
@ -20,11 +22,11 @@ export class Instruction extends Widget {
const { level, textAlign, whiteSpace, height, hgap, rgap, lgap, vgap, text, keyword, value, py } = this.options;
return {
type: "bi.label",
ref: (_ref) => {
type: Label.xtype,
ref: _ref => {
this.text = _ref;
},
cls: "instruction-" + level,
cls: `instruction-${level}`,
textAlign,
whiteSpace,
textHeight: height,
@ -36,7 +38,7 @@ export class Instruction extends Widget {
text,
keyword,
value,
py
py,
};
}

179
src/base/single/label/abstract.label.js

@ -1,11 +1,12 @@
import { Text } from "../1.text";
import { CenterAdaptLayout, isNumber, createWidget, extend } from "@/core";
import { Single } from "../0.single";
/**
* Created by dailer on 2019/6/19.
*/
import { isNumber, createWidget, extend } from "../../../core";
import { Single } from "../0.single";
export class AbstractLabel extends Single {
_defaultConfig(props) {
const conf = super._defaultConfig(...arguments);
@ -30,7 +31,7 @@ export class AbstractLabel extends Single {
const { textAlign, whiteSpace, textHeight, text, value, py, keyword, highLight, handler } = this.options;
return {
type: "bi.text",
type: Text.xtype,
textAlign,
whiteSpace,
lineHeight: textHeight,
@ -59,9 +60,10 @@ export class AbstractLabel extends Single {
if (isNumber(width) && width > 0) {
if (isNumber(textWidth) && textWidth > 0) {
json.maxWidth = textWidth;
if (isNumber(height) && height > 0) { // 1.1
if (isNumber(height) && height > 0) {
// 1.1
createWidget({
type: "bi.center_adapt",
type: CenterAdaptLayout.xtype,
height,
columnSize: ["auto"], // important! 让文字在flex布局下shrink为1
scrollable: whiteSpace === "normal",
@ -75,8 +77,9 @@ export class AbstractLabel extends Single {
return;
}
createWidget({ // 1.2
type: "bi.center_adapt",
createWidget({
// 1.2
type: CenterAdaptLayout.xtype,
columnSize: ["auto"], // important! 让文字在flex布局下shrink为1
scrollable: whiteSpace === "normal",
element: this,
@ -89,7 +92,8 @@ export class AbstractLabel extends Single {
return;
}
if (whiteSpace === "normal") { // 1.3
if (whiteSpace === "normal") {
// 1.3
extend(json, {
hgap,
vgap,
@ -100,7 +104,7 @@ export class AbstractLabel extends Single {
});
this.text = createWidget(json);
createWidget({
type: "bi.center_adapt",
type: CenterAdaptLayout.xtype,
columnSize: ["auto"], // important! 让文字在flex布局下shrink为1
scrollable: whiteSpace === "normal",
element: this,
@ -109,25 +113,29 @@ export class AbstractLabel extends Single {
return;
}
if (isNumber(height) && height > 0) { // 1.4
if (isNumber(height) && height > 0) {
// 1.4
this.element.css({
"line-height": BI.pixFormat(height),
});
json.textAlign = textAlign;
delete json.maxWidth;
this.text = createWidget(extend(json, {
element: this,
hgap,
vgap,
lgap,
rgap,
tgap,
bgap,
}));
this.text = createWidget(
extend(json, {
element: this,
hgap,
vgap,
lgap,
rgap,
tgap,
bgap,
})
);
return;
}
extend(json, { // 1.5
extend(json, {
// 1.5
hgap,
vgap,
lgap,
@ -138,7 +146,7 @@ export class AbstractLabel extends Single {
});
this.text = createWidget(json);
createWidget({
type: "bi.center_adapt",
type: CenterAdaptLayout.xtype,
columnSize: ["auto"], // important! 让文字在flex布局下shrink为1
scrollable: whiteSpace === "normal",
element: this,
@ -147,10 +155,11 @@ export class AbstractLabel extends Single {
return;
}
if (isNumber(textWidth) && textWidth > 0) { // 1.6
if (isNumber(textWidth) && textWidth > 0) {
// 1.6
json.maxWidth = textWidth;
createWidget({
type: "bi.center_adapt",
type: CenterAdaptLayout.xtype,
columnSize: ["auto"], // important! 让文字在flex布局下shrink为1
scrollable: whiteSpace === "normal",
element: this,
@ -163,7 +172,8 @@ export class AbstractLabel extends Single {
return;
}
if (whiteSpace === "normal") { // 1.7
if (whiteSpace === "normal") {
// 1.7
extend(json, {
hgap,
vgap,
@ -174,7 +184,7 @@ export class AbstractLabel extends Single {
});
this.text = createWidget(json);
createWidget({
type: "bi.center_adapt",
type: CenterAdaptLayout.xtype,
columnSize: ["auto"], // important! 让文字在flex布局下shrink为1
scrollable: true,
element: this,
@ -183,34 +193,39 @@ export class AbstractLabel extends Single {
return;
}
if (isNumber(height) && height > 0) { // 1.8
if (isNumber(height) && height > 0) {
// 1.8
this.element.css({
"line-height": BI.pixFormat(height),
});
json.textAlign = textAlign;
delete json.maxWidth;
this.text = createWidget(extend(json, {
element: this,
this.text = createWidget(
extend(json, {
element: this,
hgap,
vgap,
lgap,
rgap,
tgap,
bgap,
})
);
return;
}
this.text = createWidget(
extend(json, {
hgap,
vgap,
lgap,
rgap,
tgap,
bgap,
}));
return;
}
this.text = createWidget(extend(json, {
hgap,
vgap,
lgap,
rgap,
tgap,
bgap,
}));
})
);
createWidget({
type: "bi.center_adapt",
type: CenterAdaptLayout.xtype,
columnSize: ["auto"], // important! 让文字在flex布局下shrink为1
element: this,
items: [this.text],
@ -224,7 +239,8 @@ export class AbstractLabel extends Single {
if (isNumber(width) && width > 0) {
if (isNumber(textWidth) && textWidth > 0) {
json.maxWidth = textWidth;
if (isNumber(height) && height > 0) { // 2.1
if (isNumber(height) && height > 0) {
// 2.1
createWidget({
type: adaptLayout,
horizontalAlign: textAlign,
@ -241,7 +257,8 @@ export class AbstractLabel extends Single {
return;
}
createWidget({ // 2.2
createWidget({
// 2.2
type: adaptLayout,
horizontalAlign: textAlign,
columnSize: ["auto"], // important! 让文字在flex布局下shrink为1
@ -262,27 +279,31 @@ export class AbstractLabel extends Single {
return;
}
if (isNumber(height) && height > 0) { // 2.3
if (isNumber(height) && height > 0) {
// 2.3
if (whiteSpace !== "normal") {
this.element.css({
"line-height": BI.pixFormat(height - (vgap * 2)),
"line-height": BI.pixFormat(height - vgap * 2),
});
}
delete json.maxWidth;
this.text = createWidget(extend(json, {
element: this,
hgap,
vgap,
lgap,
rgap,
tgap,
bgap,
}));
this.text = createWidget(
extend(json, {
element: this,
hgap,
vgap,
lgap,
rgap,
tgap,
bgap,
})
);
return;
}
json.maxWidth = width - 2 * hgap - lgap - rgap;
createWidget({ // 2.4
createWidget({
// 2.4
type: adaptLayout,
horizontalAlign: textAlign,
columnSize: ["auto"], // important! 让文字在flex布局下shrink为1
@ -294,16 +315,19 @@ export class AbstractLabel extends Single {
tgap,
bgap,
element: this,
items: [{
el: (this.text = createWidget(json)),
}],
items: [
{
el: (this.text = createWidget(json)),
}
],
});
return;
}
if (isNumber(textWidth) && textWidth > 0) {
json.maxWidth = textWidth;
createWidget({ // 2.5
createWidget({
// 2.5
type: adaptLayout,
horizontalAlign: textAlign,
columnSize: ["auto"], // important! 让文字在flex布局下shrink为1
@ -327,30 +351,35 @@ export class AbstractLabel extends Single {
if (isNumber(height) && height > 0) {
if (whiteSpace !== "normal") {
this.element.css({
"line-height": BI.pixFormat(height - (vgap * 2)),
"line-height": BI.pixFormat(height - vgap * 2),
});
}
delete json.maxWidth;
this.text = createWidget(extend(json, { // 2.6
element: this,
this.text = createWidget(
extend(json, {
// 2.6
element: this,
hgap,
vgap,
lgap,
rgap,
tgap,
bgap,
})
);
return;
}
this.text = createWidget(
extend(json, {
hgap,
vgap,
lgap,
rgap,
tgap,
bgap,
}));
return;
}
this.text = createWidget(extend(json, {
hgap,
vgap,
lgap,
rgap,
tgap,
bgap,
}));
})
);
createWidget({
type: adaptLayout,
horizontalAlign: textAlign,

10
src/base/single/label/html.label.js

@ -1,8 +1,10 @@
import { Html } from "../html/html";
import { AbstractLabel } from "./abstract.label";
import { shortcut } from "@/core";
/**
* Created by GUY on 2015/6/26.
*/
import { shortcut } from "../../../core";
import { AbstractLabel } from "./abstract.label";
@shortcut()
export class HtmlLabel extends AbstractLabel {
@ -10,13 +12,13 @@ export class HtmlLabel extends AbstractLabel {
props = {
baseCls: "bi-html-label",
}
};
_createJson() {
const { textAlign, whiteSpace, textHeight, text, value, handler } = this.options;
return {
type: "bi.html",
type: Html.xtype,
textAlign,
whiteSpace,
lineHeight: textHeight,

14
src/base/single/label/icon.label.js

@ -1,10 +1,12 @@
import { Icon } from "../icon/icon";
import { DefaultLayout, CenterAdaptLayout, shortcut, createWidget, isNumber, isNull } from "@/core";
import { Single } from "../0.single";
/**
* @class BI.IconLabel
* @extends BI.Single
* 图标标签
*/
import { shortcut, createWidget, isNumber, isNull } from "../../../core";
import { Single } from "../0.single";
@shortcut()
export class IconLabel extends Single {
@ -21,7 +23,7 @@ export class IconLabel extends Single {
iconWidth: null,
iconHeight: null,
lineHeight: null,
}
};
render() {
const { iconWidth, iconHeight, height, lineHeight, hgap, vgap, lgap, rgap, tgap, bgap } = this.options;
@ -29,14 +31,14 @@ export class IconLabel extends Single {
textAlign: "center",
});
this.icon = createWidget({
type: "bi.icon",
type: Icon.xtype,
width: iconWidth,
height: iconHeight,
});
if (isNumber(height) && height > 0 && isNull(iconWidth) && isNull(iconHeight)) {
this.element.css("lineHeight", BI.pixFormat(lineHeight || height));
createWidget({
type: "bi.default",
type: DefaultLayout.xtype,
element: this,
hgap,
vgap,
@ -50,7 +52,7 @@ export class IconLabel extends Single {
this.element.css("lineHeight", "1");
createWidget({
element: this,
type: "bi.center_adapt",
type: CenterAdaptLayout.xtype,
hgap,
vgap,
lgap,

8
src/base/single/label/index.js

@ -1,4 +1,4 @@
export { AbstractLabel } from "./abstract.label";
export { HtmlLabel } from "./html.label";
export { IconLabel } from "./icon.label";
export { Label } from "./label";
export { AbstractLabel } from "./abstract.label";
export { HtmlLabel } from "./html.label";
export { IconLabel } from "./icon.label";
export { Label } from "./label";

7
src/base/single/label/label.js

@ -1,8 +1,9 @@
import { AbstractLabel } from "./abstract.label";
import { shortcut, isFunction, isNotNull } from "@/core";
/**
* Created by GUY on 2015/6/26.
*/
import { shortcut, isFunction, isNotNull } from "../../../core";
import { AbstractLabel } from "./abstract.label";
@shortcut()
export class Label extends AbstractLabel {
@ -12,7 +13,7 @@ export class Label extends AbstractLabel {
baseCls: "bi-label",
py: "",
keyword: "",
}
};
getTitle() {
const title = this.options.title;

10
src/base/single/link/link.js

@ -1,10 +1,12 @@
import { A } from "../a/a";
import { Label } from "../label/label";
import { shortcut, extend } from "@/core";
/**
* guy a元素
* @class BI.Link
* @extends BI.Text
*/
import { shortcut, extend } from "../../../core";
import { Label } from "../label/label";
@shortcut()
export class Link extends Label {
@ -14,7 +16,7 @@ export class Link extends Label {
const conf = super._defaultConfig(...arguments);
return extend(conf, {
baseCls: (conf.baseCls || "") + " bi-link display-block",
baseCls: `${conf.baseCls || ""} bi-link display-block`,
tagName: "a",
href: "",
target: "_blank",
@ -25,7 +27,7 @@ export class Link extends Label {
const { textAlign, whiteSpace, textHeight, text, keyword, value, py, href, target } = this.options;
return {
type: "bi.a",
type: A.xtype,
textAlign,
whiteSpace,
lineHeight: textHeight,

19
src/base/single/text.pure.js

@ -1,22 +1,25 @@
import { Text } from "./1.text";
import { Widget, shortcut, isFunction, isKey, isNotNull } from "@/core";
/**
* 没有html标签的纯文本
*/
import { Widget, shortcut, isFunction, isKey, isNotNull } from "../../core";
import { Text } from "./1.text";
@shortcut()
export class PureText extends Widget {
static xtype = "bi.pure_text";
props = {
tagName: null,
}
};
render() {
const { text: optionsText, value } = this.options;
const text = isFunction(optionsText) ? this.__watch(optionsText, (context, newValue) => {
this.setText(newValue);
}) : optionsText;
const text = isFunction(optionsText)
? this.__watch(optionsText, (context, newValue) => {
this.setText(newValue);
})
: optionsText;
if (isKey(text)) {
this.setText(text);
} else if (isKey(value)) {
@ -32,7 +35,7 @@ export class PureText extends Widget {
return "";
}
return Text.formatText(text + "");
return Text.formatText(`${text}`);
}
setValue(value) {

8
src/base/single/tip/0.tip.js

@ -1,3 +1,6 @@
import { Single } from "../0.single";
import { extend } from "@/core";
/**
* guy
* tip提示
@ -7,12 +10,10 @@
* @abstract
*/
import { Single } from "../0.single";
import { extend } from "../../../core";
export class Tip extends Single {
_defaultConfig() {
const conf = super._defaultConfig(...arguments);
return extend(conf, {
_baseCls: `${conf._baseCls || ""} bi-tip`,
zIndex: BI.zIndex_tip,
@ -24,4 +25,3 @@ export class Tip extends Single {
this.element.css({ zIndex: this.options.zIndex });
}
}

221
src/base/single/tip/tip.toast.js

@ -1,3 +1,8 @@
import { IconLabel, Label } from "../label";
import { IconButton } from "../button";
import { HorizontalLayout, shortcut, extend, isPlainObject } from "@/core";
import { Tip } from "./0.tip";
/**
* toast提示
*
@ -6,121 +11,123 @@
* @extends BI.Tip
*/
import { shortcut, extend, isPlainObject } from "../../../core";
import { Tip } from "./0.tip";
@shortcut()
export class Toast extends Tip {
_const= {
closableMinWidth: 146,
minWidth: 100,
closableMaxWidth: 410,
maxWidth: 400,
}
_const = {
closableMinWidth: 146,
minWidth: 100,
closableMaxWidth: 410,
maxWidth: 400,
};
static EVENT_DESTORY = "EVENT_DESTORY";
static xtype = "bi.toast";
static EVENT_DESTORY = "EVENT_DESTORY";
static xtype = "bi.toast";
_defaultConfig() {
return extend(super._defaultConfig(...arguments), {
extraCls: "bi-toast",
text: "",
level: "success", // success或warning
autoClose: true,
closable: null,
textHeight: 20,
vgap: 10,
innerHgap: 4,
hgap: 8,
});
}
_defaultConfig() {
return extend(super._defaultConfig(...arguments), {
extraCls: "bi-toast",
text: "",
level: "success", // success或warning
autoClose: true,
closable: null,
textHeight: 20,
vgap: 10,
innerHgap: 4,
hgap: 8,
});
}
render() {
const { closable, level, autoClose, textHeight, text, hgap, vgap, innerHgap } = this.options;
const { closableMinWidth, minWidth, maxWidth, closableMaxWidth } = this._const;
this.element.css({
minWidth: BI.pixFormat(closable ? closableMinWidth : minWidth),
maxWidth: BI.pixFormat(closable ? closableMaxWidth : maxWidth),
});
this.element.addClass(`toast-${level}`);
function fn(e) {
e.stopPropagation();
e.stopEvent();
return false;
}
this.element.bind({
click: fn,
mousedown: fn,
mouseup: fn,
mouseover: fn,
mouseenter: fn,
mouseleave: fn,
mousemove: fn,
});
let cls;
switch (level) {
case "success":
cls = "toast-success-font";
break;
case "error":
cls = "toast-error-font";
break;
case "warning":
cls = "toast-warning-font";
break;
case "loading":
cls = "toast-loading-font anim-rotate";
break;
case "normal":
default:
cls = "toast-message-font";
break;
}
render() {
const { closable, level, autoClose, textHeight, text, hgap, vgap, innerHgap } = this.options;
const { closableMinWidth, minWidth, maxWidth, closableMaxWidth } = this._const;
this.element.css({
minWidth: BI.pixFormat(closable ? closableMinWidth : minWidth),
maxWidth: BI.pixFormat(closable ? closableMaxWidth : maxWidth),
});
this.element.addClass(`toast-${level}`);
function fn(e) {
e.stopPropagation();
e.stopEvent();
function hasCloseIcon() {
return closable === true || (closable === null && autoClose === false);
}
const items = [{
type: "bi.icon_label",
cls: `${cls} toast-icon`,
height: textHeight,
}, {
el: isPlainObject(text) ? text : {
type: "bi.label",
whiteSpace: "normal",
text,
textHeight,
textAlign: "left",
},
}];
return false;
}
this.element.bind({
click: fn,
mousedown: fn,
mouseup: fn,
mouseover: fn,
mouseenter: fn,
mouseleave: fn,
mousemove: fn,
});
let cls;
switch (level) {
case "success":
cls = "toast-success-font";
break;
case "error":
cls = "toast-error-font";
break;
case "warning":
cls = "toast-warning-font";
break;
case "loading":
cls = "toast-loading-font anim-rotate";
break;
case "normal":
default:
cls = "toast-message-font";
break;
}
const columnSize = ["", "fill"];
function hasCloseIcon() {
return closable === true || (closable === null && autoClose === false);
}
const items = [
{
type: IconLabel.xtype,
cls: `${cls} toast-icon`,
height: textHeight,
},
{
el: isPlainObject(text)
? text
: {
type: Label.xtype,
whiteSpace: "normal",
text,
textHeight,
textAlign: "left",
},
}
];
if (hasCloseIcon()) {
items.push({
type: "bi.icon_button",
cls: "close-font toast-icon",
handler: () => {
this.destroy();
},
height: textHeight,
});
columnSize.push("");
}
const columnSize = ["", "fill"];
return {
type: "bi.horizontal",
horizontalAlign: BI.HorizontalAlign.Stretch,
items,
hgap,
vgap,
innerHgap,
columnSize,
};
}
if (hasCloseIcon()) {
items.push({
type: IconButton.xtype,
cls: "close-font toast-icon",
handler: () => {
this.destroy();
},
height: textHeight,
});
columnSize.push("");
}
beforeDestroy() {
this.fireEvent(Toast.EVENT_DESTORY);
}
}
return {
type: HorizontalLayout.xtype,
horizontalAlign: BI.HorizontalAlign.Stretch,
items,
hgap,
vgap,
innerHgap,
columnSize,
};
}
beforeDestroy() {
this.fireEvent(Toast.EVENT_DESTORY);
}
}

146
src/base/single/tip/tip.tooltip.js

@ -1,3 +1,7 @@
import { VerticalLayout, shortcut, extend, createWidget, map } from "@/core";
import { Label } from "../label";
import { Tip } from "./0.tip";
/**
* title提示
*
@ -6,87 +10,85 @@
* @extends BI.Tip
*/
import { shortcut, extend, createWidget, map } from "../../../core";
import { Tip } from "./0.tip";
@shortcut()
export class Tooltip extends Tip {
_const = {
hgap: 8,
vgap: 4,
};
static xtype = "bi.tooltip";
_defaultConfig() {
return extend(super._defaultConfig(...arguments), {
extraCls: "bi-tooltip",
text: "",
level: "success", // success或warning
stopEvent: false,
stopPropagation: false,
textAlign: "left",
});
}
static xtype = "bi.tooltip";
_defaultConfig() {
return extend(super._defaultConfig(...arguments), {
extraCls: "bi-tooltip",
text: "",
level: "success", // success或warning
stopEvent: false,
stopPropagation: false,
textAlign: "left",
});
}
render () {
const { level, stopPropagation, stopEvent, text, textAlign } = this.options;
this.element.addClass(`tooltip-${level}`);
function fn(e) {
stopPropagation && e.stopPropagation();
stopEvent && e.stopEvent();
}
this.element.bind({
click: fn,
mousedown: fn,
mouseup: fn,
mouseover: fn,
mouseenter: fn,
mouseleave: fn,
mousemove: fn,
});
render() {
const { level, stopPropagation, stopEvent, text, textAlign } = this.options;
this.element.addClass(`tooltip-${level}`);
function fn(e) {
stopPropagation && e.stopPropagation();
stopEvent && e.stopEvent();
}
this.element.bind({
click: fn,
mousedown: fn,
mouseup: fn,
mouseover: fn,
mouseenter: fn,
mouseleave: fn,
mousemove: fn,
});
const texts = (`${text}`).split("\n");
if (texts.length > 1) {
createWidget({
type: "bi.vertical",
element: this,
hgap: this._const.hgap,
innerVgap: this._const.vgap,
items: map(texts, (i, text) => {
return {
type: "bi.label",
textAlign,
whiteSpace: "normal",
text,
textHeight: 18,
title: null,
};
}),
});
} else {
this.text = createWidget({
type: "bi.label",
element: this,
textAlign,
whiteSpace: "normal",
text,
title: null,
textHeight: 18,
hgap: this._const.hgap,
vgap: this._const.vgap,
});
}
}
const texts = `${text}`.split("\n");
if (texts.length > 1) {
createWidget({
type: VerticalLayout.xtype,
element: this,
hgap: this._const.hgap,
innerVgap: this._const.vgap,
items: map(texts, (i, text) => {
return {
type: Label.xtype,
textAlign,
whiteSpace: "normal",
text,
textHeight: 18,
title: null,
};
}),
});
} else {
this.text = createWidget({
type: Label.xtype,
element: this,
textAlign,
whiteSpace: "normal",
text,
title: null,
textHeight: 18,
hgap: this._const.hgap,
vgap: this._const.vgap,
});
}
}
setWidth(width) {
this.element.width(BI.pixFormat(width - 2 * this._const.hgap));
}
setWidth(width) {
this.element.width(BI.pixFormat(width - 2 * this._const.hgap));
}
setText(text) {
this.text && this.text.setText(text);
}
setText(text) {
this.text && this.text.setText(text);
}
setLevel(level) {
this.element.removeClass("tooltip-success").removeClass("tooltip-warning");
this.element.addClass(`tooltip-${level}`);
}
setLevel(level) {
this.element.removeClass("tooltip-success").removeClass("tooltip-warning");
this.element.addClass(`tooltip-${level}`);
}
}

13
src/base/single/trigger/trigger.js

@ -1,11 +1,12 @@
import { Single } from "../0.single";
import { extend } from "@/core";
/**
* 下拉
* @class BI.Trigger
* @extends BI.Single
* @abstract
*/
import { extend } from "../../../core";
import { Single } from "../0.single";
export class Trigger extends Single {
_defaultConfig() {
@ -17,11 +18,7 @@ export class Trigger extends Single {
});
}
setKey() {
setKey() {}
}
getKey() {
}
getKey() {}
}

72
src/base/tree/customtree.js

@ -1,3 +1,23 @@
import { ButtonTree, Expander } from "../combination";
import {
VerticalLayout,
Widget,
shortcut,
extend,
emptyFn,
Tree,
each,
isNotEmptyArray,
deepClone,
stripEL,
isWidget,
clone,
isNotNull,
isNull,
createWidget,
Controller
} from "@/core";
/**
*
* 自定义树
@ -6,7 +26,7 @@
* @class BI.CustomTree
* @extends BI.Single
*/
import { Widget, shortcut, extend, emptyFn, Tree, each, isNotEmptyArray, deepClone, stripEL, isWidget, clone, isNotNull, isNull, createWidget, Controller } from "../../core";
@shortcut()
export class CustomTree extends Widget {
static xtype = "bi.custom_tree";
@ -18,7 +38,7 @@ export class CustomTree extends Widget {
expander: {
el: {},
popup: {
type: "bi.custom_tree",
type: CustomTree.xtype,
},
},
@ -26,11 +46,13 @@ export class CustomTree extends Widget {
itemsCreator: emptyFn,
el: {
type: "bi.button_tree",
type: ButtonTree.xtype,
chooseType: 0,
layouts: [{
type: "bi.vertical",
}],
layouts: [
{
type: VerticalLayout.xtype,
}
],
},
});
}
@ -46,16 +68,20 @@ export class CustomTree extends Widget {
const items = [];
each(nodes, (i, node) => {
if (isNotEmptyArray(node.children) || node.isParent === true) {
const item = extend({
type: "bi.expander",
el: {
value: node.value,
const item = extend(
{
type: Expander.xtype,
el: {
value: node.value,
},
popup: { type: CustomTree.xtype },
},
popup: { type: "bi.custom_tree" },
}, deepClone(expander), {
id: node.id,
pId: node.pId,
});
deepClone(expander),
{
id: node.id,
pId: node.pId,
}
);
let el = stripEL(node);
if (!isWidget(el)) {
el = clone(el);
@ -67,7 +93,8 @@ export class CustomTree extends Widget {
item.popup.expander = deepClone(expander);
item.items = item.popup.items = node.children;
item.itemsCreator = item.popup.itemsCreator = (op, ...arg) => {
if (isNotNull(op.node)) {// 从子节点传过来的itemsCreator直接向上传递
if (isNotNull(op.node)) {
// 从子节点传过来的itemsCreator直接向上传递
return itemsCreator(op, ...arg);
}
const args = Array.prototype.slice.call([op, ...arg], 0);
@ -91,11 +118,14 @@ export class CustomTree extends Widget {
element: this,
items: this._formatItems(nodes),
itemsCreator: (op, callback) => {
itemsCreator.apply(this, [op, items => {
const args = Array.prototype.slice.call(arguments, 0);
args[0] = this._formatItems(items);
callback(...args);
}]);
itemsCreator.apply(this, [
op,
items => {
const args = Array.prototype.slice.call(arguments, 0);
args[0] = this._formatItems(items);
callback(...args);
}
]);
},
value,
});

3
src/case/combo/bubblecombo/popup.bubble.js

@ -1,5 +1,6 @@
import { shortcut, extend } from "@/core";
import { PopupView, Label } from "@/base";
import { PopupView } from "@/base/layer/layer.popup";
import { Label } from "@/base/single/label/label";
@shortcut()
export class BubblePopupView extends PopupView {

Loading…
Cancel
Save