diff --git a/demo/MonthView.html b/demo/MonthView.html index 01ca47e6..ef3ee8a3 100644 --- a/demo/MonthView.html +++ b/demo/MonthView.html @@ -306,7 +306,7 @@

不可用状态

var test1Ipt3 = document.getElementById('test1-ipt3'); test1Btn3.onclick = function() { var range = test1Ipt3.value; - multiMonthView.setProperties({ + singleMonthView.setProperties({ range: range }); } diff --git a/demo/assets/themes/standard.css b/demo/assets/themes/standard.css index 5cf03048..bc9a3200 100644 --- a/demo/assets/themes/standard.css +++ b/demo/assets/themes/standard.css @@ -3305,6 +3305,7 @@ span.ui-crumb-node { display: inline-block; } .ui-rangecalendar-layer { + position: absolute; background: #fbfbfb; border-top: 3px solid #fbfbfb; border-bottom: none; diff --git a/src/MonthView.js b/src/MonthView.js index e60c7c0a..fb5182c8 100644 --- a/src/MonthView.js +++ b/src/MonthView.js @@ -47,16 +47,11 @@ define( * 默认选项配置 */ var properties = { - range: { - begin: new Date(1982, 10, 4), - end: new Date(2046, 10, 4) - }, - dateFormat: 'YYYY-MM-DD', - paramFormat: 'YYYY-MM-DD', viewValue: {}, - mode: 'single' + mode: 'single', + dateItemRender: null }; - u.extend(properties, options); + u.extend(properties, MonthView.defaultProperties, options); this.setProperties(properties); }, @@ -68,8 +63,12 @@ define( * @protected */ setProperties: function (properties) { + var format = properties.paramFormat || this.paramFormat; if (properties.range) { - properties.range = rangeAdapter(properties.range); + properties.range = rangeAdapter( + properties.range, + format + ); } // 如果么设置rawValue @@ -79,7 +78,7 @@ define( // 从value转 if (properties.value) { properties.rawValue - = parseValueByMode(properties.value, mode); + = parseValueByMode(properties.value, mode, format); } // 都没设 else { @@ -141,6 +140,7 @@ define( var changes = Control.prototype.setProperties.apply(this, arguments); + // yankun:真的需要在这里触发change吗? if (changes.hasOwnProperty('rawValue')) { this.fire('change'); } @@ -174,45 +174,55 @@ define( var monthBack = this.getChild('monthBack'); monthBack.on( 'click', - lib.curry(goToPrevMonth, this) + u.partial(goToPrevMonth, this) ); // 向前按钮 var monthForward = this.getChild('monthForward'); monthForward.on( 'click', - lib.curry(goToNextMonth, this) + u.partial(goToNextMonth, this) ); // 月份选择 var monthSel = this.getChild('monthSel'); monthSel.on( 'change', - lib.curry(changeMonth, this, monthSel) + u.partial(changeMonth, this, monthSel) ); // 给layer人肉增加class命名空间 monthSel.on( 'layerrendered', - lib.curry(addCustomClassesForSelectLayer, this, 'month-select') + u.partial(addCustomClassesForSelectLayer, this, 'month-select') ); // 年份选择 var yearSel = this.getChild('yearSel'); yearSel.on( 'change', - lib.curry(changeYear, this, yearSel) + u.partial(changeYear, this, yearSel) ); yearSel.on( 'layerrendered', - lib.curry(addCustomClassesForSelectLayer, this, 'year-select') + u.partial(addCustomClassesForSelectLayer, this, 'year-select') ); var controlHelper = this.helper; - // 为日期绑定点击事件 - var monthMain = controlHelper.getPart('monthMain'); - controlHelper.addDOMEvent(monthMain, 'click', monthViewClick); + var selectors = [ + '.' + controlHelper.getPartClassName('month-item'), + '.' + controlHelper.getPartClassName('month-select-all'), + '.' + controlHelper.getPartClassName('month-title'), + '.' + controlHelper.getPartClassName('month-row-select') + ]; + + controlHelper.addDOMEvent( + controlHelper.getPart('monthMain'), + 'click', + selectors.join(','), + monthViewClick + ); }, /** @@ -320,8 +330,9 @@ define( * @return {string} */ stringifyValue: function (rawValue) { + var paramFormat = this.paramFormat; if (this.mode === 'single') { - return lib.date.format(rawValue, this.paramFormat) || ''; + return m(rawValue).format(this.paramFormat) || ''; } var dateStrs = []; @@ -329,27 +340,21 @@ define( for (var i = 0; i < rawValue.length; i++) { if (i === 0) { dateStrs.push( - lib.date.format(rawValue[i], this.paramFormat) + m(rawValue[i]).format(paramFormat) ); } else { if ((rawValue[i] - rawValue[i - 1]) > oneDay) { dateStrs.push( - lib.date.format( - rawValue[i - 1], this.paramFormat - ) + m(rawValue[i - 1]).format(paramFormat) ); dateStrs.push( - lib.date.format( - rawValue[i], this.paramFormat - ) + m(rawValue[i]).format(paramFormat) ); } else if (i === (rawValue.length - 1)) { dateStrs.push( - lib.date.format( - rawValue[i], this.paramFormat - ) + m(rawValue[i]).format(paramFormat) ); } else { @@ -361,7 +366,7 @@ define( }, parseValue: function (value) { - return parseValueByMode(value, this.mode); + return parseValueByMode(value, this.mode, this.paramFormat); }, setRawValueWithoutFireChange: function (value) { @@ -375,6 +380,17 @@ define( } ); + MonthView.defaultProperties = { + range: { + begin: new Date(1982, 10, 4), + end: new Date(2046, 10, 4) + }, + paramFormat: 'YYYY-MM-DD', + dayNamesMin: ['一', '二', '三', '四', '五', '六', '日'], + monthSelectLabel: '月', + yearSelectLabel: '年' + }; + /** * 获取可选择的年列表 * @@ -447,7 +463,7 @@ define( ' id:${yearSelId};">', '', '', - '
', + '
${yearSelectLabel}
', '', '', '
', '', '', - '
', + '
${monthSelectLabel}
', '', '', '
0) { updateMultiRawValue(monthView); @@ -1059,24 +1061,21 @@ define( var controlHelper = monthView.helper; var rowTagId = controlHelper.getId('row-select'); var selectAllTag = lib.g(controlHelper.getId('month-title-0')); - var rowSelectedClasses - = controlHelper.getPartClasses('month-row-select-selected'); + var rowSelectedClass + = controlHelper.getPartClassName('month-row-select-selected'); var selectedRowNum = 0; for (var i = 0; i < rowTagNum; i++) { var rowTag = lib.g(rowTagId + '-' + i); - if (lib.hasClass(rowTag, rowSelectedClasses[0])) { + if ($(rowTag).hasClass(rowSelectedClass)) { selectedRowNum++; } } - if (selectedRowNum === rowTagNum) { - controlHelper.addPartClasses( - 'month-select-all-selected', selectAllTag); - } - else { - controlHelper.removePartClasses( - 'month-select-all-selected', selectAllTag); - } + setTagSelected( + selectAllTag, + selectedRowNum === rowTagNum, + rowSelectedClass + ); } /** @@ -1084,18 +1083,26 @@ define( * * @inner * @param {MonthView} monthView MonthView控件实例 + * @param {Object} $tar 点击的全选DOM节点的JQuery对象 */ - function selectAll(monthView) { + function selectAll(monthView, $tar) { // 获取横向选择状态 var controlHelper = monthView.helper; var rowTagNum = monthView.rowTagNum; var rowTagId = controlHelper.getId('row-select'); + var rowSelctedClass + = controlHelper.getPartClassName('month-row-select-selected'); + var rowTag; + var slected = $tar.hasClass(rowSelctedClass); for (var i = 0; i < rowTagNum; i++) { - var rowTag = lib.g(rowTagId + '-' + i); + rowTag = lib.g(rowTagId + '-' + i); // 先移除所有的选择 - controlHelper.removePartClasses( - 'month-row-select-selected', rowTag - ); + if (slected) { + $(rowTag).addClass(rowSelctedClass); + } + else { + $(rowTag).removeClass(rowSelctedClass); + } selectByTagClick(monthView, rowTag); } } @@ -1150,12 +1157,9 @@ define( for (var i = 0; i < dLength; i++) { id = controlHelper.getId(dates[i]); item = lib.g(id); - if (item) { - lib.removeClasses( - item, - controlHelper.getPartClasses('month-item-selected') - ); - } + $(item).removeClass( + controlHelper.getPartClassName('month-item-selected') + ); } } @@ -1175,12 +1179,9 @@ define( for (var i = 0; i < dLength; i++) { id = controlHelper.getId(dates[i]); item = lib.g(id); - if (item) { - lib.addClasses( - item, - controlHelper.getPartClasses('month-item-selected') - ); - } + $(item).addClass( + controlHelper.getPartClassName('month-item-selected') + ); } } @@ -1198,13 +1199,14 @@ define( if (!item) { return false; } - var classes = controlHelper.getPartClasses(className); - if (lib.hasClass(item, classes[0])) { - controlHelper.removePartClasses(className, item); + var $item = $(item); + var cls = controlHelper.getPartClassName(className); + if ($item.hasClass(cls)) { + $item.removeClass(cls); return false; } - controlHelper.addPartClasses(className, item); + $item.addClass(cls); return true; } @@ -1237,16 +1239,15 @@ define( repaintAllSelectTag(monthView); } else { - var itemSelectClasses - = monthView.helper.getPartClasses('month-item-selected'); - if (lib.hasClass(item, itemSelectClasses[0])) { + var itemSelectClass + = monthView.helper.getPartClassName('month-item-selected'); + if ($(item).hasClass(itemSelectClass)) { return; } var newDate = new Date(year, month, date); updateSingleSelectState(monthView, monthView.rawValue, newDate); monthView.rawValue = newDate; monthView.fire('change'); - monthView.fire('itemclick'); } } @@ -1454,14 +1455,14 @@ define( updateSelectStateByValue(monthView); } - function rangeAdapter(range) { + function rangeAdapter(range, format) { var begin; var end; // range类型如果是string if (typeof range === 'string') { var beginAndEnd = range.split(','); - begin = parseToDate(beginAndEnd[0]); - end = parseToDate(beginAndEnd[1]); + begin = m(beginAndEnd[0], format).toDate(); + end = m(beginAndEnd[1], format).toDate(); } else { begin = range.begin; @@ -1481,56 +1482,25 @@ define( }; } - /** - * 字符串日期转换为Date对象 - * - * @inner - * @param {string} dateStr 字符串日期 - * @return {Date} parse过的日期 - */ - function parseToDate(dateStr) { - function parse(source) { - var dates = source.split('-'); - if (dates) { - return new Date( - parseInt(dates[0], 10), - parseInt(dates[1], 10) - 1, - parseInt(dates[2], 10) - ); - } - return null; - } - - dateStr = dateStr + ''; - var dateAndHour = dateStr.split(' '); - var date = parse(dateAndHour[0]); - if (dateAndHour[1]) { - var clock = dateAndHour[1].split(':'); - date.setHours(clock[0]); - date.setMinutes(clock[1]); - date.setSeconds(clock[2]); - } - return date; - } - /** * 根据不同模式将字符串值解析为rawValue * * @inner * @param {string} value 字符串日期 * @param {string} mode 日历模式 multi | single + * @param {string} format 日期格式 * @return {Date | Array} */ - function parseValueByMode(value, mode) { + function parseValueByMode(value, mode, format) { if (mode === 'single') { - return parseToDate(value); + return m(value, format).toDate(); } var dateStrs = value.split(','); var dates = []; for (var i = 0; i < dateStrs.length - 1; i += 2) { - var begin = parseToDate(dateStrs[i]); - var end = parseToDate(dateStrs[i + 1]); + var begin = m(dateStrs[i], format).toDate(); + var end = m(dateStrs[i + 1], format).toDate(); var temp; if (!begin || !end) { continue; diff --git a/src/Pager.js b/src/Pager.js index a004633c..36afea00 100644 --- a/src/Pager.js +++ b/src/Pager.js @@ -6,16 +6,360 @@ * @file 翻页控件 * @author shenbin */ + define( function (require) { var u = require('underscore'); var lib = require('./lib'); - var ui = require('./main'); + var esui = require('./main'); var Control = require('./Control'); - + var painters = require('./painters'); + var eoo = require('eoo'); require('./Select'); + /** + * 翻页控件 + * + * 翻页控件包含2部分: + * + * - 一个显示页码的横条,根据各个属性配置显示当前页和前后若干页 + * - 一个选择“每页显示数量”的{@link Select}控件 + * + * @extends Control + * @requires Select + * @constructor + */ + var Pager = eoo.create( + Control, + { + /** + * 控件类型,始终为`"Pager"` + * + * @type {string} + * @readonly + * @override + */ + type: 'Pager', + + /** + * 初始化参数 + * + * @param {Object} [options] 构造函数传入的参数 + * @protected + * @override + */ + initOptions: function (options) { + var properties = { + pageType: 'anchor', + count: 0, + page: 1, + backCount: 3, + forwardCount: 3, + + urlTemplate: '', + layout: 'alignLeft' + }; + + u.extend( + properties, + Pager.defaultProperties, + options + ); + this.setProperties(properties); + }, + + /** + * 初始化DOM结构 + * + * @protected + * @override + */ + initStructure: function () { + // 填充主元素代码 + this.main.innerHTML = getMainHTML(this); + // 创建控件树 + this.helper.initChildren(); + + // 当初始化pageSizes属性不存在或为空数组时,隐藏控件显示 + var select = this.getChild('select'); + if (!this.pageSizes || !this.pageSizes.length) { + select.hide(); + } + else { + var properties = { + datasource: getPageSizes(this.pageSizes), + value: this.pageSize + '' + }; + select.setProperties(properties); + + // 同步一次状态 + changePageSize.call(this); + } + }, + + /** + * 初始化事件交互 + * + * @protected + * @override + */ + initEvents: function () { + // 每页显示的select控件 + var select = this.getChild('select'); + select.on('change', changePageSize, this); + + // pager主元素绑定事件 + this.helper.addDOMEvent('main', 'click', pagerClick); + }, + + /** + * 批量设置控件的属性值 + * + * @param {Object} properties 属性值集合 + * @override + */ + setProperties: function (properties) { + properties = u.clone(properties); + + // `pageIndex`提供从0开始的页码,但是以`page`为准 + if (properties.hasOwnProperty('pageIndex') + && !properties.hasOwnProperty('page') + ) { + /** + * @property {number} pageIndex + * + * 以0为起始的页码,其值始终为{@link Pager#page}减1 + * + * 如果与{@link Pager#page}属性同时存在, + * 则优先使用{@link Pager#page}属性 + */ + properties.page = +properties.pageIndex + 1; + } + + var digitalProperties = [ + 'count', 'page', 'backCount', + 'forwardCount', 'pageSize' + ]; + + u.each( + digitalProperties, + function (name) { + var value = properties[name]; + if (u.isString(value)) { + properties[name] = +value; + } + } + ); + + var changes + = Control.prototype.setProperties.apply(this, arguments); + + if (changes.hasOwnProperty('page')) { + // 触发页码变更事件 + /** + * @event changepage + * + * 页码变化时触发 + * + * @member Pager + * @deprecated 使用{@link Pager#pagechange}代替 + */ + this.fire('changepage'); + + /** + * @event pagechange + * + * 页码变化时触发 + * + * @member Pager + */ + this.fire('pagechange'); + } + }, + + /** + * 重渲染 + * + * @method + * @protected + * @override + */ + repaint: painters.createRepaint( + Control.prototype.repaint, + { + /** + * @property {number[]} pageSizes + * + * 可用的“每页条数”列表 + */ + name: 'pageSizes', + paint: function (pager, value) { + var select = pager.getChild('select'); + // 当`pageSizes`属性不存在或为空数组时,隐藏控件显示 + if (!value || !value.length) { + select.hide(); + } + else { + var properties = { + datasource: getPageSizes(value), + value: pager.pageSize + '' + }; + select.setProperties(properties); + select.show(); + } + } + }, + { + /** + * @property {string} [layout="alignLeft"] + * + * 指定控件的布局方式,可以使用以下值: + * + * - `alignLeft`:整体靠左对齐,页码在左,选择框在右 + * - `alignLeftReversed`:整体靠左对齐,而码在右,选择框在左 + * - `alignRight`:整体靠右对齐,页码在左,选择框在右 + * - `alignRightReversed`:整体靠右对齐,而码在右,选择框在左 + * - `distributed`:页码靠左对齐,选择框靠右对齐 + * - `distributedReversed`:页码靠右对齐,选择框靠左对齐 + */ + name: 'layout', + paint: repaintLayout + }, + { + name: [ + /** + * @property {string} [pageType="anchor"] + * + * 页码元素类型,可以为: + * + * - `plain`:页码为普通文本,点击后不跳转链接, + * 仅触发{@link Pager#pagechange}事件 + * - `anchor`:页码为``元素,点击后直接跳转 + */ + + 'pageType', + + /** + * @property {number} [count=0] + * + * 总条目数量 + */ + 'count', + + /** + * @property {number} pageSize + * + * 每页显示条目数量 + */ + 'pageSize', + + /** + * @property {number} [page=1] + * + * 当前页码,以1为起始,即1表示第1页 + */ + 'page', + + /** + * @property {number} backCount + * + * 在当前页前面显示的页数 + * + * 如{@link Pager#page}值为5,`backCount`为3, + * 则显示`[2] [3] [4] [5]` + */ + 'backCount', + + /** + * @property {number} forwardCount + * + * 在当前页后面显示的页数 + * + * 如{@link Pager#page}值为5,`forwardCount`为3, + * 则显示`[5] [6] [7] [8]` + */ + 'forwardCount', + /** + * @property {string} firstText + * + * “首页”元素的显示文字 + */ + 'firstText', + /** + * @property {string} lastText + * + * “末页”元素的显示文字 + */ + 'lastText', + /** + * @property {string} backText + * + * “下一页”元素的显示文字 + */ + 'backText', + /** + * @property {string} pagePattern + * + * 分页模式,默认中间分页模式'middlePattern',不显示“首页”与“末页”标签。 + * 可选完整模式'fullPattern',后继会增加简化模式'simplePattern'与 + * 极简模式'verySimplePattern' + */ + 'pagePattern', + /** + * @property {string} forwardText + * + * “上一页”元素的显示文字 + */ + 'forwardText', + + /** + * @property {string} urlTemplate + * + * 用于生成链接地址的URL模板 + * + * 模板中可以使用以下占位符: + * + * - `page`:当前页码 + * - `pageSize`:每页显示条目数 + */ + 'urlTemplate' + ], + paint: repaintPager + } + ), + + /** + * 获取从0开始的页码 + * + * @return {number} 其值始终为{@link Pager#page}减去1 + */ + getPageIndex: function () { + return this.get('page') - 1; + } + } + ); + /** + * @cfg defaultProperties + * + * 默认属性值 + * + * @cfg {number[]} [defaultProperties.pageSizes] 默认每页数量可选项 + * @cfg {number} [defaultProperties.pageSize=15] 默认每页数量 + * @static + */ + Pager.defaultProperties = { + // 这里不加任何属性,不然会覆盖掉实例上的那个`defaultProperties`出问题, + // 如果使用者直接改这个,自然是要覆盖的就没关系 + pagerLabelText: '每页显示', + firstText: '首页', + lastText: '末页', + backText: '上一页', + forwardText: '下一页', + pageSizes: [15, 30, 50, 100], + pageSize: 15 + }; + /** * 获取控件主元素HTML * @@ -36,21 +380,22 @@ define( '', '
' ]; + var controlHelper = pager.helper; return lib.format( template.join(''), { - pagerWrapperId: pager.helper.getId('pager-wrapper'), - pagerWrapperClass: pager.helper.getPartClasses(pager.layout)[0], - selectWrapperId: pager.helper.getId('select-wrapper'), - selectWrapperClass: pager.helper.getPartClassName('select-wrapper'), - labelId: pager.helper.getId('label'), - labelClass: pager.helper.getPartClassName('label'), - labelText: '每页显示', - selectPagerId: pager.helper.getId('selectPager'), - selectClass: pager.helper.getPartClassName('select'), - mainId: pager.helper.getId('main'), - mainClass: pager.helper.getPartClassName('main') + pagerWrapperId: controlHelper.getId('pager-wrapper'), + pagerWrapperClass: controlHelper.getPartClassName(pager.layout), + selectWrapperId: controlHelper.getId('select-wrapper'), + selectWrapperClass: controlHelper.getPartClassName('select-wrapper'), + labelId: controlHelper.getId('label'), + labelClass: controlHelper.getPartClassName('label'), + labelText: pager.pagerLabelText, + selectPagerId: controlHelper.getId('selectPager'), + selectClass: controlHelper.getPartClassName('select'), + mainId: controlHelper.getId('main'), + mainClass: controlHelper.getPartClassName('main') } ); } @@ -69,6 +414,7 @@ define( var anchorTpl = '
  • ' + '${text}
  • '; var omitTpl = '
  • '; + var html = []; /** * 根据模板拼接url @@ -98,8 +444,12 @@ define( * @ignore */ function getTplObj(className, num, id, text) { + var cls = []; + u.each(className.split(' '), function (name) { + cls.push(pager.helper.getPartClassName(name)); + }); var obj = { - className: pager.helper.getPartClassName(className) + className: cls.join(' ') }; if (arguments.length > 1) { @@ -157,12 +507,12 @@ define( // 计算得到的总页码数 var totalPage = Math.ceil(pager.count / pager.pageSize); // 数组html用于存储页码区域的元素代码 - var html = []; + if (page > 1) { if (pagePattern === 'fullPattern') { // 首页 var objFirst = getTplObj( - 'item-extend ui-pager-item-first', + 'item-extend item-first', 0, 'page-first', pager.firstText @@ -171,13 +521,14 @@ define( } // 上一页 - var obj = getTplObj( - 'item-extend', - page - 1, - 'page-back', - pager.backText + addSegmentToHTML( + getTplObj( + 'item-extend', + page - 1, + 'page-back', + pager.backText + ) ); - addSegmentToHTML(obj); } // 前缀页码 @@ -186,8 +537,7 @@ define( // 前缀...符号 if (page > backCount + 2) { - var obj = getTplObj('item-omit'); - addSegmentToHTML(obj, omitTpl); + addSegmentToHTML(getTplObj('item-omit'), omitTpl); } } @@ -201,28 +551,29 @@ define( } // 当前页码 - var obj = getTplObj( - 'item-current', - page, - 'page-' + page, - page + addSegmentToHTML( + getTplObj( + 'item-current', + page, + 'page-' + page, + page + ), + plainTpl ); - addSegmentToHTML(obj, plainTpl); // 后置页码 - var len = totalPage - page > forwardCount + var len2 = totalPage - page > forwardCount ? forwardCount : totalPage - page; - for (var i = page + 1; i < page + len + 1; i++) { - addSegmentToHTML(i); + for (var j = page + 1; j < page + len2 + 1; j++) { + addSegmentToHTML(j); } // 后缀页码 if (page < totalPage - forwardCount) { // 后缀...符号 if (page < totalPage - forwardCount - 1) { - var obj = getTplObj('item-omit'); - addSegmentToHTML(obj, omitTpl); + addSegmentToHTML(getTplObj('item-omit'), omitTpl); } addSegmentToHTML(totalPage); @@ -230,22 +581,24 @@ define( if (page < totalPage) { // 下一页 - var obj = getTplObj( - 'item-extend', - page + 1, - 'page-forward', - pager.forwardText + addSegmentToHTML( + getTplObj( + 'item-extend', + page + 1, + 'page-forward', + pager.forwardText + ) ); - addSegmentToHTML(obj); if (pagePattern === 'fullPattern') { // 末页 - var objLast = getTplObj( - 'item-extend ui-pager-item-last', - Math.ceil(pager.count / pager.pageSize), - 'page-last', - pager.lastText + addSegmentToHTML( + getTplObj( + 'item-extend item-last', + Math.ceil(pager.count / pager.pageSize), + 'page-last', + pager.lastText + ) ); - addSegmentToHTML(objLast); } } return html.join(''); @@ -284,6 +637,7 @@ define( * @ignore */ function repaintLayout(pager, style) { + /** * 获取class的集合 * @@ -294,22 +648,21 @@ define( function getClasses() { var classes = []; for (var i = 0, len = arguments.length; i < len; i++) { - classes.push(pager.helper.getPartClasses(arguments[i])[0]); + classes.push(pager.helper.getPartClassName(arguments[i])); } - return classes; + return classes.join(' '); } - var pagerWrapper = pager.helper.getPart('pager-wrapper'); - lib.removeClasses( - pagerWrapper, + var $pagerWrapper = $(pager.helper.getPart('pager-wrapper')); + $pagerWrapper.removeClass( getClasses( 'alignLeft', 'alignLeftReversed', 'alignRight', 'alignRightReversed', 'distributed', 'distributedReversed' ) ); - lib.addClass(pagerWrapper, pager.helper.getPartClasses(style)[0]); + $pagerWrapper.addClass(pager.helper.getPartClassName(style)); } /** @@ -320,14 +673,15 @@ define( */ function pagerClick(e) { var target = e.target; - var lastId = this.helper.getId('page-last'); - var backId = this.helper.getId('page-back'); - var forwardId = this.helper.getId('page-forward'); - var firstId = this.helper.getId('page-first'); + var controlHelper = this.helper; + var lastId = controlHelper.getId('page-last'); + var backId = controlHelper.getId('page-back'); + var forwardId = controlHelper.getId('page-forward'); + var firstId = controlHelper.getId('page-first'); var page = this.page; - if (this.helper.isPart(target, 'item') - || this.helper.isPart(target, 'item-extend') + if (controlHelper.isPart(target, 'item') + || controlHelper.isPart(target, 'item-extend') ) { if (target.id === backId) { page--; @@ -361,7 +715,7 @@ define( var datasource = u.map( pageSizes, function (size) { - return { text: size + '', value: size + '' }; + return {text: size + '', value: size + ''}; } ); @@ -402,384 +756,7 @@ define( this.fire('pagesizechange'); } - /** - * 显示`Select`控件及对应的label元素 - * - * @param {Pager} pager 控件实例 - * @ignore - */ - function showSelect(pager) { - var selectWrapper = pager.helper.getPart('select-wrapper'); - pager.helper.removePartClasses('select-wrapper-hidden', selectWrapper); - } - - /** - * 隐藏`Select`控件及对应的label元素 - * - * @param {Pager} pager 控件实例 - * @ignore - */ - function hideSelect(pager) { - var selectWrapper = pager.helper.getPart('select-wrapper'); - pager.helper.addPartClasses('select-wrapper-hidden', selectWrapper); - } - - /** - * 翻页控件 - * - * 翻页控件包含2部分: - * - * - 一个显示页码的横条,根据各个属性配置显示当前页和前后若干页 - * - 一个选择“每页显示数量”的{@link Select}控件 - * - * @extends Control - * @requires Select - * @constructor - */ - function Pager(options) { - Control.apply(this, arguments); - } - - - /** - * @cfg defaultProperties - * - * 默认属性值 - * - * @cfg {number[]} [defaultProperties.pageSizes] 默认每页数量可选项 - * @cfg {number} [defaultProperties.pageSize=15] 默认每页数量 - * @static - */ - Pager.defaultProperties = { - // 这里不加任何属性,不然会覆盖掉实例上的那个`defaultProperties`出问题, - // 如果使用者直接改这个,自然是要覆盖的就没关系 - }; - - - Pager.prototype = { - /** - * 控件类型,始终为`"Pager"` - * - * @type {string} - * @readonly - * @override - */ - type: 'Pager', - - /** - * 默认属性 - * - * @type {Object} - * @deprecated 使用构造函数上的{@link Pager#cfg-defaultProperties}代替 - */ - defaultProperties: { - pageSizes: [15, 30, 50, 100], - pageSize: 15 - }, - - /** - * 初始化参数 - * - * @param {Object} [options] 构造函数传入的参数 - * @protected - * @override - */ - initOptions: function (options) { - var properties = { - pageType: 'anchor', - count: 0, - page: 1, - backCount: 3, - forwardCount: 3, - firstText: '首页', - lastText: '末页', - backText: '上一页', - forwardText: '下一页', - urlTemplate: '', - layout: 'alignLeft' - }; - - u.extend( - properties, - this.defaultProperties, // 这么是向后兼容,以后准备去掉 - Pager.defaultProperties, - options - ); - this.setProperties(properties); - }, - - /** - * 初始化DOM结构 - * - * @protected - * @override - */ - initStructure: function () { - // 填充主元素代码 - this.main.innerHTML = getMainHTML(this); - // 创建控件树 - this.helper.initChildren(); - - // 当初始化pageSizes属性不存在或为空数组时,隐藏控件显示 - var select = this.getChild('select'); - if (!this.pageSizes || !this.pageSizes.length) { - hideSelect(this); - } - else { - var properties = { - datasource: getPageSizes(this.pageSizes), - value: this.pageSize + '' - }; - select.setProperties(properties); - - // 同步一次状态 - changePageSize.call(this); - } - }, - - /** - * 初始化事件交互 - * - * @protected - * @override - */ - initEvents: function () { - // 每页显示的select控件 - var select = this.getChild('select'); - select.on('change', changePageSize, this); - - // pager主元素绑定事件 - this.helper.addDOMEvent('main', 'click', pagerClick); - }, - - /** - * 批量设置控件的属性值 - * - * @param {Object} properties 属性值集合 - * @override - */ - setProperties: function (properties) { - properties = u.clone(properties); - - // `pageIndex`提供从0开始的页码,但是以`page`为准 - if (properties.hasOwnProperty('pageIndex') - && !properties.hasOwnProperty('page') - ) { - /** - * @property {number} pageIndex - * - * 以0为起始的页码,其值始终为{@link Pager#page}减1 - * - * 如果与{@link Pager#page}属性同时存在, - * 则优先使用{@link Pager#page}属性 - */ - properties.page = +properties.pageIndex + 1; - } - - var digitalProperties = [ - 'count', 'page', 'backCount', - 'forwardCount', 'pageSize' - ]; - - u.each( - digitalProperties, - function (name) { - var value = properties[name]; - if (u.isString(value)) { - properties[name] = +value; - } - } - ); - - var changes = - Control.prototype.setProperties.apply(this, arguments); - - if (changes.hasOwnProperty('page')) { - // 触发页码变更事件 - /** - * @event changepage - * - * 页码变化时触发 - * - * @member Pager - * @deprecated 使用{@link Pager#pagechange}代替 - */ - this.fire('changepage'); - - /** - * @event pagechange - * - * 页码变化时触发 - * - * @member Pager - */ - this.fire('pagechange'); - } - }, - - /** - * 重渲染 - * - * @method - * @protected - * @override - */ - repaint: require('./painters').createRepaint( - Control.prototype.repaint, - { - /** - * @property {number[]} pageSizes - * - * 可用的“每页条数”列表 - */ - name: 'pageSizes', - paint: function (pager, value) { - var select = pager.getChild('select'); - // 当`pageSizes`属性不存在或为空数组时,隐藏控件显示 - if (!value || !value.length) { - hideSelect(pager); - } - else { - var properties = { - datasource: getPageSizes(value), - value: pager.pageSize + '' - }; - select.setProperties(properties); - showSelect(pager); - } - } - }, - { - /** - * @property {string} [layout="alignLeft"] - * - * 指定控件的布局方式,可以使用以下值: - * - * - `alignLeft`:整体靠左对齐,页码在左,选择框在右 - * - `alignLeftReversed`:整体靠左对齐,而码在右,选择框在左 - * - `alignRight`:整体靠右对齐,页码在左,选择框在右 - * - `alignRightReversed`:整体靠右对齐,而码在右,选择框在左 - * - `distributed`:页码靠左对齐,选择框靠右对齐 - * - `distributedReversed`:页码靠右对齐,选择框靠左对齐 - */ - name: 'layout', - paint: repaintLayout - }, - { - name: [ - /** - * @property {string} [pageType="anchor"] - * - * 页码元素类型,可以为: - * - * - `plain`:页码为普通文本,点击后不跳转链接, - * 仅触发{@link Pager#pagechange}事件 - * - `anchor`:页码为``元素,点击后直接跳转 - */ - - 'pageType', - - /** - * @property {number} [count=0] - * - * 总条目数量 - */ - 'count', - - /** - * @property {number} pageSize - * - * 每页显示条目数量 - */ - 'pageSize', - - /** - * @property {number} [page=1] - * - * 当前页码,以1为起始,即1表示第1页 - */ - 'page', - - /** - * @property {number} backCount - * - * 在当前页前面显示的页数 - * - * 如{@link Pager#page}值为5,`backCount`为3, - * 则显示`[2] [3] [4] [5]` - */ - 'backCount', - - /** - * @property {number} forwardCount - * - * 在当前页后面显示的页数 - * - * 如{@link Pager#page}值为5,`forwardCount`为3, - * 则显示`[5] [6] [7] [8]` - */ - 'forwardCount', - /** - * @property {string} firstText - * - * “首页”元素的显示文字 - */ - 'firstText', - /** - * @property {string} lastText - * - * “末页”元素的显示文字 - */ - 'lastText', - /** - * @property {string} backText - * - * “下一页”元素的显示文字 - */ - 'backText', - /** - * @property {string} pagePattern - * - * 分页模式,默认中间分页模式'middlePattern',不显示“首页”与“末页”标签。 - * 可选完整模式'fullPattern',后继会增加简化模式'simplePattern'与 - * 极简模式'verySimplePattern' - */ - 'pagePattern', - /** - * @property {string} forwardText - * - * “上一页”元素的显示文字 - */ - 'forwardText', - - /** - * @property {string} urlTemplate - * - * 用于生成链接地址的URL模板 - * - * 模板中可以使用以下占位符: - * - * - `page`:当前页码 - * - `pageSize`:每页显示条目数 - */ - 'urlTemplate' - ], - paint: repaintPager - } - ), - - /** - * 获取从0开始的页码 - * - * @return {number} 其值始终为{@link Pager#page}减去1 - */ - getPageIndex: function () { - return this.get('page') - 1; - } - }; - - lib.inherits(Pager, Control); - ui.register(Pager); + esui.register(Pager); return Pager; } ); diff --git a/src/Panel.js b/src/Panel.js index ec04aee3..18c49fcf 100644 --- a/src/Panel.js +++ b/src/Panel.js @@ -9,8 +9,10 @@ define( function (require) { var u = require('underscore'); - var lib = require('./lib'); var Control = require('./Control'); + var eoo = require('eoo'); + var painters = require('./painters'); + var esui = require('./main'); /** * 通用面板 @@ -24,113 +26,158 @@ define( * @extends Control * @constructor */ - function Panel() { - Control.apply(this, arguments); - } + var Panel = eoo.create( + Control, + { + /** + * 控件类型,始终为`"Panel"` + * + * @type {string} + * @readonly + * @override + */ + type: 'Panel', - /** - * 控件类型,始终为`"Panel"` - * - * @type {string} - * @readonly - * @override - */ - Panel.prototype.type = 'Panel'; + /** + * 获取控件的分类 + * + * @return {string} 始终返回`"container"` + * @override + */ + getCategory: function () { + return 'container'; + }, - /** - * 获取控件的分类 - * - * @return {string} 始终返回`"container"` - * @override - */ - Panel.prototype.getCategory = function () { - return 'container'; - }; + /** + * 创建控件主元素 + * + * 如果初始化时提供{@link Panel#tagName}属性,则以此创建元素, + * 默认使用`
    `元素 + * + * @param {Object} options 构造函数传入的参数 + * @return {HTMLElement} + * @protected + * @override + */ + createMain: function (options) { + if (!options.tagName) { + return this.$super([options]); + } + return document.createElement(options.tagName); + }, - /** - * 创建控件主元素 - * - * 如果初始化时提供{@link Panel#tagName}属性,则以此创建元素, - * 默认使用`
    `元素 - * - * @param {Object} options 构造函数传入的参数 - * @return {HTMLElement} - * @protected - * @override - */ - Panel.prototype.createMain = function (options) { - if (!options.tagName) { - return Control.prototype.createMain.call(this); - } - return document.createElement(options.tagName); - }; + /** + * 初始化参数 + * + * 如果初始化时提供了主元素,则使用主元素的标签名作为{@link Panel#tagName}属性 + * + * @param {Object} [options] 构造函数传入的参数 + * @protected + * @override + */ + initOptions: function (options) { + var properties = {}; + u.extend(properties, options); + /** + * @property {string} tagName + * + * 指定主元素标签名 + * + * 此属性仅在初始化时生效,运行期不能修改 + * + * @readonly + */ + properties.tagName = this.main.nodeName.toLowerCase(); + this.setProperties(properties); + }, - /** - * 初始化参数 - * - * 如果初始化时提供了主元素,则使用主元素的标签名作为{@link Panel#tagName}属性 - * - * @param {Object} [options] 构造函数传入的参数 - * @protected - * @override - */ - Panel.prototype.initOptions = function (options) { - var properties = {}; - u.extend(properties, options); - /** - * @property {string} tagName - * - * 指定主元素标签名 - * - * 此属性仅在初始化时生效,运行期不能修改 - * - * @readonly - */ - properties.tagName = this.main.nodeName.toLowerCase(); - this.setProperties(properties); - }; + /** + * 重渲染 + * + * @method + * @protected + * @override + */ + repaint: painters.createRepaint( + Control.prototype.repaint, + { + /** + * @property {string} content + * + * 面板的内容,为一个HTML片段 + * + * 此属性中可包含ESUI相关的属性,在设置内容后, + * 会使用{@link Helper#initChildren}进行内部控件的初始化 + */ + name: 'content', + paint: function (panel, content) { + // 第一次刷新的时候是可能没有`content`的, + // 这时在`innerHTML`上就地创建控件,不要刷掉内容, + // 后续有要求`content`是字符串,所以不管非字符串的后果 + if (content != null) { + panel.helper.disposeChildren(); + panel.main.innerHTML = content; + } + panel.helper.initChildren(); + } + } + ), - /** - * 重渲染 - * - * @method - * @protected - * @override - */ - Panel.prototype.repaint = require('./painters').createRepaint( - Control.prototype.repaint, - { /** - * @property {string} content + * 设置内容 * - * 面板的内容,为一个HTML片段 + * @param {string} html 内容HTML,具体参考{@link Panel#content}属性的说明 + */ + setContent: function (html) { + this.setProperties({content: html}); + }, + + /** + * 在面板最前面追加内容 + * + * @param {string} html 追加内容的HTML代码 + */ + prependContent: function (html) { + addContent.call(this, html, true); + }, + + /** + * 在面板最后面追加内容 + * + * @param {string} html 追加内容的HTML代码 + */ + appendContent: function (html) { + addContent.call(this, html, false); + }, + + /** + * 获取样式,仅获取设置的样式,不包含外部CSS给定的 + * + * @param {string} name 样式名称 + * @return {string} + */ + getStyle: function (name) { + name = normalizeStyleName(name); + return this.main + ? this.main.style[name] + : ''; + }, + + /** + * 设置样式 * - * 此属性中可包含ESUI相关的属性,在设置内容后, - * 会使用{@link Helper#initChildren}进行内部控件的初始化 + * @param {string} name 样式名称,如果只有这一个参数,则表示为整串样式 + * @param {string} [value=""] 样式值 */ - name: 'content', - paint: function (panel, content) { - // 第一次刷新的时候是可能没有`content`的, - // 这时在`innerHTML`上就地创建控件,不要刷掉内容, - // 后续有要求`content`是字符串,所以不管非字符串的后果 - if (content != null) { - panel.helper.disposeChildren(); - panel.main.innerHTML = content; + setStyle: function (name, value) { + name = normalizeStyleName(name); + if (this.main) { + this.main.style[name] = value || ''; } - panel.helper.initChildren(); } } ); - /** - * 设置内容 - * - * @param {string} html 内容HTML,具体参考{@link Panel#content}属性的说明 - */ - Panel.prototype.setContent = function (html) { - this.setProperties({ content: html }); - }; - /** * 追加内容 * @@ -154,7 +201,6 @@ define( children.push(childNodes[i]); } - var ui = require('./main'); u.each(children, function (child) { if (isPrepend) { main.insertBefore(child, main.firstChild); @@ -162,28 +208,10 @@ define( else { main.appendChild(child); } - ui.init(main, options); + esui.init(main, options); }); } - /** - * 在面板最前面追加内容 - * - * @param {string} html 追加内容的HTML代码 - */ - Panel.prototype.prependContent = function (html) { - addContent.call(this, html, true); - }; - - /** - * 在面板最后面追加内容 - * - * @param {string} html 追加内容的HTML代码 - */ - Panel.prototype.appendContent = function (html) { - addContent.call(this, html, false); - }; - /** * 统一化样式名 * @@ -204,34 +232,7 @@ define( return name; } - /** - * 获取样式,仅获取设置的样式,不包含外部CSS给定的 - * - * @param {string} name 样式名称 - * @return {string} - */ - Panel.prototype.getStyle = function (name) { - name = normalizeStyleName(name); - return this.main - ? this.main.style[name] - : ''; - }; - - /** - * 设置样式 - * - * @param {string} name 样式名称,如果只有这一个参数,则表示为整串样式 - * @param {string} [value=""] 样式值 - */ - Panel.prototype.setStyle = function (name, value) { - name = normalizeStyleName(name); - if (this.main) { - this.main.style[name] = value || ''; - } - }; - - lib.inherits(Panel, Control); - require('./main').register(Panel); + esui.register(Panel); return Panel; } ); diff --git a/src/main.js b/src/main.js index 97d3f40e..8644a81d 100644 --- a/src/main.js +++ b/src/main.js @@ -322,7 +322,7 @@ define( options = options || {}; var defaultValueParser = function (value) { - var coreNumber = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/; + var coreNumber = /^[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)$/; if (value === 'true') { value = true; } @@ -392,7 +392,7 @@ define( ); } else { - optionObject[joinCamelCase(terms)] = valueReplacer(value); + optionObject[joinCamelCase(terms)] = valueReplacer(valueParser(value)); } } diff --git a/src/painters.js b/src/painters.js index 93d5cf03..c97bc977 100644 --- a/src/painters.js +++ b/src/painters.js @@ -9,7 +9,6 @@ define( function (require) { var u = require('underscore'); - var lib = require('./lib'); /** * @class painters @@ -247,7 +246,7 @@ define( * - `{Control} control`:当前的控件实例 * - `{Mixed} args...`:根据`name`配置指定的属性,依次将属性的最新值作为参数 * - * @param {Object... | Function...} args `painter`对象 + * @param {...Object | Function} args `painter`对象 * @return {Function} `repaint`方法的实现 */ painters.createRepaint = function () { @@ -255,7 +254,7 @@ define( return function (changes, changesIndex) { // 临时索引,不能直接修改`changesIndex`,会导致子类的逻辑错误 - var index = lib.extend({}, changesIndex); + var index = u.extend({}, changesIndex); for (var i = 0; i < painters.length; i++) { var painter = painters[i]; @@ -288,29 +287,13 @@ define( // 收集所有属性的值 var properties = [this]; - for (var j = 0; j < propertyNames.length; j++) { - var name = propertyNames[j]; - properties.push(this[name]); + for (var k = 0; k < propertyNames.length; k++) { + var name2 = propertyNames[k]; + properties.push(this[name2]); // 从索引中删除,为了后续构建`unpainted`数组 - delete index[name]; + delete index[name2]; } - // 绘制 - try { - painter.paint.apply(painter, properties); - } - catch (ex) { - var paintingPropertyNames = - '"' + propertyNames.join('", "') + '"'; - var error = new Error( - 'Failed to paint [' + paintingPropertyNames + '] ' - + 'for control "' + (this.id || 'anonymous')+ '" ' - + 'of type ' + this.type + ' ' - + 'because: ' + ex.message - ); - error.actualError = ex; - throw error; - } - + painter.paint.apply(painter, properties); } // 构建出未渲染的属性集合