mirror of
https://github.com/ElemeFE/element.git
synced 2025-12-16 11:44:01 +08:00
Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c3ee5fc0df | ||
|
|
33bf6f9cd9 | ||
|
|
c0c0e728ca | ||
|
|
2260a3bab3 | ||
|
|
010b09891a | ||
|
|
9f2ea7eab0 | ||
|
|
aa02b42022 | ||
|
|
cbfd9cfab3 | ||
|
|
73184399ed | ||
|
|
7f8991a664 | ||
|
|
363a80b184 | ||
|
|
6c77cd9716 | ||
|
|
81011d1c48 | ||
|
|
4ea53ab896 | ||
|
|
651b517fd0 | ||
|
|
839dda529e | ||
|
|
4d71e2f3af | ||
|
|
c8477c815a | ||
|
|
38e320b8cc | ||
|
|
cee4542c36 | ||
|
|
fb066a6e45 | ||
|
|
513294d159 |
@@ -6,7 +6,7 @@
|
||||
"expect": true,
|
||||
"sinon": true
|
||||
},
|
||||
"plugins": ['vue'],
|
||||
"plugins": ['vue','json'],
|
||||
"extends": 'elemefe',
|
||||
"parserOptions": {
|
||||
"ecmaFeatures": {
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -14,3 +14,4 @@ fe.element/element-ui
|
||||
coverage
|
||||
waiter.config.js
|
||||
build/bin/algolia-key.js
|
||||
.envrc
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
## Changelog
|
||||
|
||||
### 2.0.4
|
||||
|
||||
*2017-11-10*
|
||||
|
||||
- Improved accessibility for Cascader, Dropdown, Message, Notification, Popover, Tooltip and Tree
|
||||
- Fixed Container resize when the width of viewport decreases, #8042
|
||||
- Fixed Tree's `updateKeyChildren` incorrectly deleting child nodes, #8100
|
||||
- Fixed bordered CheckboxButton's height when nested in a Form, #8100
|
||||
- Fixed Menu's parsing error for custom colors, #8153 (by @zhouyixiang)
|
||||
|
||||
### 2.0.3
|
||||
|
||||
*2017-11-03*
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
## 更新日志
|
||||
|
||||
### 2.0.4
|
||||
|
||||
*2017-11-10*
|
||||
|
||||
- 提升 Cascader、Dropdown、Message、Notification、Popover、Tooltip、Tree 的可访问性
|
||||
- 修复当视口变窄时 Container 无法同步更新其宽度的问题,#8042
|
||||
- 修复 Tree 的 `updateKeyChildren` 在删除子节点时的行为错误,#8100
|
||||
- 修复带有边框的 CheckboxButton 在 Form 中高度错误的问题,#8100
|
||||
- 修复 Menu 在解析自定义颜色时的错误,#8153(by @zhouyixiang)
|
||||
|
||||
### 2.0.3
|
||||
|
||||
*2017-11-03*
|
||||
|
||||
@@ -219,6 +219,7 @@
|
||||
const preferGithub = localStorage.getItem('PREFER_GITHUB');
|
||||
if (href.indexOf('element-cn') > -1 || preferGithub) return;
|
||||
setTimeout(() => {
|
||||
if (this.lang !== 'zh-CN') return;
|
||||
this.$confirm('建议大陆用户访问部署在国内的站点,是否跳转?', '提示')
|
||||
.then(() => {
|
||||
location.href = location.href.replace('element.', 'element-cn.');
|
||||
@@ -232,16 +233,14 @@
|
||||
|
||||
mounted() {
|
||||
this.localize();
|
||||
if (this.lang === 'zh-CN') {
|
||||
this.suggestJump();
|
||||
}
|
||||
this.suggestJump();
|
||||
setTimeout(() => {
|
||||
const notified = localStorage.getItem('RELEASE_NOTIFIED');
|
||||
if (!notified) {
|
||||
const notified = localStorage.getItem('ES_NOTIFIED');
|
||||
if (!notified && this.lang !== 'zh-CN') {
|
||||
const h = this.$createElement;
|
||||
const title = this.lang === 'zh-CN'
|
||||
? '2.0 正式发布'
|
||||
: '2.0 available now';
|
||||
? '帮助我们完成西班牙语文档'
|
||||
: 'Help us with Spanish docs';
|
||||
const messages = this.lang === 'zh-CN'
|
||||
? ['点击', '这里', '查看详情']
|
||||
: ['Click ', 'here', ' to learn more'];
|
||||
@@ -253,13 +252,13 @@
|
||||
h('a', {
|
||||
attrs: {
|
||||
target: '_blank',
|
||||
href: `https://github.com/ElemeFE/element/issues/${ this.lang === 'zh-CN' ? '7755' : '7756' }`
|
||||
href: 'https://github.com/ElemeFE/element/issues/8074'
|
||||
}
|
||||
}, messages[1]),
|
||||
messages[2]
|
||||
]),
|
||||
onClose() {
|
||||
localStorage.setItem('RELEASE_NOTIFIED', 1);
|
||||
localStorage.setItem('ES_NOTIFIED', 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
},
|
||||
{
|
||||
"name": "Element Angular",
|
||||
"href": "https://eleme.github.io/element-angular/"
|
||||
"href": "https://element-angular.faas.ele.me/"
|
||||
},
|
||||
{
|
||||
"name": "开发指南",
|
||||
@@ -260,7 +260,7 @@
|
||||
},
|
||||
{
|
||||
"name": "Element Angular",
|
||||
"href": "https://eleme.github.io/element-angular/"
|
||||
"href": "https://element-angular.faas.ele.me/"
|
||||
},
|
||||
{
|
||||
"name": "Development",
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"1.0.9":"1.0","1.1.6":"1.1","1.2.9":"1.2","1.3.7":"1.3","1.4.9":"1.4","2.0.3":"2.0"}
|
||||
{"1.0.9":"1.0","1.1.6":"1.1","1.2.9":"1.2","1.3.7":"1.3","1.4.9":"1.4","2.0.4":"2.0"}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "element-ui",
|
||||
"version": "2.0.3",
|
||||
"version": "2.0.4",
|
||||
"description": "A Component Library for Vue.js.",
|
||||
"main": "lib/element-ui.common.js",
|
||||
"files": [
|
||||
@@ -82,6 +82,7 @@
|
||||
"css-loader": "^0.28.7",
|
||||
"es6-promise": "^4.0.5",
|
||||
"eslint": "^3.10.2",
|
||||
"eslint-plugin-json": "^1.2.0",
|
||||
"extract-text-webpack-plugin": "^3.0.1",
|
||||
"file-loader": "^1.1.5",
|
||||
"file-save": "^0.2.0",
|
||||
|
||||
@@ -20,9 +20,12 @@
|
||||
separatorClass: ''
|
||||
};
|
||||
},
|
||||
|
||||
inject: ['elBreadcrumb'],
|
||||
|
||||
mounted() {
|
||||
this.separator = this.$parent.separator;
|
||||
this.separatorClass = this.$parent.separatorClass;
|
||||
this.separator = this.elBreadcrumb.separator;
|
||||
this.separatorClass = this.elBreadcrumb.separatorClass;
|
||||
let self = this;
|
||||
if (this.to) {
|
||||
let link = this.$refs.link;
|
||||
|
||||
@@ -17,6 +17,13 @@
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
|
||||
provide() {
|
||||
return {
|
||||
elBreadcrumb: this
|
||||
};
|
||||
},
|
||||
|
||||
mounted() {
|
||||
const items = this.$el.querySelectorAll('.el-breadcrumb__item');
|
||||
items[items.length - 1].setAttribute('aria-current', 'page');
|
||||
|
||||
@@ -10,9 +10,12 @@
|
||||
]"
|
||||
@click="handleClick"
|
||||
@mouseenter="inputHover = true"
|
||||
@focus="inputHover = true"
|
||||
@mouseleave="inputHover = false"
|
||||
@blur="inputHover = false"
|
||||
ref="reference"
|
||||
v-clickoutside="handleClickoutside"
|
||||
@keydown="handleKeydown"
|
||||
>
|
||||
<el-input
|
||||
ref="input"
|
||||
@@ -63,6 +66,7 @@ import emitter from 'element-ui/src/mixins/emitter';
|
||||
import Locale from 'element-ui/src/mixins/locale';
|
||||
import { t } from 'element-ui/src/locale';
|
||||
import debounce from 'throttle-debounce/debounce';
|
||||
import { generateId } from 'element-ui/src/utils/util';
|
||||
|
||||
const popperMixin = {
|
||||
props: {
|
||||
@@ -149,6 +153,10 @@ export default {
|
||||
beforeFilter: {
|
||||
type: Function,
|
||||
default: () => (() => {})
|
||||
},
|
||||
hoverThreshold: {
|
||||
type: Number,
|
||||
default: 500
|
||||
}
|
||||
},
|
||||
|
||||
@@ -191,11 +199,15 @@ export default {
|
||||
},
|
||||
cascaderSize() {
|
||||
return this.size || this._elFormItemSize || (this.$ELEMENT || {}).size;
|
||||
},
|
||||
id() {
|
||||
return generateId();
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
menuVisible(value) {
|
||||
this.$refs.input.$refs.input.setAttribute('aria-expanded', value);
|
||||
value ? this.showMenu() : this.hideMenu();
|
||||
},
|
||||
value(value) {
|
||||
@@ -204,6 +216,10 @@ export default {
|
||||
currentValue(value) {
|
||||
this.dispatch('ElFormItem', 'el.form.change', [value]);
|
||||
},
|
||||
currentLabels(value) {
|
||||
const inputLabel = this.showAllLevels ? value.join('/') : value[value.length - 1] ;
|
||||
this.$refs.input.$refs.input.setAttribute('value', inputLabel);
|
||||
},
|
||||
options: {
|
||||
deep: true,
|
||||
handler(value) {
|
||||
@@ -224,10 +240,13 @@ export default {
|
||||
this.menu.expandTrigger = this.expandTrigger;
|
||||
this.menu.changeOnSelect = this.changeOnSelect;
|
||||
this.menu.popperClass = this.popperClass;
|
||||
this.menu.hoverThreshold = this.hoverThreshold;
|
||||
this.popperElm = this.menu.$el;
|
||||
this.menu.$refs.menus[0].setAttribute('id', `cascader-menu-${this.id}`);
|
||||
this.menu.$on('pick', this.handlePick);
|
||||
this.menu.$on('activeItemChange', this.handleActiveItemChange);
|
||||
this.menu.$on('menuLeave', this.doDestroy);
|
||||
this.menu.$on('closeInside', this.handleClickoutside);
|
||||
},
|
||||
showMenu() {
|
||||
if (!this.menu) {
|
||||
@@ -245,6 +264,7 @@ export default {
|
||||
hideMenu() {
|
||||
this.inputValue = '';
|
||||
this.menu.visible = false;
|
||||
this.$refs.input.focus();
|
||||
},
|
||||
handleActiveItemChange(value) {
|
||||
this.$nextTick(_ => {
|
||||
@@ -252,6 +272,23 @@ export default {
|
||||
});
|
||||
this.$emit('active-item-change', value);
|
||||
},
|
||||
handleKeydown(e) {
|
||||
const keyCode = e.keyCode;
|
||||
if (keyCode === 13) {
|
||||
this.handleClick();
|
||||
} else if (keyCode === 40) { // down
|
||||
this.menuVisible = true; // 打开
|
||||
setTimeout(() => {
|
||||
const firstMenu = this.popperElm.querySelectorAll('.el-cascader-menu')[0];
|
||||
firstMenu.querySelectorAll("[tabindex='-1']")[0].focus();
|
||||
});
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
} else if (keyCode === 27 || keyCode === 9) { // esc tab
|
||||
this.inputValue = '';
|
||||
if (this.menu) this.menu.visible = false;
|
||||
}
|
||||
},
|
||||
handlePick(value, close = true) {
|
||||
this.currentValue = value;
|
||||
this.$emit('input', value);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script>
|
||||
import { isDef } from 'element-ui/src/utils/shared';
|
||||
import scrollIntoView from 'element-ui/src/utils/scroll-into-view';
|
||||
import { generateId } from 'element-ui/src/utils/util';
|
||||
|
||||
const copyArray = (arr, props) => {
|
||||
if (!arr || !Array.isArray(arr) || !props) return arr;
|
||||
@@ -39,7 +40,8 @@
|
||||
value: [],
|
||||
expandTrigger: 'click',
|
||||
changeOnSelect: false,
|
||||
popperClass: ''
|
||||
popperClass: '',
|
||||
hoverTimer: 0
|
||||
};
|
||||
},
|
||||
|
||||
@@ -94,6 +96,9 @@
|
||||
formatOptions(optionsCopy);
|
||||
return loadActiveOptions(optionsCopy);
|
||||
}
|
||||
},
|
||||
id() {
|
||||
return generateId();
|
||||
}
|
||||
},
|
||||
|
||||
@@ -135,11 +140,41 @@
|
||||
activeOptions,
|
||||
visible,
|
||||
expandTrigger,
|
||||
popperClass
|
||||
popperClass,
|
||||
hoverThreshold
|
||||
} = this;
|
||||
let itemId = null;
|
||||
let itemIndex = 0;
|
||||
|
||||
let hoverMenuRefs = {};
|
||||
const hoverMenuHandler = e => {
|
||||
const offsetX = e.offsetX;
|
||||
const width = hoverMenuRefs.activeMenu.offsetWidth;
|
||||
const height = hoverMenuRefs.activeMenu.offsetHeight;
|
||||
|
||||
if (e.target === hoverMenuRefs.activeItem) {
|
||||
clearTimeout(this.hoverTimer);
|
||||
const {activeItem} = hoverMenuRefs;
|
||||
const offsetY_top = activeItem.offsetTop;
|
||||
const offsetY_Bottom = offsetY_top + activeItem.offsetHeight;
|
||||
|
||||
hoverMenuRefs.hoverZone.innerHTML = `
|
||||
<path style="pointer-events: auto;" fill="transparent" d="M${offsetX} ${offsetY_top} L${width} 0 V${offsetY_top} Z" />
|
||||
<path style="pointer-events: auto;" fill="transparent" d="M${offsetX} ${offsetY_Bottom} L${width} ${height} V${offsetY_Bottom} Z" />
|
||||
`;
|
||||
} else {
|
||||
if (!this.hoverTimer) {
|
||||
this.hoverTimer = setTimeout(() => {
|
||||
hoverMenuRefs.hoverZone.innerHTML = '';
|
||||
}, hoverThreshold);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const menus = this._l(activeOptions, (menu, menuIndex) => {
|
||||
let isFlat = false;
|
||||
const menuId = `menu-${this.id}-${ menuIndex}`;
|
||||
const ownsId = `menu-${this.id}-${ menuIndex + 1 }`;
|
||||
const items = this._l(menu, item => {
|
||||
const events = {
|
||||
on: {}
|
||||
@@ -148,12 +183,52 @@
|
||||
if (item.__IS__FLAT__OPTIONS) isFlat = true;
|
||||
|
||||
if (!item.disabled) {
|
||||
// keydown up/down/left/right/enter
|
||||
events.on.keydown = (ev) => {
|
||||
const keyCode = ev.keyCode;
|
||||
if (![37, 38, 39, 40, 13, 9, 27].includes(keyCode)) {
|
||||
return;
|
||||
}
|
||||
const currentEle = ev.target;
|
||||
const parentEle = this.$refs.menus[menuIndex];
|
||||
const menuItemList = parentEle.querySelectorAll("[tabindex='-1']");
|
||||
const currentIndex = Array.prototype.indexOf.call(menuItemList, currentEle); // 当前索引
|
||||
let nextIndex, nextMenu;
|
||||
if ([38, 40].includes(keyCode)) {
|
||||
if (keyCode === 38) { // up键
|
||||
nextIndex = currentIndex !== 0 ? (currentIndex - 1) : currentIndex;
|
||||
} else if (keyCode === 40) { // down
|
||||
nextIndex = currentIndex !== (menuItemList.length - 1) ? currentIndex + 1 : currentIndex;
|
||||
}
|
||||
menuItemList[nextIndex].focus();
|
||||
} else if (keyCode === 37) { // left键
|
||||
if (menuIndex !== 0) {
|
||||
const previousMenu = this.$refs.menus[menuIndex - 1];
|
||||
previousMenu.querySelector('[aria-expanded=true]').focus();
|
||||
}
|
||||
} else if (keyCode === 39) { // right
|
||||
if (item.children) {
|
||||
// 有子menu 选择子menu的第一个menuitem
|
||||
nextMenu = this.$refs.menus[menuIndex + 1];
|
||||
nextMenu.querySelectorAll("[tabindex='-1']")[0].focus();
|
||||
}
|
||||
} else if (keyCode === 13) {
|
||||
if (!item.children) {
|
||||
const id = currentEle.getAttribute('id');
|
||||
parentEle.setAttribute('aria-activedescendant', id);
|
||||
this.select(item, menuIndex);
|
||||
this.$nextTick(() => this.scrollMenu(this.$refs.menus[menuIndex]));
|
||||
}
|
||||
} else if (keyCode === 9 || keyCode === 27) { // esc tab
|
||||
this.$emit('closeInside');
|
||||
}
|
||||
};
|
||||
if (item.children) {
|
||||
let triggerEvent = {
|
||||
click: 'click',
|
||||
hover: 'mouseenter'
|
||||
}[expandTrigger];
|
||||
events.on[triggerEvent] = () => {
|
||||
events.on[triggerEvent] = events.on['focus'] = () => { // focus 选中
|
||||
this.activeItem(item, menuIndex);
|
||||
this.$nextTick(() => {
|
||||
// adjust self and next level
|
||||
@@ -168,7 +243,10 @@
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (!item.disabled && !item.children) { // no children set id
|
||||
itemId = `${menuId}-${itemIndex}`;
|
||||
itemIndex++;
|
||||
}
|
||||
return (
|
||||
<li
|
||||
class={{
|
||||
@@ -177,7 +255,14 @@
|
||||
'is-active': item.value === activeValue[menuIndex],
|
||||
'is-disabled': item.disabled
|
||||
}}
|
||||
ref={item.value === activeValue[menuIndex] ? 'activeItem' : null}
|
||||
{...events}
|
||||
tabindex= { item.disabled ? null : -1 }
|
||||
role="menuitem"
|
||||
aria-haspopup={ !!item.children }
|
||||
aria-expanded={ item.value === activeValue[menuIndex] }
|
||||
id = { itemId }
|
||||
aria-owns = { !item.children ? null : ownsId }
|
||||
>
|
||||
{item.label}
|
||||
</li>
|
||||
@@ -188,19 +273,68 @@
|
||||
menuStyle.minWidth = this.inputWidth + 'px';
|
||||
}
|
||||
|
||||
const isHoveredMenu = expandTrigger === 'hover' && activeValue.length - 1 === menuIndex;
|
||||
const hoverMenuEvent = {
|
||||
on: {
|
||||
}
|
||||
};
|
||||
|
||||
if (isHoveredMenu) {
|
||||
hoverMenuEvent.on.mousemove = hoverMenuHandler;
|
||||
menuStyle.position = 'relative';
|
||||
}
|
||||
|
||||
return (
|
||||
<ul
|
||||
class={{
|
||||
'el-cascader-menu': true,
|
||||
'el-cascader-menu--flexible': isFlat
|
||||
}}
|
||||
{...hoverMenuEvent}
|
||||
style={menuStyle}
|
||||
refInFor
|
||||
ref="menus">
|
||||
ref="menus"
|
||||
role="menu"
|
||||
id = { menuId }
|
||||
>
|
||||
{items}
|
||||
{
|
||||
isHoveredMenu
|
||||
? (<svg
|
||||
ref="hoverZone"
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
left: 0,
|
||||
pointerEvents: 'none'
|
||||
}}
|
||||
></svg>) : null
|
||||
}
|
||||
</ul>
|
||||
);
|
||||
});
|
||||
|
||||
if (expandTrigger === 'hover') {
|
||||
this.$nextTick(() => {
|
||||
const activeItem = this.$refs.activeItem;
|
||||
|
||||
if (activeItem) {
|
||||
const activeMenu = activeItem.parentElement;
|
||||
const hoverZone = this.$refs.hoverZone;
|
||||
|
||||
hoverMenuRefs = {
|
||||
activeMenu,
|
||||
activeItem,
|
||||
hoverZone
|
||||
};
|
||||
} else {
|
||||
hoverMenuRefs = {};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<transition name="el-zoom-in-top" on-before-enter={this.handleMenuEnter} on-after-leave={this.handleMenuLeave}>
|
||||
<div
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
'el-dropdown-menu__item--divided': divided
|
||||
}"
|
||||
@click="handleClick"
|
||||
:aria-disabled="disabled"
|
||||
:tabindex="disabled ? null : -1"
|
||||
>
|
||||
<slot></slot>
|
||||
</li>
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
import Migrating from 'element-ui/src/mixins/migrating';
|
||||
import ElButton from 'element-ui/packages/button';
|
||||
import ElButtonGroup from 'element-ui/packages/button-group';
|
||||
import { generateId } from 'element-ui/src/utils/util';
|
||||
|
||||
export default {
|
||||
name: 'ElDropdown',
|
||||
@@ -61,25 +62,43 @@
|
||||
return {
|
||||
timeout: null,
|
||||
visible: false,
|
||||
triggerElm: null
|
||||
triggerElm: null,
|
||||
menuItems: null,
|
||||
menuItemsArray: null,
|
||||
dropdownElm: null,
|
||||
focusing: false
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
dropdownSize() {
|
||||
return this.size || (this.$ELEMENT || {}).size;
|
||||
},
|
||||
listId() {
|
||||
return `dropdown-menu-${generateId()}`;
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.$on('menu-item-click', this.handleMenuItemClick);
|
||||
this.initEvent();
|
||||
this.initAria();
|
||||
},
|
||||
|
||||
watch: {
|
||||
visible(val) {
|
||||
this.broadcast('ElDropdownMenu', 'visible', val);
|
||||
this.$emit('visible-change', val);
|
||||
},
|
||||
focusing(val) {
|
||||
const selfDefine = this.$el.querySelector('.el-dropdown-selfdefine');
|
||||
if (selfDefine) { // 自定义
|
||||
if (val) {
|
||||
selfDefine.className += ' focusing';
|
||||
} else {
|
||||
selfDefine.className = selfDefine.className.replace('focusing', '');
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -100,6 +119,8 @@
|
||||
},
|
||||
hide() {
|
||||
if (this.triggerElm.disabled) return;
|
||||
this.removeTabindex();
|
||||
this.resetTabindex(this.triggerElm);
|
||||
clearTimeout(this.timeout);
|
||||
this.timeout = setTimeout(() => {
|
||||
this.visible = false;
|
||||
@@ -109,18 +130,98 @@
|
||||
if (this.triggerElm.disabled) return;
|
||||
this.visible = !this.visible;
|
||||
},
|
||||
handleTriggerKeyDown(ev) {
|
||||
const keyCode = ev.keyCode;
|
||||
if ([38, 40].includes(keyCode)) { // up/down
|
||||
this.removeTabindex();
|
||||
this.resetTabindex(this.menuItems[0]);
|
||||
this.menuItems[0].focus();
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
} else if (keyCode === 13) { // space enter选中
|
||||
this.handleClick();
|
||||
} else if ([9, 27].includes(keyCode)) { // tab || esc
|
||||
this.hide();
|
||||
}
|
||||
return;
|
||||
},
|
||||
handleItemKeyDown(ev) {
|
||||
const keyCode = ev.keyCode;
|
||||
const target = ev.target;
|
||||
const currentIndex = this.menuItemsArray.indexOf(target);
|
||||
const max = this.menuItemsArray.length - 1;
|
||||
let nextIndex;
|
||||
if ([38, 40].includes(keyCode)) { // up/down
|
||||
if (keyCode === 38) { // up
|
||||
nextIndex = currentIndex !== 0 ? currentIndex - 1 : 0;
|
||||
} else { // down
|
||||
nextIndex = currentIndex < max ? currentIndex + 1 : max;
|
||||
}
|
||||
this.removeTabindex();
|
||||
this.resetTabindex(this.menuItems[nextIndex]);
|
||||
this.menuItems[nextIndex].focus();
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
} else if (keyCode === 13) { // enter选中
|
||||
this.triggerElm.focus();
|
||||
target.click();
|
||||
if (!this.hideOnClick) { // click关闭
|
||||
this.visible = false;
|
||||
}
|
||||
} else if ([9, 27].includes(keyCode)) { // tab // esc
|
||||
this.hide();
|
||||
this.triggerElm.focus();
|
||||
}
|
||||
return;
|
||||
},
|
||||
resetTabindex(ele) { // 下次tab时组件聚焦元素
|
||||
this.removeTabindex();
|
||||
ele.setAttribute('tabindex', '0'); // 下次期望的聚焦元素
|
||||
},
|
||||
removeTabindex() {
|
||||
this.triggerElm.setAttribute('tabindex', '-1');
|
||||
this.menuItemsArray.forEach((item) => {
|
||||
item.setAttribute('tabindex', '-1');
|
||||
});
|
||||
},
|
||||
initAria() {
|
||||
this.dropdownElm.setAttribute('id', this.listId);
|
||||
this.triggerElm.setAttribute('aria-haspopup', 'list');
|
||||
this.triggerElm.setAttribute('aria-controls', this.listId);
|
||||
this.menuItems = this.dropdownElm.querySelectorAll("[tabindex='-1']");
|
||||
this.menuItemsArray = Array.prototype.slice.call(this.menuItems);
|
||||
|
||||
if (!this.splitButton) { // 自定义
|
||||
this.triggerElm.setAttribute('role', 'button');
|
||||
this.triggerElm.setAttribute('tabindex', '0');
|
||||
this.triggerElm.className += ' el-dropdown-selfdefine'; // 控制
|
||||
}
|
||||
},
|
||||
initEvent() {
|
||||
let { trigger, show, hide, handleClick, splitButton } = this;
|
||||
let { trigger, show, hide, handleClick, splitButton, handleTriggerKeyDown, handleItemKeyDown } = this;
|
||||
this.triggerElm = splitButton
|
||||
? this.$refs.trigger.$el
|
||||
: this.$slots.default[0].elm;
|
||||
|
||||
let dropdownElm = this.dropdownElm = this.$slots.dropdown[0].elm;
|
||||
|
||||
this.triggerElm.addEventListener('keydown', handleTriggerKeyDown); // triggerElm keydown
|
||||
dropdownElm.addEventListener('keydown', handleItemKeyDown, true); // item keydown
|
||||
// 控制自定义元素的样式
|
||||
if (!splitButton) {
|
||||
this.triggerElm.addEventListener('focus', () => {
|
||||
this.focusing = true;
|
||||
});
|
||||
this.triggerElm.addEventListener('blur', () => {
|
||||
this.focusing = false;
|
||||
});
|
||||
this.triggerElm.addEventListener('click', () => {
|
||||
this.focusing = false;
|
||||
});
|
||||
}
|
||||
if (trigger === 'hover') {
|
||||
this.triggerElm.addEventListener('mouseenter', show);
|
||||
this.triggerElm.addEventListener('mouseleave', hide);
|
||||
|
||||
let dropdownElm = this.$slots.dropdown[0].elm;
|
||||
|
||||
dropdownElm.addEventListener('mouseenter', show);
|
||||
dropdownElm.addEventListener('mouseleave', hide);
|
||||
} else if (trigger === 'click') {
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
required: true
|
||||
},
|
||||
route: {
|
||||
type: Object,
|
||||
type: [String, Object],
|
||||
required: false
|
||||
},
|
||||
disabled: {
|
||||
|
||||
@@ -157,14 +157,14 @@
|
||||
},
|
||||
getColorChannels(color) {
|
||||
color = color.replace('#', '');
|
||||
if (/^[1-9a-fA-F]{3}$/.test(color)) {
|
||||
if (/^[0-9a-fA-F]{3}$/.test(color)) {
|
||||
color = color.split('');
|
||||
for (let i = 2; i >= 0; i--) {
|
||||
color.splice(i, 0, color[i]);
|
||||
}
|
||||
color = color.join('');
|
||||
}
|
||||
if (/^[1-9a-fA-F]{6}$/.test(color)) {
|
||||
if (/^[0-9a-fA-F]{6}$/.test(color)) {
|
||||
return {
|
||||
red: parseInt(color.slice(0, 2), 16),
|
||||
green: parseInt(color.slice(2, 4), 16),
|
||||
@@ -207,6 +207,7 @@
|
||||
let openedMenus = this.openedMenus;
|
||||
if (openedMenus.indexOf(index) !== -1) return;
|
||||
// 将不在该菜单路径下的其余菜单收起
|
||||
// collapse all menu that are not under current menu item
|
||||
if (this.uniqueOpened) {
|
||||
this.openedMenus = openedMenus.filter(index => {
|
||||
return indexPath.indexOf(index) !== -1;
|
||||
@@ -246,6 +247,7 @@
|
||||
}
|
||||
},
|
||||
// 初始化展开菜单
|
||||
// initialize opened menu
|
||||
initOpenedMenu() {
|
||||
const index = this.activeIndex;
|
||||
const activeItem = this.items[index];
|
||||
@@ -254,6 +256,7 @@
|
||||
let indexPath = activeItem.indexPath;
|
||||
|
||||
// 展开该菜单项的路径上所有子菜单
|
||||
// expand all submenus of the menu item
|
||||
indexPath.forEach(index => {
|
||||
let submenu = this.submenus[index];
|
||||
submenu && this.openMenu(index, submenu.indexPath);
|
||||
|
||||
@@ -173,11 +173,13 @@
|
||||
},
|
||||
handleTitleMouseenter() {
|
||||
if (this.mode === 'horizontal' && !this.rootMenu.backgroundColor) return;
|
||||
this.$refs['submenu-title'].style.backgroundColor = this.rootMenu.hoverBackground;
|
||||
const title = this.$refs['submenu-title'];
|
||||
title && (title.style.backgroundColor = this.rootMenu.hoverBackground);
|
||||
},
|
||||
handleTitleMouseleave() {
|
||||
if (this.mode === 'horizontal' && !this.rootMenu.backgroundColor) return;
|
||||
this.$refs['submenu-title'].style.backgroundColor = this.rootMenu.backgroundColor || '';
|
||||
const title = this.$refs['submenu-title'];
|
||||
title && (title.style.backgroundColor = this.rootMenu.backgroundColor || '');
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
||||
@@ -9,15 +9,15 @@
|
||||
v-show="visible"
|
||||
@mouseenter="clearTimer"
|
||||
@mouseleave="startTimer"
|
||||
role="alertdialog"
|
||||
role="alert"
|
||||
>
|
||||
<i :class="iconClass" v-if="iconClass"></i>
|
||||
<i :class="typeClass" v-else></i>
|
||||
<slot>
|
||||
<p v-if="!dangerouslyUseHTMLString" class="el-message__content" tabindex="0">{{ message }}</p>
|
||||
<p v-else v-html="message" class="el-message__content" tabindex="0"></p>
|
||||
<p v-if="!dangerouslyUseHTMLString" class="el-message__content">{{ message }}</p>
|
||||
<p v-else v-html="message" class="el-message__content"></p>
|
||||
</slot>
|
||||
<i v-if="showClose" class="el-message__closeBtn el-icon-close" @click="close" tabindex="0" role="button" aria-label="close" @keydown.enter.stop="close"></i>
|
||||
<i v-if="showClose" class="el-message__closeBtn el-icon-close" @click="close"></i>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
@@ -44,9 +44,7 @@
|
||||
closed: false,
|
||||
timer: null,
|
||||
dangerouslyUseHTMLString: false,
|
||||
center: false,
|
||||
initFocus: null,
|
||||
originFocus: null
|
||||
center: false
|
||||
};
|
||||
},
|
||||
|
||||
@@ -87,18 +85,6 @@
|
||||
if (typeof this.onClose === 'function') {
|
||||
this.onClose(this);
|
||||
}
|
||||
if (!this.originFocus || !this.originFocus.getBoundingClientRect) return;
|
||||
|
||||
// restore keyboard focus
|
||||
const { top, left, bottom, right } = this.originFocus.getBoundingClientRect();
|
||||
const viewportHeight = window.innerHeight || document.documentElement.clientHeight;
|
||||
const viewportWidth = window.innerWidth || document.documentElement.clientWidth;
|
||||
if (top >= 0 &&
|
||||
left >= 0 &&
|
||||
bottom <= viewportHeight &&
|
||||
right <= viewportWidth) {
|
||||
this.originFocus.focus();
|
||||
}
|
||||
},
|
||||
|
||||
clearTimer() {
|
||||
@@ -115,24 +101,15 @@
|
||||
}
|
||||
},
|
||||
keydown(e) {
|
||||
if (e.keyCode === 46 || e.keyCode === 8) {
|
||||
this.clearTimer(); // detele 取消倒计时
|
||||
} else if (e.keyCode === 27) { // esc关闭消息
|
||||
if (e.keyCode === 27) { // esc关闭消息
|
||||
if (!this.closed) {
|
||||
this.close();
|
||||
}
|
||||
} else {
|
||||
this.startTimer(); // 恢复倒计时
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.startTimer();
|
||||
this.originFocus = document.activeElement;
|
||||
this.initFocus = this.showClose ? this.$el.querySelector('.el-icon-close') : this.$el.querySelector('.el-message__content');
|
||||
setTimeout(() => {
|
||||
this.initFocus && this.initFocus.focus();
|
||||
});
|
||||
document.addEventListener('keydown', this.keydown);
|
||||
},
|
||||
beforeDestroy() {
|
||||
|
||||
@@ -6,7 +6,9 @@
|
||||
:style="positionStyle"
|
||||
@mouseenter="clearTimer()"
|
||||
@mouseleave="startTimer()"
|
||||
@click="click">
|
||||
@click="click"
|
||||
role="alert"
|
||||
>
|
||||
<i
|
||||
class="el-notification__icon"
|
||||
:class="[ typeClass, iconClass ]"
|
||||
@@ -119,9 +121,19 @@
|
||||
}
|
||||
}, this.duration);
|
||||
}
|
||||
},
|
||||
keydown(e) {
|
||||
if (e.keyCode === 46 || e.keyCode === 8) {
|
||||
this.clearTimer(); // detele 取消倒计时
|
||||
} else if (e.keyCode === 27) { // esc关闭消息
|
||||
if (!this.closed) {
|
||||
this.close();
|
||||
}
|
||||
} else {
|
||||
this.startTimer(); // 恢复倒计时
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
if (this.duration > 0) {
|
||||
this.timer = setTimeout(() => {
|
||||
@@ -130,6 +142,11 @@
|
||||
}
|
||||
}, this.duration);
|
||||
}
|
||||
document.addEventListener('keydown', this.keydown);
|
||||
},
|
||||
beforeDestroy() {
|
||||
document.removeEventListener('keydown', this.keydown);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
@@ -6,7 +6,11 @@
|
||||
:class="[popperClass, content && 'el-popover--plain']"
|
||||
ref="popper"
|
||||
v-show="!disabled && showPopper"
|
||||
:style="{ width: width + 'px' }">
|
||||
:style="{ width: width + 'px' }"
|
||||
role="tooltip"
|
||||
:id="tooltipId"
|
||||
:aria-hidden="(disabled || !showPopper) ? 'true' : 'false'"
|
||||
>
|
||||
<div class="el-popover__title" v-if="title" v-text="title"></div>
|
||||
<slot>{{ content }}</slot>
|
||||
</div>
|
||||
@@ -14,10 +18,10 @@
|
||||
<slot name="reference"></slot>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Popper from 'element-ui/src/utils/vue-popper';
|
||||
import { on, off } from 'element-ui/src/utils/dom';
|
||||
import { generateId } from 'element-ui/src/utils/util';
|
||||
|
||||
export default {
|
||||
name: 'ElPopover',
|
||||
@@ -49,6 +53,11 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
tooltipId() {
|
||||
return `el-popover-${generateId()}`;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
showPopper(newVal, oldVal) {
|
||||
newVal ? this.$emit('show') : this.$emit('hide');
|
||||
@@ -62,12 +71,23 @@ export default {
|
||||
},
|
||||
|
||||
mounted() {
|
||||
let reference = this.reference || this.$refs.reference;
|
||||
let reference = this.referenceElm = this.reference || this.$refs.reference;
|
||||
const popper = this.popper || this.$refs.popper;
|
||||
|
||||
if (!reference && this.$slots.reference && this.$slots.reference[0]) {
|
||||
reference = this.referenceElm = this.$slots.reference[0].elm;
|
||||
}
|
||||
// 可访问性
|
||||
if (reference) {
|
||||
reference.className += ' el-tooltip';
|
||||
reference.setAttribute('aria-describedby', this.tooltipId);
|
||||
reference.setAttribute('tabindex', 0); // tab序列
|
||||
|
||||
on(reference, 'focus', this.handleFocus);
|
||||
on(reference, 'blur', this.handleBlur);
|
||||
on(reference, 'keydown', this.handleKeydown);
|
||||
on(reference, 'click', this.handleClick);
|
||||
}
|
||||
if (this.trigger === 'click') {
|
||||
on(reference, 'click', this.doToggle);
|
||||
on(document, 'click', this.handleDocumentClick);
|
||||
@@ -114,6 +134,20 @@ export default {
|
||||
doClose() {
|
||||
this.showPopper = false;
|
||||
},
|
||||
handleFocus() {
|
||||
const reference = this.referenceElm;
|
||||
reference.className += ' focusing';
|
||||
this.showPopper = true;
|
||||
},
|
||||
handleClick() {
|
||||
const reference = this.referenceElm;
|
||||
reference.className = reference.className.replace(/\s*focusing\s*/, ' ');
|
||||
},
|
||||
handleBlur() {
|
||||
const reference = this.referenceElm;
|
||||
reference.className = reference.className.replace(/\s*focusing\s*/, ' ');
|
||||
this.showPopper = false;
|
||||
},
|
||||
handleMouseEnter() {
|
||||
clearTimeout(this._timer);
|
||||
if (this.openDelay) {
|
||||
@@ -124,6 +158,11 @@ export default {
|
||||
this.showPopper = true;
|
||||
}
|
||||
},
|
||||
handleKeydown(ev) {
|
||||
if (ev.keyCode === 27) { // esc
|
||||
this.doClose();
|
||||
}
|
||||
},
|
||||
handleMouseLeave() {
|
||||
clearTimeout(this._timer);
|
||||
this._timer = setTimeout(() => {
|
||||
|
||||
@@ -53,9 +53,10 @@
|
||||
},
|
||||
mounted() {
|
||||
// 当radioGroup没有默认选项时,第一个可以选中Tab导航
|
||||
let radios = this.$el.querySelectorAll('[type=radio]');
|
||||
if (![].some.call(radios, radio => radio.checked)) {
|
||||
this.$el.querySelectorAll('[role=radio]')[0].tabIndex = 0;
|
||||
const radios = this.$el.querySelectorAll('[type=radio]');
|
||||
const firstLabel = this.$el.querySelectorAll('[role=radio]')[0];
|
||||
if (![].some.call(radios, radio => radio.checked) && firstLabel) {
|
||||
firstLabel.tabIndex = 0;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "element-theme-chalk",
|
||||
"version": "2.0.3",
|
||||
"version": "2.0.4",
|
||||
"description": "Element component chalk theme.",
|
||||
"main": "lib/index.css",
|
||||
"style": "lib/index.css",
|
||||
@@ -28,7 +28,8 @@
|
||||
"devDependencies": {
|
||||
"gulp": "^3.9.1",
|
||||
"gulp-cssmin": "^0.1.7",
|
||||
"gulp-sass": "^3.1.0"
|
||||
"gulp-sass": "^3.1.0",
|
||||
"gulp-autoprefixer": "^4.0.0"
|
||||
},
|
||||
"dependencies": {}
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@
|
||||
line-height: 1.5;
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
|
||||
outline: none;
|
||||
@include m(extensible) {
|
||||
&:after {
|
||||
font-family: 'element-icons';
|
||||
@@ -154,7 +154,7 @@
|
||||
color: $--select-option-selected;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
&:hover, &:focus:not(:active) {
|
||||
background-color: $--select-option-hover-background;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
padding: $--checkbox-bordered-padding;
|
||||
border-radius: $--border-radius-base;
|
||||
border: $--border-base;
|
||||
box-sizing: border-box;
|
||||
line-height: normal;
|
||||
height: $--checkbox-bordered-height;
|
||||
|
||||
&.is-checked {
|
||||
border-color: $--color-primary;
|
||||
@@ -34,6 +37,7 @@
|
||||
&.el-checkbox--medium {
|
||||
padding: $--checkbox-bordered-medium-padding;
|
||||
border-radius: $--button-medium-border-radius;
|
||||
height: $--checkbox-bordered-medium-height;
|
||||
|
||||
.el-checkbox__label {
|
||||
line-height: 17px;
|
||||
@@ -49,6 +53,7 @@
|
||||
&.el-checkbox--small {
|
||||
padding: $--checkbox-bordered-small-padding;
|
||||
border-radius: $--button-small-border-radius;
|
||||
height: $--checkbox-bordered-small-height;
|
||||
|
||||
.el-checkbox__label {
|
||||
line-height: 15px;
|
||||
@@ -69,6 +74,7 @@
|
||||
&.el-checkbox--mini {
|
||||
padding: $--checkbox-bordered-mini-padding;
|
||||
border-radius: $--button-mini-border-radius;
|
||||
height: $--checkbox-bordered-mini-height;
|
||||
|
||||
.el-checkbox__label {
|
||||
line-height: 12px;
|
||||
|
||||
@@ -137,16 +137,20 @@ $--checkbox-checked-icon-color: $--fill-base !default;
|
||||
|
||||
$--checkbox-input-border-color-hover: $--color-primary !default;
|
||||
|
||||
$--checkbox-bordered-height: 40px !default;
|
||||
$--checkbox-bordered-padding: 9px 20px 9px 10px !default;
|
||||
$--checkbox-bordered-medium-padding: 7px 20px 7px 10px !default;
|
||||
$--checkbox-bordered-small-padding: 3px 15px 7px 10px !default;
|
||||
$--checkbox-bordered-mini-padding: 1px 15px 5px 10px !default;
|
||||
$--checkbox-bordered-small-padding: 5px 15px 5px 10px !default;
|
||||
$--checkbox-bordered-mini-padding: 3px 15px 3px 10px !default;
|
||||
$--checkbox-bordered-medium-input-height: 14px !default;
|
||||
$--checkbox-bordered-medium-input-width: 14px !default;
|
||||
$--checkbox-bordered-medium-height: 36px !default;
|
||||
$--checkbox-bordered-small-input-height: 12px !default;
|
||||
$--checkbox-bordered-small-input-width: 12px !default;
|
||||
$--checkbox-bordered-small-height: 32px !default;
|
||||
$--checkbox-bordered-mini-input-height: 12px !default;
|
||||
$--checkbox-bordered-mini-input-width: 12px !default;
|
||||
$--checkbox-bordered-mini-height: 28px !default;
|
||||
|
||||
$--checkbox-button-font-size: $--font-size-base !default;
|
||||
$--checkbox-button-checked-fill: $--color-primary !default;
|
||||
@@ -183,16 +187,20 @@ $--radio-checked-icon-color: $--color-primary !default;
|
||||
|
||||
$--radio-input-border-color-hover: $--color-primary !default;
|
||||
|
||||
$--radio-bordered-padding: 10px 20px 10px 10px !default;
|
||||
$--radio-bordered-medium-padding: 8px 20px 8px 10px !default;
|
||||
$--radio-bordered-small-padding: 6px 15px 6px 10px !default;
|
||||
$--radio-bordered-mini-padding: 4px 15px 4px 10px !default;
|
||||
$--radio-bordered-height: 40px !default;
|
||||
$--radio-bordered-padding: 12px 20px 0 10px !default;
|
||||
$--radio-bordered-medium-padding: 10px 20px 0 10px !default;
|
||||
$--radio-bordered-small-padding: 8px 15px 0 10px !default;
|
||||
$--radio-bordered-mini-padding: 6px 15px 0 10px !default;
|
||||
$--radio-bordered-medium-input-height: 14px !default;
|
||||
$--radio-bordered-medium-input-width: 14px !default;
|
||||
$--radio-bordered-medium-height: 36px !default;
|
||||
$--radio-bordered-small-input-height: 12px !default;
|
||||
$--radio-bordered-small-input-width: 12px !default;
|
||||
$--radio-bordered-small-height: 32px !default;
|
||||
$--radio-bordered-mini-input-height: 12px !default;
|
||||
$--radio-bordered-mini-input-width: 12px !default;
|
||||
$--radio-bordered-mini-height: 28px !default;
|
||||
|
||||
$--radio-button-font-size: $--font-size-base !default;
|
||||
$--radio-button-checked-fill: $--color-primary !default;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
flex-direction: row;
|
||||
flex: 1;
|
||||
box-sizing: border-box;
|
||||
min-width: 0;
|
||||
|
||||
@include when(vertical) {
|
||||
flex-direction: column;
|
||||
|
||||
@@ -50,6 +50,12 @@
|
||||
font-size: 12px;
|
||||
margin: 0 3px;
|
||||
}
|
||||
|
||||
.el-dropdown-selfdefine { // 自定义
|
||||
&:focus:active, &:focus:not(.focusing) {
|
||||
outline-width: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include b(dropdown-menu) {
|
||||
@@ -72,8 +78,8 @@
|
||||
font-size: $--font-size-base;
|
||||
color: $--color-text-regular;
|
||||
cursor: pointer;
|
||||
|
||||
&:not(.is-disabled):hover {
|
||||
outline: none;
|
||||
&:not(.is-disabled):hover, &:focus {
|
||||
background-color: $--dropdown-menuItem-hover-fill;
|
||||
color: $--dropdown-menuItem-hover-color;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
.el-input__inner {
|
||||
text-align: center;
|
||||
-moz-appearance: textfield;
|
||||
}
|
||||
|
||||
// pagesize 的下拉 icon
|
||||
@@ -35,9 +36,6 @@
|
||||
width: 100px;
|
||||
margin: 0 5px;
|
||||
|
||||
.el-input__icon {
|
||||
}
|
||||
|
||||
.el-input__inner {
|
||||
padding-right: 25px;
|
||||
border-radius: $--pagination-border-radius;
|
||||
@@ -149,7 +147,6 @@
|
||||
margin: 0 2px;
|
||||
box-sizing: border-box;
|
||||
border-radius: $--pagination-border-radius;
|
||||
-moz-appearance: textfield;
|
||||
|
||||
&.el-input {
|
||||
width: 50px;
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
padding: $--radio-bordered-padding;
|
||||
border-radius: $--border-radius-base;
|
||||
border: $--border-base;
|
||||
box-sizing: border-box;
|
||||
height: $--radio-bordered-height;
|
||||
|
||||
&.is-checked {
|
||||
border-color: $--color-primary;
|
||||
@@ -38,6 +40,7 @@
|
||||
&.is-bordered {
|
||||
padding: $--radio-bordered-medium-padding;
|
||||
border-radius: $--button-medium-border-radius;
|
||||
height: $--radio-bordered-medium-height;
|
||||
.el-radio__label {
|
||||
font-size: $--button-medium-font-size;
|
||||
}
|
||||
@@ -51,6 +54,7 @@
|
||||
&.is-bordered {
|
||||
padding: $--radio-bordered-small-padding;
|
||||
border-radius: $--button-small-border-radius;
|
||||
height: $--radio-bordered-small-height;
|
||||
.el-radio__label {
|
||||
font-size: $--button-small-font-size;
|
||||
}
|
||||
@@ -64,6 +68,7 @@
|
||||
&.is-bordered {
|
||||
padding: $--radio-bordered-mini-padding;
|
||||
border-radius: $--button-mini-border-radius;
|
||||
height: $--radio-bordered-mini-height;
|
||||
.el-radio__label {
|
||||
font-size: $--button-mini-font-size;
|
||||
}
|
||||
|
||||
@@ -140,12 +140,12 @@
|
||||
@include when(vertical) {
|
||||
position: relative;
|
||||
.el-slider__runway {
|
||||
width: 4px;
|
||||
width: $--slider-height;
|
||||
height: 100%;
|
||||
margin: 0 16px;
|
||||
}
|
||||
.el-slider__bar {
|
||||
width: 4px;
|
||||
width: $--slider-height;
|
||||
height: auto;
|
||||
border-radius: 0 0 3px 3px;
|
||||
}
|
||||
|
||||
@@ -229,9 +229,11 @@
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
&.el-tabs--border-card .el-tabs__item:nth-child(2),
|
||||
&.el-tabs--card .el-tabs__item:nth-child(2) {
|
||||
padding-left: 20px;
|
||||
&.el-tabs--border-card, &.el-tabs--card,
|
||||
.el-tabs--left, .el-tabs--right {
|
||||
.el-tabs__item:nth-child(2) {
|
||||
padding-left: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@include m(bottom) {
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
@import "common/var";
|
||||
|
||||
@include b(tooltip) {
|
||||
&:focus:not(.focusing), &:focus:hover {
|
||||
outline-width: 0;
|
||||
}
|
||||
@include e(popper) {
|
||||
position: absolute;
|
||||
border-radius: 4px;
|
||||
|
||||
@@ -25,7 +25,12 @@
|
||||
|
||||
@include b(tree-node) {
|
||||
white-space: nowrap;
|
||||
|
||||
outline: none;
|
||||
&:focus { /* focus */
|
||||
> .el-tree-node__content {
|
||||
background-color: $--tree-node-hover-color;
|
||||
}
|
||||
}
|
||||
@include e(content) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import Popper from 'element-ui/src/utils/vue-popper';
|
||||
import debounce from 'throttle-debounce/debounce';
|
||||
import { getFirstComponentChild } from 'element-ui/src/utils/vdom';
|
||||
import { generateId } from 'element-ui/src/utils/util';
|
||||
import Vue from 'vue';
|
||||
|
||||
export default {
|
||||
@@ -48,10 +49,15 @@ export default {
|
||||
|
||||
data() {
|
||||
return {
|
||||
timeoutPending: null
|
||||
timeoutPending: null,
|
||||
focusing: false
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
tooltipId() {
|
||||
return `el-tooltip-${generateId()}`;
|
||||
}
|
||||
},
|
||||
beforeCreate() {
|
||||
if (this.$isServer) return;
|
||||
|
||||
@@ -75,6 +81,9 @@ export default {
|
||||
onMouseleave={ () => { this.setExpectedState(false); this.debounceClose(); } }
|
||||
onMouseenter= { () => { this.setExpectedState(true); } }
|
||||
ref="popper"
|
||||
role="tooltip"
|
||||
id={this.tooltipId}
|
||||
aria-hidden={ (this.disabled || !this.showPopper) ? 'true' : 'false' }
|
||||
v-show={!this.disabled && this.showPopper}
|
||||
class={
|
||||
['el-tooltip__popper', 'is-' + this.effect, this.popperClass]
|
||||
@@ -87,24 +96,38 @@ export default {
|
||||
if (!this.$slots.default || !this.$slots.default.length) return this.$slots.default;
|
||||
|
||||
const vnode = getFirstComponentChild(this.$slots.default);
|
||||
|
||||
if (!vnode) return vnode;
|
||||
|
||||
const data = vnode.data = vnode.data || {};
|
||||
const on = vnode.data.on = vnode.data.on || {};
|
||||
const nativeOn = vnode.data.nativeOn = vnode.data.nativeOn || {};
|
||||
|
||||
data.staticClass = this.concatClass(data.staticClass, 'el-tooltip');
|
||||
on.mouseenter = this.addEventHandle(on.mouseenter, this.show);
|
||||
on.mouseleave = this.addEventHandle(on.mouseleave, this.hide);
|
||||
nativeOn.mouseenter = this.addEventHandle(nativeOn.mouseenter, this.show);
|
||||
nativeOn.mouseleave = this.addEventHandle(nativeOn.mouseleave, this.hide);
|
||||
|
||||
nativeOn.mouseenter = on.mouseenter = this.addEventHandle(on.mouseenter, this.show);
|
||||
nativeOn.mouseleave = on.mouseleave = this.addEventHandle(on.mouseleave, this.hide);
|
||||
nativeOn.focus = on.focus = this.addEventHandle(on.focus, this.handleFocus);
|
||||
nativeOn.blur = on.blur = this.addEventHandle(on.blur, this.handleBlur);
|
||||
nativeOn.click = on.click = this.addEventHandle(on.click, () => { this.focusing = false; });
|
||||
return vnode;
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.referenceElm = this.$el;
|
||||
if (this.$el.nodeType === 1) {
|
||||
this.$el.setAttribute('aria-describedby', this.tooltipId);
|
||||
this.$el.setAttribute('tabindex', 0);
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
focusing(val) {
|
||||
if (val) {
|
||||
this.referenceElm.className += ' focusing';
|
||||
} else {
|
||||
this.referenceElm.className = this.referenceElm.className.replace('focusing', '');
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
show() {
|
||||
this.setExpectedState(true);
|
||||
@@ -115,7 +138,14 @@ export default {
|
||||
this.setExpectedState(false);
|
||||
this.debounceClose();
|
||||
},
|
||||
|
||||
handleFocus() {
|
||||
this.focusing = true;
|
||||
this.show();
|
||||
},
|
||||
handleBlur() {
|
||||
this.focusing = false;
|
||||
this.hide();
|
||||
},
|
||||
addEventHandle(old, fn) {
|
||||
if (!old) {
|
||||
return fn;
|
||||
|
||||
@@ -198,9 +198,10 @@ export default class TreeStore {
|
||||
const node = this.nodesMap[key];
|
||||
if (!node) return;
|
||||
const childNodes = node.childNodes;
|
||||
childNodes.forEach(child => {
|
||||
for (let i = childNodes.length - 1; i >= 0; i--) {
|
||||
const child = childNodes[i];
|
||||
this.remove(child.data);
|
||||
});
|
||||
}
|
||||
for (let i = 0, j = data.length; i < j; i++) {
|
||||
const child = data[i];
|
||||
this.append(child, node.data);
|
||||
|
||||
@@ -1,12 +1,21 @@
|
||||
<template>
|
||||
<div class="el-tree-node"
|
||||
<div
|
||||
class="el-tree-node"
|
||||
@click.stop="handleClick"
|
||||
v-show="node.visible"
|
||||
:class="{
|
||||
'is-expanded': expanded,
|
||||
'is-current': tree.store.currentNode === node,
|
||||
'is-hidden': !node.visible
|
||||
}">
|
||||
'is-hidden': !node.visible,
|
||||
'is-focusable': !node.disabled,
|
||||
'is-checked': !node.disabled && node.checked
|
||||
}"
|
||||
role="treeitem"
|
||||
tabindex="-1"
|
||||
:aria-expanded="expanded"
|
||||
:aria-disabled="node.disabled"
|
||||
:aria-checked="node.checked"
|
||||
>
|
||||
<div class="el-tree-node__content"
|
||||
:style="{ 'padding-left': (node.level - 1) * tree.indent + 'px' }">
|
||||
<span
|
||||
@@ -20,7 +29,8 @@
|
||||
:indeterminate="node.indeterminate"
|
||||
:disabled="!!node.disabled"
|
||||
@click.native.stop
|
||||
@change="handleCheckChange">
|
||||
@change="handleCheckChange"
|
||||
>
|
||||
</el-checkbox>
|
||||
<span
|
||||
v-if="node.loading"
|
||||
@@ -32,7 +42,10 @@
|
||||
<div
|
||||
class="el-tree-node__children"
|
||||
v-if="childNodeRendered"
|
||||
v-show="expanded">
|
||||
v-show="expanded"
|
||||
role="group"
|
||||
:aria-expanded="expanded"
|
||||
>
|
||||
<el-tree-node
|
||||
:render-content="renderContent"
|
||||
v-for="child in node.childNodes"
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
<template>
|
||||
<div class="el-tree" :class="{ 'el-tree--highlight-current': highlightCurrent }">
|
||||
<div
|
||||
class="el-tree"
|
||||
:class="{ 'el-tree--highlight-current': highlightCurrent }"
|
||||
role="tree"
|
||||
>
|
||||
<el-tree-node
|
||||
v-for="child in root.childNodes"
|
||||
:node="child"
|
||||
@@ -33,7 +37,9 @@
|
||||
return {
|
||||
store: null,
|
||||
root: null,
|
||||
currentNode: null
|
||||
currentNode: null,
|
||||
treeItems: null,
|
||||
checkboxItems: []
|
||||
};
|
||||
},
|
||||
|
||||
@@ -101,6 +107,9 @@
|
||||
get() {
|
||||
return this.data;
|
||||
}
|
||||
},
|
||||
treeItemArray() {
|
||||
return Array.prototype.slice.call(this.treeItems);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -115,6 +124,11 @@
|
||||
},
|
||||
data(newVal) {
|
||||
this.store.setData(newVal);
|
||||
},
|
||||
checkboxItems(val) {
|
||||
Array.prototype.forEach.call(val, (checkbox) => {
|
||||
checkbox.setAttribute('tabindex', -1);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@@ -171,6 +185,42 @@
|
||||
updateKeyChildren(key, data) {
|
||||
if (!this.nodeKey) throw new Error('[Tree] nodeKey is required in updateKeyChild');
|
||||
this.store.updateChildren(key, data);
|
||||
},
|
||||
initTabindex() {
|
||||
this.treeItems = this.$el.querySelectorAll('.is-focusable[role=treeitem]');
|
||||
this.checkboxItems = this.$el.querySelectorAll('input[type=checkbox]');
|
||||
const checkedItem = this.$el.querySelectorAll('.is-checked[role=treeitem]');
|
||||
if (checkedItem.length) {
|
||||
checkedItem[0].setAttribute('tabindex', 0);
|
||||
return;
|
||||
}
|
||||
this.treeItems[0].setAttribute('tabindex', 0);
|
||||
},
|
||||
handelKeydown(ev) {
|
||||
const currentItem = ev.target;
|
||||
const keyCode = ev.keyCode;
|
||||
this.treeItems = this.$el.querySelectorAll('.is-focusable[role=treeitem]');
|
||||
const currentIndex = this.treeItemArray.indexOf(currentItem);
|
||||
let nextIndex;
|
||||
if ([38, 40].includes(keyCode)) { // up、down
|
||||
if (keyCode === 38) { // up
|
||||
nextIndex = currentIndex !== 0 ? currentIndex - 1 : 0;
|
||||
} else {
|
||||
nextIndex = (currentIndex < this.treeItemArray.length - 1) ? currentIndex + 1 : 0;
|
||||
}
|
||||
this.treeItemArray[nextIndex].focus(); // 选中
|
||||
}
|
||||
const hasInput = currentItem.querySelector('[type="checkbox"]');
|
||||
if ([37, 39].includes(keyCode)) { // left、right 展开
|
||||
currentItem.click(); // 选中
|
||||
}
|
||||
if ([13, 32].includes(keyCode)) { // space enter选中checkbox
|
||||
if (hasInput) {
|
||||
hasInput.click();
|
||||
}
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -194,6 +244,14 @@
|
||||
});
|
||||
|
||||
this.root = this.store.root;
|
||||
},
|
||||
mounted() {
|
||||
this.initTabindex();
|
||||
this.$el.addEventListener('keydown', this.handelKeydown);
|
||||
},
|
||||
updated() {
|
||||
this.treeItems = this.$el.querySelectorAll('[role=treeitem]');
|
||||
this.checkboxItems = this.$el.querySelectorAll('input[type=checkbox]');
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
function getError(action, option, xhr) {
|
||||
let msg;
|
||||
if (xhr.response) {
|
||||
msg = `${xhr.status} ${xhr.response.error || xhr.response}`;
|
||||
msg = `${xhr.response.error || xhr.response}`;
|
||||
} else if (xhr.responseText) {
|
||||
msg = `${xhr.status} ${xhr.responseText}`;
|
||||
msg = `${xhr.responseText}`;
|
||||
} else {
|
||||
msg = `fail to post ${action} ${xhr.status}`;
|
||||
}
|
||||
|
||||
@@ -173,7 +173,7 @@ if (typeof window !== 'undefined' && window.Vue) {
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
version: '2.0.3',
|
||||
version: '2.0.4',
|
||||
locale: locale.use,
|
||||
i18n: locale.i18n,
|
||||
install,
|
||||
|
||||
@@ -16,11 +16,11 @@ export default {
|
||||
startTime: 'Horaire début',
|
||||
endDate: 'Date fin',
|
||||
endTime: 'Horaire fin',
|
||||
prevYear: 'Previous Year', // to be translated
|
||||
nextYear: 'Next Year', // to be translated
|
||||
prevMonth: 'Previous Month', // to be translated
|
||||
nextMonth: 'Next Month', // to be translated
|
||||
year: '',
|
||||
prevYear: 'Année précédente',
|
||||
nextYear: 'Année suivante',
|
||||
prevMonth: 'Mois précédent',
|
||||
nextMonth: 'Mois suivant',
|
||||
year: 'Année',
|
||||
month1: 'Janvier',
|
||||
month2: 'Février',
|
||||
month3: 'Mars',
|
||||
@@ -81,7 +81,7 @@ export default {
|
||||
error: 'Erreur'
|
||||
},
|
||||
upload: {
|
||||
deleteTip: 'press delete to remove', // to be translated
|
||||
deleteTip: 'Cliquer sur supprimer pour retirer le fichier',
|
||||
delete: 'Supprimer',
|
||||
preview: 'Aperçu',
|
||||
continue: 'Continuer'
|
||||
@@ -91,7 +91,7 @@ export default {
|
||||
confirmFilter: 'Confirmer',
|
||||
resetFilter: 'Réinitialiser',
|
||||
clearFilter: 'Tous',
|
||||
sumText: 'Sum' // to be translated
|
||||
sumText: 'Somme'
|
||||
},
|
||||
tree: {
|
||||
emptyText: 'Aucune donnée'
|
||||
@@ -99,10 +99,10 @@ export default {
|
||||
transfer: {
|
||||
noMatch: 'Aucune correspondance',
|
||||
noData: 'Aucune donnée',
|
||||
titles: ['List 1', 'List 2'], // to be translated
|
||||
filterPlaceholder: 'Enter keyword', // to be translated
|
||||
noCheckedFormat: '{total} items', // to be translated
|
||||
hasCheckedFormat: '{checked}/{total} checked' // to be translated
|
||||
titles: ['Liste 1', 'Liste 2'],
|
||||
filterPlaceholder: 'Entrer un mot clef',
|
||||
noCheckedFormat: '{total} elements',
|
||||
hasCheckedFormat: '{checked}/{total} coché(s)'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -16,10 +16,10 @@ export default {
|
||||
startTime: 'Время начала',
|
||||
endDate: 'Дата окончания',
|
||||
endTime: 'Время окончания',
|
||||
prevYear: 'Previous Year', // to be translated
|
||||
nextYear: 'Next Year', // to be translated
|
||||
prevMonth: 'Previous Month', // to be translated
|
||||
nextMonth: 'Next Month', // to be translated
|
||||
prevYear: 'Предыдущий год',
|
||||
nextYear: 'Следующий год',
|
||||
prevMonth: 'Предыдущий месяц',
|
||||
nextMonth: 'Следующий месяц',
|
||||
year: '',
|
||||
month1: 'Январь',
|
||||
month2: 'Февраль',
|
||||
@@ -82,7 +82,7 @@ export default {
|
||||
error: 'Недопустимый ввод данных'
|
||||
},
|
||||
upload: {
|
||||
deleteTip: 'press delete to remove', // to be translated
|
||||
deleteTip: 'Нажмите [Удалить] для удаления',
|
||||
delete: 'Удалить',
|
||||
preview: 'Превью',
|
||||
continue: 'Продолжить'
|
||||
|
||||
@@ -82,7 +82,7 @@ export default {
|
||||
error: '输入的数据不合法!'
|
||||
},
|
||||
upload: {
|
||||
deleteTip: '按delete键可删除',
|
||||
deleteTip: '按 delete 键可删除',
|
||||
delete: '删除',
|
||||
preview: '查看图片',
|
||||
continue: '继续上传'
|
||||
|
||||
@@ -82,7 +82,7 @@ export default {
|
||||
error: '輸入的資料不符規定!'
|
||||
},
|
||||
upload: {
|
||||
deleteTip: '按delete鍵可刪除',
|
||||
deleteTip: '按 delete 鍵可刪除',
|
||||
delete: '刪除',
|
||||
preview: '查看圖片',
|
||||
continue: '繼續上傳'
|
||||
|
||||
@@ -41,7 +41,7 @@ describe('ajax', () => {
|
||||
});
|
||||
it('40x code should be error', done => {
|
||||
option.onError = e => {
|
||||
expect(e.toString()).to.contain('404 Not found');
|
||||
expect(e.toString()).to.contain('Not found');
|
||||
done();
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user