UNPKG

ecui

Version:

Enterprise Classic User Interface.

615 lines (563 loc) 22.9 kB
/* Panel - 定义在一个小区域内截取显示大区域内容的基本操作。 截面控件,继承自基础控件,用于显示实际的内容区域超过控件显示区域的信息,通过拖拽滚动条显示完整的内容,截面控件可以设置参数决定是否自动显示水平/垂直滚动条,如果设置不显示水平/垂直滚动条,水平/垂直内容超出的部分将直接被截断,当设置两个滚动条都不显示时,截面控件从显示效果上等同于基础控件。在截面控件上滚动鼠标滑轮,将控制截面控件往垂直方向(如果没有垂直滚动条则在水平方向)前移或者后移滚动条,在获得焦点后,通过键盘的方向键也可以操作截面控件的滚动条。 截面控件直接HTML初始化的例子: <div ecui="type:panel"> <!-- 这里放内容 --> ... </div> 属性 _bAbsolute - 是否包含绝对定位的Element _nWheelDelta - 鼠标滚轮滚动一次的差值 _eBrowser - 用于浏览器原生的滚动条实现的Element _uVScrollbar - 垂直滚动条控件 _uHScrollbar - 水平滚动条控件 _uCorner - 夹角控件 $$mainWidth - layout区域的实际宽度 $$mainHeight - layout区域的实际高度 */ //{if 0}// (function () { var core = ecui, dom = core.dom, ui = core.ui, util = core.util, MATH = Math, MAX = MATH.max, MIN = MATH.min, FLOOR = MATH.floor, createDom = dom.create, getParent = dom.getParent, getPosition = dom.getPosition, getStyle = dom.getStyle, moveElements = dom.moveElements, attachEvent = util.attachEvent, blank = util.blank, detachEvent = util.detachEvent, toNumber = util.toNumber, $fastCreate = core.$fastCreate, calcHeightRevise = core.calcHeightRevise, calcWidthRevise = core.calcWidthRevise, findControl = core.findControl, getKey = core.getKey, getScrollNarrow = core.getScrollNarrow, inheritsControl = core.inherits, triggerEvent = core.triggerEvent, wrapEvent = core.wrapEvent, UI_CONTROL = ui.Control, UI_CONTROL_CLASS = UI_CONTROL.prototype, UI_VSCROLLBAR = ui.VScrollbar, UI_HSCROLLBAR = ui.HScrollbar; //{/if}// //{if $phase == "define"}// /** * 初始化浏览器原生滚动条控件。 * @protected * * @param {Object} options 初始化选项 */ ///__gzip_original__UI_BROWSER_SCROLLBAR ///__gzip_original__UI_BROWSER_SCROLLBAR_CLASS ///__gzip_original__UI_BROWSER_VSCROLLBAR ///__gzip_original__UI_BROWSER_VSCROLLBAR_CLASS ///__gzip_original__UI_BROWSER_HSCROLLBAR ///__gzip_original__UI_BROWSER_HSCROLLBAR_CLASS ///__gzip_original__UI_BROWSER_CORNER ///__gzip_original__UI_BROWSER_CORNER_CLASS ///__gzip_original__UI_PANEL ///__gzip_original__UI_PANEL_CLASS var UI_BROWSER_SCROLLBAR = inheritsControl( UI_CONTROL, null, null, function (el, options) { detachEvent(el, 'scroll', UI_BROWSER_SCROLLBAR_SCROLL); attachEvent(el, 'scroll', UI_BROWSER_SCROLLBAR_SCROLL); } ), UI_BROWSER_SCROLLBAR_CLASS = UI_BROWSER_SCROLLBAR.prototype; //{else}// /** * 原生滚动条滚动处理。 * 滚动条滚动后,将触发父控件的 onscroll 事件,如果事件返回值不为 false,则调用父控件的 $scroll 方法。 * @private * * @param {ecui.ui.Event} event 事件对象 */ function UI_BROWSER_SCROLLBAR_SCROLL(event) { triggerEvent(findControl(getParent(wrapEvent(event).target)), 'scroll'); } /** * @override */ UI_BROWSER_SCROLLBAR_CLASS.$hide = UI_BROWSER_SCROLLBAR_CLASS.hide = function () { this.getMain().style[this._aProperty[0]] = 'hidden'; UI_BROWSER_SCROLLBAR_CLASS.setValue.call(this, 0); }; /** * 直接设置控件的当前值。 * @protected * * @param {number} value 控件的当前值 */ UI_BROWSER_SCROLLBAR_CLASS.$setValue = function (value) { this.getMain()[this._aProperty[1]] = MIN(MAX(0, value), this.getTotal()); }; /** * @override */ UI_BROWSER_SCROLLBAR_CLASS.$show = UI_BROWSER_SCROLLBAR_CLASS.show = function () { this.getMain().style[this._aProperty[0]] = 'scroll'; }; /** * @override */ UI_BROWSER_SCROLLBAR_CLASS.getHeight = function () { return this._aProperty[4] ? this.getMain()[this._aProperty[4]] : getScrollNarrow(); }; /** * 获取滚动条控件的最大值。 * getTotal 方法返回滚动条控件允许滚动的最大值,最大值、当前值与滑动块控件的实际位置互相影响,通过 setTotal 设置。 * @public * * @return {number} 控件的最大值 */ UI_BROWSER_SCROLLBAR_CLASS.getTotal = function () { return toNumber(this.getMain().lastChild.style[this._aProperty[2]]); }; /** * 获取滚动条控件的当前值。 * getValue 方法返回滚动条控件的当前值,最大值、当前值与滑动按钮控件的实际位置互相影响,但是当前值不允许超过最大值,通过 setValue 方法设置。 * @public * * @return {number} 滚动条控件的当前值 */ UI_BROWSER_SCROLLBAR_CLASS.getValue = function () { return this.getMain()[this._aProperty[1]]; }; /** * @override */ UI_BROWSER_SCROLLBAR_CLASS.getWidth = function () { return this._aProperty[3] ? this.getMain()[this._aProperty[3]] : getScrollNarrow(); }; /** * @override */ UI_BROWSER_SCROLLBAR_CLASS.isShow = function () { return this.getMain().style[this._aProperty[0]] != 'hidden'; }; /** * 设置滚动条控件的最大值。 * setTotal 方法设置的值不能为负数,当前值如果大于最大值,设置当前值为新的最大值,最大值发生改变将导致滑动按钮刷新。 * @public * * @param {number} value 控件的最大值 */ UI_BROWSER_SCROLLBAR_CLASS.setTotal = function (value) { this.getMain().lastChild.style[this._aProperty[2]] = value + 'px'; }; /** * 设置滚动条控件的当前值。 * @public * * @param {number} value 控件的当前值 */ UI_BROWSER_SCROLLBAR_CLASS.setValue = function (value) { this.$setValue(value); triggerEvent(this.getParent(), 'scroll'); }; UI_BROWSER_SCROLLBAR_CLASS.$cache = UI_BROWSER_SCROLLBAR_CLASS.$getPageStep = UI_BROWSER_SCROLLBAR_CLASS.$setPageStep = UI_BROWSER_SCROLLBAR_CLASS.$setSize = UI_BROWSER_SCROLLBAR_CLASS.alterClass = UI_BROWSER_SCROLLBAR_CLASS.cache = UI_BROWSER_SCROLLBAR_CLASS.getStep = UI_BROWSER_SCROLLBAR_CLASS.init = UI_BROWSER_SCROLLBAR_CLASS.setPosition = UI_BROWSER_SCROLLBAR_CLASS.setStep = UI_BROWSER_SCROLLBAR_CLASS.skip = blank; //{/if}// //{if $phase == "define"}// /** * 初始化浏览器原生垂直滚动条控件。 * @public * * @param {Object} options 初始化选项 */ var UI_BROWSER_VSCROLLBAR = inheritsControl( UI_BROWSER_SCROLLBAR, null, null, function (el, options) { this._aProperty = ['overflowY', 'scrollTop', 'height', null, 'offsetHeight']; } ); //{/if}// //{if $phase == "define"}// /** * 初始化浏览器原生水平滚动条控件。 * @public * * @param {Object} options 初始化选项 */ var UI_BROWSER_HSCROLLBAR = inheritsControl( UI_BROWSER_SCROLLBAR, null, null, function (el, options) { this._aProperty = ['overflowX', 'scrollLeft', 'width', 'offsetWidth', null]; } ); //{/if}// //{if $phase == "define"}// /** * 初始化夹角控件。 * @public * * @param {Object} options 初始化选项 */ var UI_BROWSER_CORNER = inheritsControl(UI_CONTROL), UI_BROWSER_CORNER_CLASS = UI_BROWSER_CORNER.prototype; //{else}// (function () { for (var name in UI_CONTROL_CLASS) { UI_BROWSER_CORNER_CLASS[name] = blank; } })(); //{/if}// //{if $phase == "define"}// /** * 初始化截面控件,截面控件支持自动展现滚动条控件,允许指定需要自动展现的垂直或水平滚动条。 * options 对象支持的属性如下: * vScroll 是否自动展现垂直滚动条,默认展现 * hScroll 是否自动展现水平滚动条,默认展现 * browser 是否使用浏览器原生的滚动条,默认使用模拟的滚动条 * absolute 是否包含绝对定位的Element,默认不包含 * wheelDelta 鼠标滚轮的步长,即滚动一次移动的最小步长单位,默认总步长(差值*步长)为不大于20像素的最大值 * @public * * @param {Object} options 初始化选项 */ var UI_PANEL = ui.Panel = inheritsControl( UI_CONTROL, 'ui-panel', function (el, options) { var vscroll = options.vScroll !== false, hscroll = options.hScroll !== false, type = this.getType(), o = createDom( type + '-body', 'position:absolute;top:0px;left:0px' + (hscroll ? ';white-space:nowrap' : '') ); el.style.overflow = 'hidden'; moveElements(el, o, true); el.innerHTML = (options.browser ? '<div style="position:absolute;top:0px;left:0px;overflow:auto;padding:0px;border:0px">' + '<div style="width:1px;height:1px;padding:0px;border:0px"></div></div>' : (vscroll ? '<div class="' + type + '-vscrollbar' + this.VScrollbar.TYPES + '" style="position:absolute"></div>' : '') + (hscroll ? '<div class="' + type + '-hscrollbar' + this.HScrollbar.TYPES + '" style="position:absolute"></div>' : '') + (vscroll && hscroll ? '<div class="' + type + '-corner' + UI_CONTROL.TYPES + '" style="position:absolute"></div>' : '') ) + '<div class="' + type + '-layout" style="position:relative;overflow:hidden;padding:0px"></div>'; el.lastChild.appendChild(o); }, function (el, options) { var i = 0, browser = options.browser, vscroll = options.vScroll !== false, hscroll = options.hScroll !== false, list = [ [vscroll, '_uVScrollbar', browser ? UI_BROWSER_VSCROLLBAR : this.VScrollbar], [hscroll, '_uHScrollbar', browser ? UI_BROWSER_HSCROLLBAR : this.HScrollbar], [vscroll && hscroll, '_uCorner', browser ? UI_BROWSER_CORNER : UI_CONTROL] ], o; this.$setBody(el.lastChild.lastChild); this._bAbsolute = options.absolute; this._nWheelDelta = options.wheelDelta; el = el.firstChild; if (browser) { this._eBrowser = el; } // 生成中心区域的Element层容器,滚动是通过改变容器的left与top属性实现 for (; o = list[i++]; ) { if (o[0]) { this[o[1]] = $fastCreate(o[2], el, this); if (!browser) { el = el.nextSibling; } } } } ), UI_PANEL_CLASS = UI_PANEL.prototype; //{else}// UI_PANEL_CLASS.VScrollbar = UI_VSCROLLBAR; UI_PANEL_CLASS.HScrollbar = UI_HSCROLLBAR; /** * @override */ UI_PANEL_CLASS.$cache = function (style, cacheSize) { UI_CONTROL_CLASS.$cache.call(this, style, cacheSize); var body = this.getBody(), mainWidth = body.offsetWidth, mainHeight = body.offsetHeight; style = getStyle(getParent(body)); this.$$bodyWidthRevise = calcWidthRevise(style); this.$$bodyHeightRevise = calcHeightRevise(style); // 考虑到内部Element绝对定位的问题,中心区域的宽度与高度修正 if (this._bAbsolute) { for ( var i = 0, list = body.all || body.getElementsByTagName('*'), pos = getPosition(body); // 以下使用 body 代替临时的 DOM 节点对象 body = list[i++]; ) { if (body.offsetWidth && getStyle(body, 'position') == 'absolute') { style = getPosition(body); mainWidth = MAX(mainWidth, style.left - pos.left + body.offsetWidth); mainHeight = MAX(mainHeight, style.top - pos.top + body.offsetHeight); } } } this.$$mainWidth = mainWidth; this.$$mainHeight = mainHeight; if (this._uVScrollbar) { this._uVScrollbar.cache(true, true); } if (this._uHScrollbar) { this._uHScrollbar.cache(true, true); } if (this._uCorner) { this._uCorner.cache(true, true); } }; /** * @override */ UI_PANEL_CLASS.$dispose = function () { this._eBrowser = null; UI_CONTROL_CLASS.$dispose.call(this); }; /** * 接管对方向键的处理。 * @override */ UI_PANEL_CLASS.$keydown = UI_PANEL_CLASS.$keypress = function (event) { var which = getKey(), o = which % 2 ? this._uHScrollbar : this._uVScrollbar; if (which >= 37 && which <= 40 && !event.target.value) { if (o) { o.skip(which + which % 2 - 39); } return false; } }; /** * 如果有垂直滚动条,则垂直滚动条随滚轮滚动。 * @override */ UI_PANEL_CLASS.$mousewheel = function (event) { if (this.isHovered()) { o = this._uVScrollbar; if (o && o.isShow()) { // 计算滚动的次数,至少要滚动一次 var value = o.getValue(), delta = this._nWheelDelta || FLOOR(20 / o.getStep()) || 1, o; o.skip(event.detail > 0 ? delta : -delta); event.stopPropagation(); // 如果截面已经移动到最后,不屏弊缺省事件 return value == o.getValue(); } } }; /** * 控件的滚动条发生滚动的默认处理。 * 如果控件包含滚动条,滚动条滚动时触发 onscroll 事件,如果事件返回值不为 false,则调用 $scroll 方法。 * @protected */ UI_PANEL_CLASS.$scroll = function () { var style = this.getBody().style; style.left = -MAX(this.getScrollLeft(), 0) + 'px'; style.top = -MAX(this.getScrollTop(), 0) + 'px'; }; /** * @override */ UI_PANEL_CLASS.$setSize = function (width, height) { UI_CONTROL_CLASS.$setSize.call(this, width, height); this.$locate(); var basicWidth = this.$getBasicWidth(), basicHeight = this.$getBasicHeight(), paddingWidth = this.$$paddingLeft + this.$$paddingRight, paddingHeight = this.$$paddingTop + this.$$paddingBottom, bodyWidth = this.getWidth() - basicWidth, bodyHeight = this.getHeight() - basicHeight, mainWidth = this.$$mainWidth, mainHeight = this.$$mainHeight, browser = this._eBrowser, vscroll = this._uVScrollbar, hscroll = this._uHScrollbar, corner = this._uCorner, vsWidth = vscroll ? vscroll.getWidth() : 0, hsHeight = hscroll ? hscroll.getHeight() : 0, innerWidth = bodyWidth - vsWidth, innerHeight = bodyHeight - hsHeight, hsWidth = innerWidth + paddingWidth, vsHeight = innerHeight + paddingHeight; // 设置垂直与水平滚动条与夹角控件的位置 if (vscroll) { vscroll.setPosition(hsWidth, 0); } if (hscroll) { hscroll.setPosition(0, vsHeight); } if (corner) { corner.setPosition(hsWidth, vsHeight); } if (mainWidth <= bodyWidth && mainHeight <= bodyHeight) { // 宽度与高度都没有超过截面控件的宽度与高度,不需要显示滚动条 if (vscroll) { vscroll.$hide(); } if (hscroll) { hscroll.$hide(); } if (corner) { corner.$hide(); } innerWidth = bodyWidth; innerHeight = bodyHeight; } else { while (true) { if (corner) { // 宽度与高度都超出了显示滚动条后余下的宽度与高度,垂直与水平滚动条同时显示 if (mainWidth > innerWidth && mainHeight > innerHeight) { hscroll.$setSize(hsWidth); hscroll.setTotal(browser ? mainWidth + basicWidth : mainWidth - innerWidth); hscroll.$show(); vscroll.$setSize(0, vsHeight); vscroll.setTotal(browser ? mainHeight + basicHeight : mainHeight - innerHeight); vscroll.$show(); corner.$setSize(vsWidth, hsHeight); corner.$show(); break; } corner.$hide(); } if (hscroll) { if (mainWidth > bodyWidth) { // 宽度超出控件的宽度,高度没有超出显示水平滚动条后余下的高度,只显示水平滚动条 hscroll.$setSize(bodyWidth + paddingWidth); hscroll.setTotal(browser ? mainWidth + basicWidth : mainWidth - bodyWidth); hscroll.$show(); if (vscroll) { vscroll.$hide(); } innerWidth = bodyWidth; } else { hscroll.$hide(); } } if (vscroll) { if (mainHeight > bodyHeight) { // 高度超出控件的高度,宽度没有超出显示水平滚动条后余下的宽度,只显示水平滚动条 vscroll.$setSize(0, bodyHeight + paddingHeight); vscroll.setTotal(browser ? mainHeight + basicHeight : mainHeight - bodyHeight); vscroll.$show(); if (hscroll) { hscroll.$hide(); } innerHeight = bodyHeight; } else { vscroll.$hide(); } } break; } } innerWidth -= this.$$bodyWidthRevise; innerHeight -= this.$$bodyHeightRevise; if (vscroll) { vscroll.$setPageStep(innerHeight); } if (hscroll) { hscroll.$setPageStep(innerWidth); } // 设置内部定位器的大小,以下使用 corner 表示 style if (browser) { corner = browser.style; corner.width = bodyWidth + paddingWidth + 'px'; corner.height = bodyHeight + paddingHeight + 'px'; } corner = getParent(this.getBody()).style; corner.width = innerWidth + 'px'; corner.height = innerHeight + 'px'; }; /** * 获取水平滚动条的当前值。 * getScrollLeft 方法提供了对水平滚动条当前值的快捷访问方式,参见 getValue。 * @public * * @return {number} 水平滚动条的当前值,如果没有水平滚动条返回 -1 */ UI_PANEL_CLASS.getScrollLeft = function () { var o = this._uHScrollbar; return o ? o.getValue() : -1; }; /** * 获取垂直滚动条的当前值。 * getScrollTop 方法提供了对水平滚动条当前值的快捷访问方式,参见 getValue。 * @public * * @return {number} 垂直滚动条的当前值,如果没有垂直滚动条返回 -1 */ UI_PANEL_CLASS.getScrollTop = function () { var o = this._uVScrollbar; return o ? o.getValue() : -1; }; /** * @override */ UI_PANEL_CLASS.init = function () { UI_CONTROL_CLASS.init.call(this); if (this._uVScrollbar) { this._uVScrollbar.init(); } if (this._uHScrollbar) { this._uHScrollbar.init(); } if (this._uCorner) { this._uCorner.init(); } }; /** * 控件显示区域复位。 * reset 方法设置水平滚动条或者垂直滚动条的当前值为 0。 * @public */ UI_PANEL_CLASS.reset = function () { if (this._uVScrollbar) { this._uVScrollbar.setValue(0); } if (this._uHScrollbar) { this._uHScrollbar.setValue(0); } }; //{/if}// //{if 0}// })(); //{/if}//