Merge remote-tracking branch 'upstream/2.0' into 2.0

This commit is contained in:
yison 2019-04-03 15:56:08 +08:00
commit b0297c8d5a
179 changed files with 3943 additions and 2394 deletions

View file

@ -80,6 +80,9 @@
// window.addEventListener('resize', this.handleScroll, false);
on(window, 'scroll', this.handleScroll);
on(window, 'resize', this.handleScroll);
this.$nextTick(() => {
this.handleScroll();
});
},
beforeDestroy () {
// window.removeEventListener('scroll', this.handleScroll, false);

View file

@ -166,6 +166,7 @@
if (!this.clearable) return;
this.currentValue = '';
this.$refs.select.reset();
this.$emit('on-clear');
}
}
};

View file

@ -1,6 +1,6 @@
<template>
<span :class="classes">
<img :src="src" v-if="src">
<img :src="src" v-if="src" @error="handleError">
<Icon :type="icon" :custom="customIcon" v-else-if="icon || customIcon"></Icon>
<span ref="children" :class="[prefixCls + '-string']" :style="childrenStyle" v-else><slot></slot></span>
</span>
@ -89,6 +89,9 @@
this.scale = 1;
}
}
},
handleError (e) {
this.$emit('on-error', e);
}
},
mounted () {

View file

@ -82,7 +82,7 @@
import {directive as clickOutside} from 'v-click-outside-x';
import TransferDom from '../../directives/transfer-dom';
import { oneOf } from '../../utils/assist';
import { DEFAULT_FORMATS, RANGE_SEPARATOR, TYPE_VALUE_RESOLVER_MAP, getDayCountOfMonth } from './util';
import { DEFAULT_FORMATS, TYPE_VALUE_RESOLVER_MAP, getDayCountOfMonth } from './util';
import {findComponentsDownward} from '../../utils/assist';
import Emitter from '../../mixins/emitter';
@ -209,6 +209,10 @@
options: {
type: Object,
default: () => ({})
},
separator: {
type: String,
default: ' - '
}
},
data(){
@ -607,23 +611,23 @@
const multipleParser = TYPE_VALUE_RESOLVER_MAP['multiple'].parser;
if (val && type === 'time' && !(val instanceof Date)) {
val = parser(val, format);
val = parser(val, format, this.separator);
} else if (this.multiple && val) {
val = multipleParser(val, format);
val = multipleParser(val, format, this.separator);
} else if (isRange) {
if (!val){
val = [null, null];
} else {
if (typeof val === 'string') {
val = parser(val, format);
val = parser(val, format, this.separator);
} else if (type === 'timerange') {
val = parser(val, format).map(v => v || '');
val = parser(val, format, this.separator).map(v => v || '');
} else {
const [start, end] = val;
if (start instanceof Date && end instanceof Date){
val = val.map(date => new Date(date));
} else if (typeof start === 'string' && typeof end === 'string'){
val = parser(val.join(RANGE_SEPARATOR), format);
val = parser(val.join(this.separator), format, this.separator);
} else if (!start || !end){
val = [null, null];
}
@ -640,13 +644,13 @@
if (this.multiple) {
const formatter = TYPE_VALUE_RESOLVER_MAP.multiple.formatter;
return formatter(value, this.format || format);
return formatter(value, this.format || format, this.separator);
} else {
const {formatter} = (
TYPE_VALUE_RESOLVER_MAP[this.type] ||
TYPE_VALUE_RESOLVER_MAP['default']
);
return formatter(value, this.format || format);
return formatter(value, this.format || format, this.separator);
}
},
onPick(dates, visible = false, type) {

View file

@ -147,7 +147,7 @@ export const DEFAULT_FORMATS = {
datetimerange: 'yyyy-MM-dd HH:mm:ss'
};
export const RANGE_SEPARATOR = ' - ';
// export const RANGE_SEPARATOR = ' - '; // use picker.vue prop separator
const DATE_FORMATTER = function(value, format) {
return formatDate(value, format);
@ -155,7 +155,7 @@ const DATE_FORMATTER = function(value, format) {
const DATE_PARSER = function(text, format) {
return parseDate(text, format);
};
const RANGE_FORMATTER = function(value, format) {
const RANGE_FORMATTER = function(value, format, RANGE_SEPARATOR) {
if (Array.isArray(value) && value.length === 2) {
const start = value[0];
const end = value[1];
@ -168,7 +168,7 @@ const RANGE_FORMATTER = function(value, format) {
}
return '';
};
const RANGE_PARSER = function(text, format) {
const RANGE_PARSER = function(text, format, RANGE_SEPARATOR) {
const array = Array.isArray(text) ? text : text.split(RANGE_SEPARATOR);
if (array.length === 2) {
const range1 = array[0];

View file

@ -31,6 +31,12 @@
dashed: {
type: Boolean,
default: false,
},
size: {
validator (value) {
return oneOf(value, ['small', 'default']);
},
default: 'default'
}
},
computed: {
@ -41,6 +47,7 @@
return [
`${prefixCls}`,
`${prefixCls}-${this.type}`,
`${prefixCls}-${this.size}`,
{
[`${prefixCls}-with-text`]: this.hasSlot && this.orientation === 'center',
[`${prefixCls}-with-text-${this.orientation}`]: this.hasSlot,

View file

@ -15,6 +15,15 @@
<div :class="[prefixCls + '-header']" v-if="showHead"><slot name="header"><div :class="[prefixCls + '-header-inner']">{{ title }}</div></slot></div>
<div :class="[prefixCls + '-body']" :style="styles"><slot></slot></div>
</div>
<div class="ivu-drawer-drag" :class="{ 'ivu-drawer-drag-left': placement === 'left' }" v-if="draggable" @mousedown="handleTriggerMousedown">
<slot name="trigger">
<div class="ivu-drawer-drag-move-trigger">
<div class="ivu-drawer-drag-move-trigger-point">
<i></i><i></i><i></i><i></i><i></i>
</div>
</div>
</slot>
</div>
</div>
</transition>
</div>
@ -27,6 +36,8 @@
import Emitter from '../../mixins/emitter';
import ScrollbarMixins from '../modal/mixins-scrollbar';
import { on, off } from '../../utils/dom';
const prefixCls = 'ivu-drawer';
export default {
@ -90,7 +101,13 @@
inner: {
type: Boolean,
default: false
}
},
// Whether drag and drop is allowed to adjust width
draggable: {
type: Boolean,
default: false
},
beforeClose: Function,
},
data () {
return {
@ -98,6 +115,11 @@
visible: this.value,
wrapShow: false,
showHead: true,
canMove: false,
dragWidth: this.width,
wrapperWidth: this.width,
wrapperLeft: 0,
minWidth: 256
};
},
computed: {
@ -108,14 +130,15 @@
[`${prefixCls}-hidden`]: !this.wrapShow,
[`${this.className}`]: !!this.className,
[`${prefixCls}-no-mask`]: !this.mask,
[`${prefixCls}-wrap-inner`]: this.inner
[`${prefixCls}-wrap-inner`]: this.inner,
[`${prefixCls}-wrap-dragging`]: this.canMove
}
];
},
mainStyles () {
let style = {};
const width = parseInt(this.width);
const width = parseInt(this.dragWidth);
const styleWidth = {
width: width <= 100 ? `${width}%` : `${width}px`
@ -154,6 +177,21 @@
},
methods: {
close () {
if (!this.beforeClose) {
return this.handleClose();
}
const before = this.beforeClose();
if (before && before.then) {
before.then(() => {
this.handleClose();
});
} else {
this.handleClose();
}
},
handleClose () {
this.visible = false;
this.$emit('input', false);
this.$emit('on-close');
@ -168,6 +206,38 @@
const className = event.target.getAttribute('class');
if (className && className.indexOf(`${prefixCls}-wrap`) > -1) this.handleMask();
},
handleMousemove (event) {
if (!this.canMove || !this.draggable) return;
// window0
this.handleSetWrapperWidth();
const left = event.pageX - this.wrapperLeft;
// left
let width = this.placement === 'right' ? this.wrapperWidth - left : left;
//
width = Math.max(width, parseFloat(this.minWidth));
event.atMin = width === parseFloat(this.minWidth);
// width100
if (width <= 100) width = (width / this.wrapperWidth) * 100;
this.dragWidth = width;
this.$emit('on-resize-width', parseInt(this.dragWidth));
},
handleSetWrapperWidth () {
const {
width,
left
} = this.$el.getBoundingClientRect();
this.wrapperWidth = width;
this.wrapperLeft = left;
},
handleMouseup () {
if (!this.draggable) return;
this.canMove = false;
},
handleTriggerMousedown () {
this.canMove = true;
// trigger
window.getSelection().removeAllRanges();
},
},
mounted () {
if (this.visible) {
@ -181,8 +251,14 @@
}
this.showHead = showHead;
on(document, 'mousemove', this.handleMousemove);
on(document, 'mouseup', this.handleMouseup);
this.handleSetWrapperWidth();
},
beforeDestroy () {
off(document, 'mousemove', this.handleMousemove);
off(document, 'mouseup', this.handleMouseup);
this.removeScrollEffect();
},
watch: {

View file

@ -53,7 +53,10 @@
default () {
return !this.$IVIEW || this.$IVIEW.transfer === '' ? false : this.$IVIEW.transfer;
}
}
},
transferClassName: {
type: String
},
},
computed: {
transition () {
@ -61,7 +64,8 @@
},
dropdownCls () {
return {
[prefixCls + '-transfer']: this.transfer
[prefixCls + '-transfer']: this.transfer,
[this.transferClassName]: this.transferClassName
};
},
relClasses () {

View file

@ -84,9 +84,12 @@
};
},
watch: {
error (val) {
this.validateMessage = val;
this.validateState = val === '' ? '' : 'error';
error: {
handler (val) {
this.validateMessage = val;
this.validateState = val ? 'error' : '';
},
immediate: true
},
validateStatus (val) {
this.validateState = val;
@ -114,19 +117,16 @@
// }
// return parent;
// },
fieldValue: {
cache: false,
get() {
const model = this.form.model;
if (!model || !this.prop) { return; }
fieldValue () {
const model = this.form.model;
if (!model || !this.prop) { return; }
let path = this.prop;
if (path.indexOf(':') !== -1) {
path = path.replace(/:/, '.');
}
return getPropByPath(model, path).v;
let path = this.prop;
if (path.indexOf(':') !== -1) {
path = path.replace(/:/, '.');
}
return getPropByPath(model, path).v;
},
labelStyles () {
let style = {};

View file

@ -19,7 +19,9 @@
xs: [Number, Object],
sm: [Number, Object],
md: [Number, Object],
lg: [Number, Object]
lg: [Number, Object],
xl: [Number, Object],
xxl: [Number, Object]
},
data () {
return {
@ -40,7 +42,7 @@
}
];
['xs', 'sm', 'md', 'lg'].forEach(size => {
['xs', 'sm', 'md', 'lg', 'xl', 'xxl'].forEach(size => {
if (typeof this[size] === 'number') {
classList.push(`${prefixCls}-span-${size}-${this[size]}`);
} else if (typeof this[size] === 'object') {

View file

@ -2,7 +2,7 @@
<div :class="wrapClasses">
<template v-if="type !== 'textarea'">
<div :class="[prefixCls + '-group-prepend']" v-if="prepend" v-show="slotReady"><slot name="prepend"></slot></div>
<i class="ivu-icon" :class="['ivu-icon-ios-close-circle', prefixCls + '-icon', prefixCls + '-icon-clear' , prefixCls + '-icon-normal']" v-if="clearable && currentValue" @click="handleClear"></i>
<i class="ivu-icon" :class="['ivu-icon-ios-close-circle', prefixCls + '-icon', prefixCls + '-icon-clear' , prefixCls + '-icon-normal']" v-if="clearable && currentValue && !disabled" @click="handleClear"></i>
<i class="ivu-icon" :class="['ivu-icon-' + icon, prefixCls + '-icon', prefixCls + '-icon-normal']" v-else-if="icon" @click="handleIconClick"></i>
<i class="ivu-icon ivu-icon-ios-search" :class="[prefixCls + '-icon', prefixCls + '-icon-normal', prefixCls + '-search-icon']" v-else-if="search && enterButton === false" @click="handleSearch"></i>
<span class="ivu-input-suffix" v-else-if="showSuffix"><slot name="suffix"><i class="ivu-icon" :class="['ivu-icon-' + suffix]" v-if="suffix"></i></slot></span>
@ -85,7 +85,7 @@
props: {
type: {
validator (value) {
return oneOf(value, ['text', 'textarea', 'password', 'url', 'email', 'date']);
return oneOf(value, ['text', 'textarea', 'password', 'url', 'email', 'date', 'number', 'tel']);
},
default: 'text'
},

View file

@ -42,7 +42,7 @@
breakpoint: {
type: String,
validator (val) {
return oneOf(val, ['xs', 'sm', 'md', 'lg', 'xl']);
return oneOf(val, ['xs', 'sm', 'md', 'lg', 'xl', 'xxl']);
}
},
collapsible: {

View file

@ -11,6 +11,7 @@
const prefixCls = 'ivu-loading-bar';
export default {
name: 'LoadingBar',
props: {
// percent: {
// type: Number,

View file

@ -111,7 +111,8 @@ Modal.newInstance = properties => {
on: {
input: (status) => {
this.visible = status;
}
},
'on-cancel': this.cancel
}
}, [
h('div', {

View file

@ -52,6 +52,9 @@
vertical: {
type: Boolean,
default: false
},
strokeColor: {
type: String
}
},
data () {
@ -77,13 +80,19 @@
return type;
},
bgStyle () {
return this.vertical ? {
const style = this.vertical ? {
height: `${this.percent}%`,
width: `${this.strokeWidth}px`
width: `${this.strokeWidth}px`,
} : {
width: `${this.percent}%`,
height: `${this.strokeWidth}px`
};
if (this.strokeColor) {
style['background-color'] = this.strokeColor;
}
return style;
},
successBgStyle () {
return this.vertical ? {

View file

@ -231,7 +231,10 @@
},
elementId: {
type: String
}
},
transferClassName: {
type: String
},
},
mounted(){
this.$on('on-select-selected', this.onOptionClick);
@ -286,6 +289,7 @@
[prefixCls + '-dropdown-transfer']: this.transfer,
[prefixCls + '-multiple']: this.multiple && this.transfer,
['ivu-auto-complete']: this.autoComplete,
[this.transferClassName]: this.transferClassName
};
},
selectionCls () {

View file

@ -7,7 +7,7 @@
<template v-if="renderType === 'html'"><span v-html="row[column.key]"></span></template>
<template v-if="renderType === 'normal'">
<template v-if="column.tooltip">
<Tooltip transfer :content="row[column.key]" :disabled="!showTooltip" :max-width="300" class="ivu-table-cell-tooltip">
<Tooltip transfer :content="row[column.key]" :theme="tableRoot.tooltipTheme" :disabled="!showTooltip" :max-width="300" class="ivu-table-cell-tooltip">
<span ref="content" @mouseenter="handleTooltipIn" @mouseleave="handleTooltipOut" class="ivu-table-cell-tooltip-content">{{ row[column.key] }}</span>
</Tooltip>
</template>
@ -41,6 +41,7 @@
export default {
name: 'TableCell',
components: { Icon, Checkbox, TableExpand, TableSlot, Tooltip },
inject: ['tableRoot'],
props: {
prefixCls: String,
row: Object,

View file

@ -6,6 +6,7 @@
<tbody :class="[prefixCls + '-tbody']">
<template v-for="(row, index) in data">
<table-tr
:draggable="draggable"
:row="row"
:key="row._rowKey"
:prefix-cls="prefixCls"
@ -58,6 +59,10 @@
fixed: {
type: [Boolean, String],
default: false
},
draggable: {
type: Boolean,
default: false
}
},
computed: {

View file

@ -1,11 +1,13 @@
<template>
<tr :class="rowClasses(row._index)"><slot></slot></tr>
<tr :class="rowClasses(row._index)" :draggable="draggable" @dragstart="onDrag($event,row._index)" @drop="onDrop($event,row._index)" @dragover="allowDrop($event)" v-if="draggable"><slot></slot></tr>
<tr :class="rowClasses(row._index)" v-else><slot></slot></tr>
</template>
<script>
export default {
props: {
row: Object,
prefixCls: String
prefixCls: String,
draggable: Boolean
},
computed: {
objData () {
@ -13,6 +15,17 @@
}
},
methods: {
onDrag (e,index) {
e.dataTransfer.setData('index',index);
},
onDrop (e,index) {
const dragIndex = e.dataTransfer.getData('index');
this.$parent.$parent.dragAndDrop(dragIndex,index);
e.preventDefault();
},
allowDrop (e) {
e.preventDefault();
},
rowClasses (_index) {
return [
`${this.prefixCls}-row`,
@ -28,4 +41,4 @@
},
}
};
</script>
</script>

View file

@ -16,6 +16,7 @@
v-show="!((!!localeNoDataText && (!data || data.length === 0)) || (!!localeNoFilteredDataText && (!rebuildData || rebuildData.length === 0)))">
<table-body
ref="tbody"
:draggable="draggable"
:prefix-cls="prefixCls"
:styleObject="tableStyle"
:columns="cloneColumns"
@ -53,6 +54,7 @@
<div :class="[prefixCls + '-fixed-body']" :style="fixedBodyStyle" ref="fixedBody" @mousewheel="handleFixedMousewheel" @DOMMouseScroll="handleFixedMousewheel">
<table-body
fixed="left"
:draggable="draggable"
:prefix-cls="prefixCls"
:styleObject="fixedTableStyle"
:columns="leftFixedColumns"
@ -77,6 +79,7 @@
<div :class="[prefixCls + '-fixed-body']" :style="fixedBodyStyle" ref="fixedRightBody" @mousewheel="handleFixedMousewheel" @DOMMouseScroll="handleFixedMousewheel">
<table-body
fixed="right"
:draggable="draggable"
:prefix-cls="prefixCls"
:styleObject="fixedRightTableStyle"
:columns="rightFixedColumns"
@ -183,6 +186,16 @@
loading: {
type: Boolean,
default: false
},
draggable: {
type: Boolean,
default: false
},
tooltipTheme: {
validator (value) {
return oneOf(value, ['dark', 'light']);
},
default: 'dark'
}
},
data () {
@ -909,6 +922,9 @@
const data = Csv(columns, datas, params, noHeader);
if (params.callback) params.callback(data);
else ExportCsv.download(params.filename, data);
},
dragAndDrop(a,b) {
this.$emit('on-drag-drop', a,b);
}
},
created () {

View file

@ -6,6 +6,7 @@
export default {
name: 'TabPane',
inject: ['TabsInstance'],
props: {
name: {
type: String
@ -24,6 +25,15 @@
closable: {
type: Boolean,
default: null
},
// Tabs tab Tabs name
tab: {
type: String
},
// TabPane 使 v-if index
// 0
index: {
type: Number
}
},
data () {
@ -36,13 +46,13 @@
computed: {
contentStyle () {
return {
visibility: this.$parent.activeKey !== this.currentName ? 'hidden' : 'visible'
visibility: this.TabsInstance.activeKey !== this.currentName ? 'hidden' : 'visible'
};
}
},
methods: {
updateNav () {
this.$parent.updateNav();
this.TabsInstance.updateNav();
}
},
watch: {

View file

@ -32,7 +32,7 @@
<script>
import Icon from '../icon/icon.vue';
import Render from '../base/render';
import { oneOf, MutationObserver } from '../../utils/assist';
import { oneOf, MutationObserver, findComponentsDownward } from '../../utils/assist';
import Emitter from '../../mixins/emitter';
import elementResizeDetectorMaker from 'element-resize-detector';
@ -64,6 +64,9 @@
name: 'Tabs',
mixins: [ Emitter ],
components: { Icon, Render },
provide () {
return { TabsInstance: this };
},
props: {
value: {
type: [String, Number]
@ -93,6 +96,10 @@
default: false
},
beforeRemove: Function,
// Tabs name
name: {
type: String
},
},
data () {
return {
@ -166,7 +173,27 @@
},
methods: {
getTabs () {
return this.$children.filter(item => item.$options.name === 'TabPane');
// return this.$children.filter(item => item.$options.name === 'TabPane');
const AllTabPanes = findComponentsDownward(this, 'TabPane');
const TabPanes = [];
AllTabPanes.forEach(item => {
if (item.tab && this.name) {
if (item.tab === this.name) {
TabPanes.push(item);
}
} else {
TabPanes.push(item);
}
});
// TabPane 使 v-if index
TabPanes.sort((a, b) => {
if (a.index && b.index) {
return a.index > b.index ? 1 : -1;
}
});
return TabPanes;
},
updateNav () {
this.navList = [];
@ -393,7 +420,7 @@
return false;
},
updateVisibility(index){
[...this.$refs.panes.children].forEach((el, i) => {
[...this.$refs.panes.querySelectorAll(`.${prefixCls}-tabpane`)].forEach((el, i) => {
if (index === i) {
[...el.children].filter(child=> child.classList.contains(`${prefixCls}-tabpane`)).forEach(child => child.style.visibility = 'visible');
if (this.captureFocus) setTimeout(() => focusFirst(el, el), transitionTime);

View file

@ -41,6 +41,7 @@
export default {
name: 'TreeNode',
mixins: [ Emitter ],
inject: ['TreeInstance'],
components: { Checkbox, Icon, CollapseTransition, Render },
props: {
data: {
@ -156,7 +157,11 @@
},
handleSelect () {
if (this.data.disabled) return;
this.dispatch('Tree', 'on-selected', this.data.nodeKey);
if (this.TreeInstance.showCheckbox && this.TreeInstance.checkDirectly) {
this.handleCheck();
} else {
this.dispatch('Tree', 'on-selected', this.data.nodeKey);
}
},
handleCheck () {
if (this.data.disabled) return;

View file

@ -23,6 +23,9 @@
name: 'Tree',
mixins: [ Emitter, Locale ],
components: { TreeNode },
provide () {
return { TreeInstance: this };
},
props: {
data: {
type: Array,
@ -38,9 +41,14 @@
type: Boolean,
default: false
},
checkStrictly:{
type:Boolean,
default:false
checkStrictly: {
type: Boolean,
default: false
},
// showCheckbox checkDirectlyselect check
checkDirectly: {
type: Boolean,
default: false
},
emptyText: {
type: String
@ -54,7 +62,8 @@
},
render: {
type: Function
}
},
},
data () {
return {

View file

@ -137,6 +137,10 @@
paste: {
type: Boolean,
default: false
},
disabled: {
type: Boolean,
default: false
}
},
data () {
@ -162,6 +166,7 @@
},
methods: {
handleClick () {
if (this.disabled) return;
this.$refs.input.click();
},
handleChange (e) {
@ -175,9 +180,11 @@
},
onDrop (e) {
this.dragOver = false;
if (this.disabled) return;
this.uploadFiles(e.dataTransfer.files);
},
handlePaste (e) {
if (this.disabled) return;
if (this.paste) {
this.uploadFiles(e.clipboardData.files);
}