tijaio

tijaio

<template>

		<el-col :span="24" class="toolbar">
			<el-form :inline="true" :model="filters">

				<el-form-item>
					<el-button type="primary" @click="handleAdd">新增</el-button>
				</el-form-item>
			</el-form>
		</el-col>

		<template>
			<el-table :data="users" highlight-current-row v-loading="listLoading" style="width: 100%;">

				<el-table-column type="index" width="60">
				</el-table-column>
				<el-table-column prop="cover" label="图标" width="120" sortable>
					<template scope="scope">

					</template>
				</el-table-column>
				<el-table-column prop="title" label="名称" width="120" sortable>
				</el-table-column>
				<el-table-column prop="status" label="状态" :formatter="formatSex" width="120" sortable>
				</el-table-column>

				<el-table-column inline-template :context="_self" label="操作" min-width="320">

						<el-button size="small" @click="handleEdit(row)">编辑</el-button>

				</el-table-column>
			</el-table>
		</template>

		<el-dialog :title="editFormTtile" v-model="editFormVisible" :close-on-click-modal="false">
			<el-form :model="editForm" label-width="80px" :rules="editFormRules" ref="editForm">
				<el-form-item label="名称" prop="title">
					<el-input v-model="editForm.title" auto-complete="off"></el-input>
					<el-input type="hidden" v-model="editForm.cover" auto-complete="off"></el-input>
				</el-form-item>
				<el-form-item label="图片" prop="cover">
					<el-upload action="" :file-list="filelist" :http-request="handleRequestOss" list-type="picture-card" :on-change="handlechange" :on-preview="handlePictureCardPreview" :on-remove="handleRemove" :on-success="getUpstr">

					</el-upload>
					<el-dialog v-model="dialogVisible" size="tiny">

					</el-dialog>
				</el-form-item>

			</el-form>

				<el-button @click.native="editFormVisible = false">取 消</el-button>
				<el-button type="primary" @click.native="editSubmit" :loading="editLoading">{{btnEditText}}</el-button>

		</el-dialog>

		<el-dialog :title="editFormTtile" v-model="editFormVisibletest" :close-on-click-modal="false">
			<el-form :model="editForm" label-width="100px" :rules="editFormRules" ref="editForm">
				<el-form-item label="类型">
					<el-select v-model="editForm.sex" placeholder="请选择">
						<el-option label="现金券" :value="1"></el-option>
						<el-option label="满减券" :value="0"></el-option>
						<el-option label="打折券" :value="2"></el-option>
					</el-select>
				</el-form-item>

				<el-form-item label="分类">
					<el-select v-model="editForm.sex" placeholder="请选择">
						<el-option label="现金券" :value="1"></el-option>
						<el-option label="满减券" :value="0"></el-option>
						<el-option label="打折券" :value="2"></el-option>
					</el-select>
				</el-form-item>

				<el-form-item label="使用店铺" prop="name">
					<el-input v-model="editForm.name" auto-complete="off"></el-input>
				</el-form-item>
				<el-form-item label="优惠券名称" prop="name">
					<el-input v-model="editForm.name" auto-complete="off"></el-input>
				</el-form-item>
				<el-form-item label="优惠券面额" prop="name">
					<el-input v-model="editForm.name" auto-complete="off"></el-input>
				</el-form-item>
				<el-form-item label="优惠券折扣" prop="name">
					<el-input v-model="editForm.name" auto-complete="off"></el-input>
				</el-form-item>
				<el-form-item label="最低消费" prop="name">
					<el-input v-model="editForm.name" auto-complete="off"></el-input>
				</el-form-item>
				<el-form-item label="优惠券数量" prop="name">
					<el-input v-model="editForm.name" auto-complete="off"></el-input>
				</el-form-item>
				<el-form-item label="领券时间">
					<el-col :span="11">
						<el-date-picker type="date" placeholder="选择日期" v-model="editForm.date1" style="width: 100%;"></el-date-picker>
					</el-col>
					<el-col class="line" :span="2">-</el-col>
					<el-col :span="11">
						<el-time-picker type="date" placeholder="选择时间" v-model="editForm.date2" style="width: 100%;"></el-time-picker>
					</el-col>
				</el-form-item>
				<el-form-item label="优惠券说明">
					<el-input type="textarea" v-model="editForm.desc"></el-input>
				</el-form-item>
				<el-form-item label="使用说明">
					<el-input type="textarea" v-model="editForm.desc"></el-input>
				</el-form-item>
			</el-form>

				<el-button @click.native="editFormVisible = false">取 消</el-button>
				<el-button type="primary" @click.native="editSubmit" :loading="editLoading">{{btnEditText}}</el-button>

		</el-dialog>

</template>

<template>

		<el-col :span="24" class="toolbar">
			<el-form :inline="true" :model="filters">

				<el-form-item>
					<el-button type="primary" @click="handleAdd">新增</el-button>
				</el-form-item>
			</el-form>
		</el-col>

		<template>
			<el-table :data="users" highlight-current-row v-loading="listLoading" style="width: 100%;">
				<el-table-column type="expand">
					<template scope="props">
						<el-table :data="props.row.sub_type" style="width: 100%">
							<el-table-column type="index" width="60">
							</el-table-column>
							<el-table-column prop="cover" label="图标" width="120" sortable>
								<template scope="scope">

								</template>
							</el-table-column>
							<el-table-column prop="title" width="120" sortable>
							</el-table-column>
							<el-table-column prop="status" :formatter="formatSex" width="120" sortable>
							</el-table-column>

							<el-table-column inline-template :context="_self" min-width="320">

									<el-button size="small" @click="handleEdit(row)">编辑</el-button>

							</el-table-column>
						</el-table>
					</template>
				</el-table-column>
				<el-table-column type="index" width="60">
				</el-table-column>
				<el-table-column prop="cover" label="图标" width="120" sortable>
					<template scope="scope">

					</template>
				</el-table-column>
				<el-table-column prop="title" label="名称" width="120" sortable>
				</el-table-column>
				<el-table-column prop="status" label="状态" :formatter="formatSex" width="120" sortable>
				</el-table-column>

				<el-table-column inline-template :context="_self" label="操作" min-width="320">

						<el-button size="small" @click="handleEdit(row)">编辑</el-button>
						<el-button size="small" @click="handlesubAdd(row)">添加</el-button>

				</el-table-column>
			</el-table>
		</template>

		<el-dialog :title="editFormTtile" v-model="editFormVisible" :close-on-click-modal="false">
			<el-form :model="editForm" label-width="80px" :rules="editFormRules" ref="editForm">
				<el-form-item label="名称" prop="title">
					<el-input v-model="editForm.title" auto-complete="off"></el-input>
					<el-input type="hidden" v-model="editForm.cover" auto-complete="off"></el-input>
				</el-form-item>
				<el-form-item label="图片" prop="cover">
					<el-upload action="" :file-list="filelist" :http-request="handleRequestOss" list-type="picture-card" :on-change="handlechange" :on-preview="handlePictureCardPreview" :on-remove="handleRemove" :on-success="getUpstr">

					</el-upload>
					<el-dialog v-model="dialogVisible" size="tiny">

					</el-dialog>
				</el-form-item>

			</el-form>

				<el-button @click.native="editFormVisible = false">取 消</el-button>
				<el-button type="primary" @click.native="editSubmit" :loading="editLoading">{{btnEditText}}</el-button>

		</el-dialog>

		<el-dialog :title="editFormTtile" v-model="editFormVisibletest" :close-on-click-modal="false">
			<el-form :model="editForm" label-width="100px" :rules="editFormRules" ref="editForm">
				<el-form-item label="类型">
					<el-select v-model="editForm.sex" placeholder="请选择">
						<el-option label="现金券" :value="1"></el-option>
						<el-option label="满减券" :value="0"></el-option>
						<el-option label="打折券" :value="2"></el-option>
					</el-select>
				</el-form-item>

				<el-form-item label="分类">
					<el-select v-model="editForm.sex" placeholder="请选择">
						<el-option label="现金券" :value="1"></el-option>
						<el-option label="满减券" :value="0"></el-option>
						<el-option label="打折券" :value="2"></el-option>
					</el-select>
				</el-form-item>

				<el-form-item label="使用店铺" prop="name">
					<el-input v-model="editForm.name" auto-complete="off"></el-input>
				</el-form-item>
				<el-form-item label="优惠券名称" prop="name">
					<el-input v-model="editForm.name" auto-complete="off"></el-input>
				</el-form-item>
				<el-form-item label="优惠券面额" prop="name">
					<el-input v-model="editForm.name" auto-complete="off"></el-input>
				</el-form-item>
				<el-form-item label="优惠券折扣" prop="name">
					<el-input v-model="editForm.name" auto-complete="off"></el-input>
				</el-form-item>
				<el-form-item label="最低消费" prop="name">
					<el-input v-model="editForm.name" auto-complete="off"></el-input>
				</el-form-item>
				<el-form-item label="优惠券数量" prop="name">
					<el-input v-model="editForm.name" auto-complete="off"></el-input>
				</el-form-item>
				<el-form-item label="领券时间">
					<el-col :span="11">
						<el-date-picker type="date" placeholder="选择日期" v-model="editForm.date1" style="width: 100%;"></el-date-picker>
					</el-col>
					<el-col class="line" :span="2">-</el-col>
					<el-col :span="11">
						<el-time-picker type="date" placeholder="选择时间" v-model="editForm.date2" style="width: 100%;"></el-time-picker>
					</el-col>
				</el-form-item>
				<el-form-item label="优惠券说明">
					<el-input type="textarea" v-model="editForm.desc"></el-input>
				</el-form-item>
				<el-form-item label="使用说明">
					<el-input type="textarea" v-model="editForm.desc"></el-input>
				</el-form-item>
			</el-form>

				<el-button @click.native="editFormVisible = false">取 消</el-button>
				<el-button type="primary" @click.native="editSubmit" :loading="editLoading">{{btnEditText}}</el-button>

		</el-dialog>

</template>


Revised Same As check and its behaviour

Revised Same As check and its behaviour

/*
Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
*/
<template>
    <fieldset>

          <legend :id="id">
            Person Responsible for Work
          </legend>

            Save
            Back to top

Supervisor and Operator are the same

            <v-select
                :class="errors.person_responsible?'border border-danger dropdown-error-border':''"
                :disabled="persons === null"
                id="personResponsibleSelect"
                :filterable="false"
                :options="personOptions"
                label="name"
                v-model="personResponsibleInput"
                @search="onPersonSearch"
                ref="personResponsible"
                @search:blur="handleSearchBlur(personOptions, $refs.personResponsible, 'personResponsibleInput')">
              <template slot="no-options">
                  Type to search registry...
              </template>
              <template slot="option" slot-scope="option">

                  {{ option.name }}

              </template>
              <template slot="selected-option" slot-scope="option">

                  {{ option.name }}

              </template>
            </v-select>

              *displays a maximum of {{MAX_RESULTS}} results

              <div v-for="(error, index) in errors.person_responsible" :key="`personResponsible error ${index}`" class="text-danger">
                {{ error }}

          <form-input
              id="drillerName"
              label="Drill Operator"
              type="text"
              :disabled="drillerSameAsPersonResponsible"
              v-model="drillerNameInput"
              :errors="errors['driller_name']"
              :loaded="fieldsLoaded['driller_name']"
          ></form-input>

            Company of person Responsible for Drilling
            <v-select
              :disabled="companies === null"
              id="companyOfPersonResponsibleSelect"
              :filterable="false"
              :options="companyOfPersonResponsibleOptions"
              label="org_verbose_name"
              v-model="companyOfPersonResponsibleInput"
              @search="onCompanyOfPersonResponsibleSearch"
              ref="companyOfPersonResponsible"
              @search:blur="handleSearchBlur(companyOfPersonResponsibleOptions, $refs.companyOfPersonResponsible, 'companyOfPersonResponsibleInput')">
              <template slot="no-options">
                  Search by company name
              </template>
            </v-select>

              *displays a maximum of {{MAX_RESULTS}} results

              <div v-for="(error, index) in errors.driller_company_responsible" :key="`companyOfPersonResponsible error ${index}`" class="text-danger">
                {{ error }}

          <form-input
              id="consultantName"
              label="Consultant Name"
              type="text"
              v-model="consultantNameInput"
              :errors="errors['consultant_name']"
              :loaded="fieldsLoaded['consultant_name']"
          ></form-input>

          <form-input
              id="consultantCompany"
              label="Consultant Company"
              type="text"
              v-model="consultantCompanyInput"
              :errors="errors['consultant_company']"
              :loaded="fieldsLoaded['consultant_company']"
          ></form-input>

    </fieldset>
</template>

/*
Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
*/
<template>
    <fieldset>

          <legend :id="id">
            Person Responsible for Work
          </legend>

            Save
            Back to top

            Person Responsible for Drilling
            <v-select
                :class="errors.person_responsible?'border border-danger dropdown-error-border':''"
                :disabled="persons === null"
                id="personResponsibleSelect"
                :filterable="false"
                :options="personOptions"
                label="name"
                v-model="personResponsibleInput"
                @search="onPersonSearch"
                ref="personResponsible"
                @search:blur="handleSearchBlur(personOptions, $refs.personResponsible, 'personResponsibleInput')">
              <template slot="no-options">
                  Type to search registry...
              </template>
              <template slot="option" slot-scope="option">

                  {{ option.name }}

              </template>
              <template slot="selected-option" slot-scope="option">

                  {{ option.name }}

              </template>
            </v-select>

              *displays a maximum of {{MAX_RESULTS}} results

              <div v-for="(error, index) in errors.person_responsible" :key="`personResponsible error ${index}`" class="text-danger">
                {{ error }}

Drill Operator

            Same as Supervisor

          <form-input
              id="drillerName"
              label=""
              type="text"
              :disabled="drillerSameAsPersonResponsible"
              v-model="drillerNameInput"
              :errors="errors['driller_name']"
              :loaded="fieldsLoaded['driller_name']"
          ></form-input>

            Company of person Responsible for Drilling
            <v-select
              :disabled="companies === null"
              id="companyOfPersonResponsibleSelect"
              :filterable="false"
              :options="companyOfPersonResponsibleOptions"
              label="org_verbose_name"
              v-model="companyOfPersonResponsibleInput"
              @search="onCompanyOfPersonResponsibleSearch"
              ref="companyOfPersonResponsible"
              @search:blur="handleSearchBlur(companyOfPersonResponsibleOptions, $refs.companyOfPersonResponsible, 'companyOfPersonResponsibleInput')">
              <template slot="no-options">
                  Search by company name
              </template>
            </v-select>

              *displays a maximum of {{MAX_RESULTS}} results

              <div v-for="(error, index) in errors.driller_company_responsible" :key="`companyOfPersonResponsible error ${index}`" class="text-danger">
                {{ error }}

          <form-input
              id="consultantName"
              label="Consultant Name"
              type="text"
              v-model="consultantNameInput"
              :errors="errors['consultant_name']"
              :loaded="fieldsLoaded['consultant_name']"
          ></form-input>

          <form-input
              id="consultantCompany"
              label="Consultant Company"
              type="text"
              v-model="consultantCompanyInput"
              :errors="errors['consultant_company']"
              :loaded="fieldsLoaded['consultant_company']"
          ></form-input>

    </fieldset>
</template>


Use Boolean as a callback function

Use Boolean as a callback function

<template>

  <VDataTable
    v-if="items.length"
    hide-actions
    disable-initial-sort
    :headers="headers"
    :items="items"
  >
    <template slot="items" slot-scope="props">

      {{ props.item.type }}

        <template v-if="props.item.key === 'file_size_in_bytes'">
          {{ formatFileSize(props.item.live) }}
        </template>
        <template v-else>
          {{ props.item.live === '' ? '-' : props.item.live }}
        </template>

        <template v-if="props.item.key === 'file_size_in_bytes'">
          {{ formatFileSize(props.item.staged) }}
        </template>
        <template v-else>
          {{ props.item.staged === '' ? '-' : props.item.staged }}
        </template>

        <template v-if="props.item.key === 'ricecooker_version'">
          -
        </template>
        <template v-else>
          <Diff :value="props.item.diff" class="font-weight-bold">
            <template slot-scope="{ sign, value }">

                {{ sign }}{{ value ? formatFileSize(value) : '-' }}

                {{ sign }}{{ value ? value : '-' }}

            </template>
          </Diff>
        </template>

    </template>
  </VDataTable>

</template>


Ensure default table always selected.

Ensure default table always selected.

<template>

      <component is="tableheaderkeys" :activeNames="localHeaderNames" :getSelectedKeys="foreignKey.fields" :pushSelectedKeys="pushSelectedLocalKeys(index)" />
      <component v-show="enableComponent(foreignKey.fields)" is="tablekeys" :allTableNames="allTableNames" :getSelectedTable="foreignKey.reference.resource" :pushSelectedTable="pushSelectedForeignTable(index)" />
      <component v-show="enableComponent(foreignKey.fields)" is="tableheaderkeys" :activeNames="getForeignHeaderNames(foreignKey.reference.resource)" :getSelectedKeys="foreignKey.reference.fields" :pushSelectedKeys="pushSelectedForeignKeys(index)"/>

    <button v-show="hotIdAllForeignKeys.length > 1" type="button" class="btn btn-danger btn-sm" @click="removeForeignKey(index)">

    </button>

    <button type="button" class="add-foreign btn btn-primary btn-sm" @click="addForeignKey()">
      Add Foreign Key
    </button>

</template>

<template>

      <component is="tableheaderkeys" :activeNames="localHeaderNames" :getSelectedKeys="foreignKey.fields" :pushSelectedKeys="pushSelectedLocalKeys(index)" />
      <component v-show="enableComponent(foreignKey.fields)" is="tablekeys" :allTableNames="allTableNames" :getSelectedTable="foreignKey.reference.resource" :pushSelectedTable="pushSelectedForeignTable(index)" />
      <component v-show="enableComponent(foreignKey.reference.resource)" is="tableheaderkeys" :activeNames="getForeignHeaderNames(foreignKey.reference.resource)" :getSelectedKeys="foreignKey.reference.fields" :pushSelectedKeys="pushSelectedForeignKeys(index)"/>

    <button v-show="hotIdAllForeignKeys.length > 1" type="button" class="btn btn-danger btn-sm" @click="removeForeignKey(index)">

    </button>

    <button type="button" class="add-foreign btn btn-primary btn-sm" @click="addForeignKey()">
      Add Foreign Key
    </button>

</template>


Cascader: prevent value changing when menu is closing  (#12507)

<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;
    const result = [];
    const configurableProps = ['__IS__FLAT__OPTIONS', 'label', 'value', 'disabled'];
    const childrenProp = props.children || 'children';
    arr.forEach(item => {
      const itemCopy = {};
      configurableProps.forEach(prop => {
        let name = props[prop];
        let value = item[name];
        if (value === undefined) {
          name = prop;
          value = item[name];
        }
        if (value !== undefined) itemCopy[name] = value;
      });
      if (Array.isArray(item[childrenProp])) {
        itemCopy[childrenProp] = copyArray(item[childrenProp], props);
      }
      result.push(itemCopy);
    });
    return result;
  };

  export default {
    name: 'ElCascaderMenu',

    data() {
      return {
        inputWidth: 0,
        options: [],
        props: {},
        visible: false,
        activeValue: [],
        value: [],
        expandTrigger: 'click',
        changeOnSelect: false,
        popperClass: '',
        hoverTimer: 0,
        clicking: false,
        id: generateId()
      };
    },

    watch: {
      visible(value) {
        if (value) {
          this.activeValue = this.value;
        }
      },
      value: {
        immediate: true,
        handler(value) {
          this.activeValue = value;
        }
      }
    },

    computed: {
      activeOptions: {
        cache: false,
        get() {
          const activeValue = this.activeValue;
          const configurableProps = ['label', 'value', 'children', 'disabled'];

          const formatOptions = options => {
            options.forEach(option => {
              if (option.__IS__FLAT__OPTIONS) return;
              configurableProps.forEach(prop => {
                const value = option[this.props[prop] || prop];
                if (value !== undefined) option[prop] = value;
              });
              if (Array.isArray(option.children)) {
                formatOptions(option.children);
              }
            });
          };

          const loadActiveOptions = (options, activeOptions = []) => {
            const level = activeOptions.length;
            activeOptions[level] = options;
            let active = activeValue[level];
            if (isDef(active)) {
              options = options.filter(option => option.value === active)[0];
              if (options && options.children) {
                loadActiveOptions(options.children, activeOptions);
              }
            }
            return activeOptions;
          };

          const optionsCopy = copyArray(this.options, this.props);
          formatOptions(optionsCopy);
          return loadActiveOptions(optionsCopy);
        }
      }
    },

    methods: {
      select(item, menuIndex) {
        if (item.__IS__FLAT__OPTIONS) {
          this.activeValue = item.value;
        } else if (menuIndex) {
          this.activeValue.splice(menuIndex, this.activeValue.length - 1, item.value);
        } else {
          this.activeValue = [item.value];
        }
        this.$emit('pick', this.activeValue.slice());
      },
      handleMenuLeave() {
        this.$emit('menuLeave');
      },
      activeItem(item, menuIndex) {
        const len = this.activeOptions.length;
        this.activeValue.splice(menuIndex, len, item.value);
        this.activeOptions.splice(menuIndex + 1, len, item.children);
        if (this.changeOnSelect) {
          this.$emit('pick', this.activeValue.slice(), false);
        } else {
          this.$emit('activeItemChange', this.activeValue);
        }
      },
      scrollMenu(menu) {
        scrollIntoView(menu, menu.getElementsByClassName('is-active')[0]);
      },
      handleMenuEnter() {
        this.$nextTick(() => this.$refs.menus.forEach(menu => this.scrollMenu(menu)));
      }
    },

    render(h) {
      const {
        activeValue,
        activeOptions,
        visible,
        expandTrigger,
        popperClass,
        hoverThreshold
      } = this;
      let itemId = null;
      let itemIndex = 0;

      let hoverMenuRefs = {};
      const hoverMenuHandler = e => {
        const activeMenu = hoverMenuRefs.activeMenu;
        if (!activeMenu) return;
        const offsetX = e.offsetX;
        const width = activeMenu.offsetWidth;
        const height = 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: {}
          };

          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].indexOf(keyCode) < 0) {
                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].indexOf(keyCode) > -1) {
                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];
              const triggerHandler = () => {
                if (this.visible) {
                  this.activeItem(item, menuIndex);
                  this.$nextTick(() => {
                    // adjust self and next level
                    this.scrollMenu(this.$refs.menus[menuIndex]);
                    this.scrollMenu(this.$refs.menus[menuIndex + 1]);
                  });
                }
              };
              events.on[triggerEvent] = triggerHandler;
              if (triggerEvent === 'mouseenter' && this.changeOnSelect) {
                events.on.click = () => {
                  if (this.activeValue.indexOf(item.value) !== -1) {
                    this.$emit('closeInside', true);
                  }
                };
              }
              events.on['mousedown'] = () => {
                this.clicking = true;
              };
              events.on['focus'] = () => { // focus 选中
                if (this.clicking) {
                  this.clicking = false;
                  return;
                }
                triggerHandler();
              };
            } else {
              events.on.click = () => {
                this.select(item, menuIndex);
                this.$nextTick(() => this.scrollMenu(this.$refs.menus[menuIndex]));
              };
            }
          }
          if (!item.disabled && !item.children) { // no children set id
            itemId = `${menuId}-${itemIndex}`;
            itemIndex++;
          }
          return (
            <li
              class={{
                'el-cascader-menu__item': true,
                'el-cascader-menu__item--extensible': item.children,
                '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>
          );
        });
        let menuStyle = {};
        if (isFlat) {
          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"
            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
            v-show={visible}
            class={[
              'el-cascader-menus el-popper',
              popperClass
            ]}
            ref="wrapper"
          >
            <div x-arrow class="popper__arrow"></div>
            {menus}
          </div>
        </transition>
      );
    }
  };
</script>

<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;
    const result = [];
    const configurableProps = ['__IS__FLAT__OPTIONS', 'label', 'value', 'disabled'];
    const childrenProp = props.children || 'children';
    arr.forEach(item => {
      const itemCopy = {};
      configurableProps.forEach(prop => {
        let name = props[prop];
        let value = item[name];
        if (value === undefined) {
          name = prop;
          value = item[name];
        }
        if (value !== undefined) itemCopy[name] = value;
      });
      if (Array.isArray(item[childrenProp])) {
        itemCopy[childrenProp] = copyArray(item[childrenProp], props);
      }
      result.push(itemCopy);
    });
    return result;
  };

  export default {
    name: 'ElCascaderMenu',

    data() {
      return {
        inputWidth: 0,
        options: [],
        props: {},
        visible: false,
        activeValue: [],
        value: [],
        expandTrigger: 'click',
        changeOnSelect: false,
        popperClass: '',
        hoverTimer: 0,
        clicking: false,
        id: generateId()
      };
    },

    watch: {
      visible(value) {
        if (value) {
          this.activeValue = this.value;
        }
      },
      value: {
        immediate: true,
        handler(value) {
          this.activeValue = value;
        }
      }
    },

    computed: {
      activeOptions: {
        cache: false,
        get() {
          const activeValue = this.activeValue;
          const configurableProps = ['label', 'value', 'children', 'disabled'];

          const formatOptions = options => {
            options.forEach(option => {
              if (option.__IS__FLAT__OPTIONS) return;
              configurableProps.forEach(prop => {
                const value = option[this.props[prop] || prop];
                if (value !== undefined) option[prop] = value;
              });
              if (Array.isArray(option.children)) {
                formatOptions(option.children);
              }
            });
          };

          const loadActiveOptions = (options, activeOptions = []) => {
            const level = activeOptions.length;
            activeOptions[level] = options;
            let active = activeValue[level];
            if (isDef(active)) {
              options = options.filter(option => option.value === active)[0];
              if (options && options.children) {
                loadActiveOptions(options.children, activeOptions);
              }
            }
            return activeOptions;
          };

          const optionsCopy = copyArray(this.options, this.props);
          formatOptions(optionsCopy);
          return loadActiveOptions(optionsCopy);
        }
      }
    },

    methods: {
      select(item, menuIndex) {
        if (item.__IS__FLAT__OPTIONS) {
          this.activeValue = item.value;
        } else if (menuIndex) {
          this.activeValue.splice(menuIndex, this.activeValue.length - 1, item.value);
        } else {
          this.activeValue = [item.value];
        }
        this.$emit('pick', this.activeValue.slice());
      },
      handleMenuLeave() {
        this.$emit('menuLeave');
      },
      activeItem(item, menuIndex) {
        const len = this.activeOptions.length;
        this.activeValue.splice(menuIndex, len, item.value);
        this.activeOptions.splice(menuIndex + 1, len, item.children);
        if (this.changeOnSelect) {
          this.$emit('pick', this.activeValue.slice(), false);
        } else {
          this.$emit('activeItemChange', this.activeValue);
        }
      },
      scrollMenu(menu) {
        scrollIntoView(menu, menu.getElementsByClassName('is-active')[0]);
      },
      handleMenuEnter() {
        this.$nextTick(() => this.$refs.menus.forEach(menu => this.scrollMenu(menu)));
      }
    },

    render(h) {
      const {
        activeValue,
        activeOptions,
        visible,
        expandTrigger,
        popperClass,
        hoverThreshold
      } = this;
      let itemId = null;
      let itemIndex = 0;

      let hoverMenuRefs = {};
      const hoverMenuHandler = e => {
        const activeMenu = hoverMenuRefs.activeMenu;
        if (!activeMenu) return;
        const offsetX = e.offsetX;
        const width = activeMenu.offsetWidth;
        const height = 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: {}
          };

          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].indexOf(keyCode) < 0) {
                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].indexOf(keyCode) > -1) {
                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];
              const triggerHandler = () => {
                this.activeItem(item, menuIndex);
                this.$nextTick(() => {
                  // adjust self and next level
                  this.scrollMenu(this.$refs.menus[menuIndex]);
                  this.scrollMenu(this.$refs.menus[menuIndex + 1]);
                });
              };
              events.on[triggerEvent] = triggerHandler;
              if (triggerEvent === 'mouseenter' && this.changeOnSelect) {
                events.on.click = () => {
                  if (this.activeValue.indexOf(item.value) !== -1) {
                    this.$emit('closeInside', true);
                  }
                };
              }
              events.on['mousedown'] = () => {
                this.clicking = true;
              };
              events.on['focus'] = () => { // focus 选中
                if (this.clicking) {
                  this.clicking = false;
                  return;
                }
                triggerHandler();
              };
            } else {
              events.on.click = () => {
                this.select(item, menuIndex);
                this.$nextTick(() => this.scrollMenu(this.$refs.menus[menuIndex]));
              };
            }
          }
          if (!item.disabled && !item.children) { // no children set id
            itemId = `${menuId}-${itemIndex}`;
            itemIndex++;
          }
          return (
            <li
              class={{
                'el-cascader-menu__item': true,
                'el-cascader-menu__item--extensible': item.children,
                '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>
          );
        });
        let menuStyle = {};
        if (isFlat) {
          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"
            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
            v-show={visible}
            class={[
              'el-cascader-menus el-popper',
              popperClass
            ]}
            ref="wrapper"
          >
            <div x-arrow class="popper__arrow"></div>
            {menus}
          </div>
        </transition>
      );
    }
  };
</script>


Fix typo in dashboard search suggestions

<template>

        <router-link
          :to="{ name: searchRoute, params: searchRouteParameters }"
          class="suggestions__header is-caption text"
          :class="{ 'suggestions__header--loading': isFetching }"
          v-if="query"
          @click.native="onPageChange">
          {{ query }} - {{ searchResults.total_entries }} results
        </router-link>

        <SearchSuggestionsItem :item="visualization" @itemClick="onPageChange"/>

</template>


show delegates if exists

show delegates if exists

<template>
  <uw-card-property-group>
    <uw-card-property title="Grading System">

        {{titleCaseWord(section.grading_system)}}

        Unspecified

    </uw-card-property>
    <uw-card-property :title="`Delegate${gradeSubmissionDelegatesCount > 1 ? 's' :  ''}`">

          {{titleCaseName(delegate.person.display_name)}}
          ({{titleCaseWord(delegate.level)}})

        None assigned

          Update grade submission delegate

          Add grade submission delegate

    </uw-card-property>
    <uw-card-property title="Grade Submission">
      <template v-if="section.gradingPeriod.isOpen">

                {{section.grading_status.submitted_count}}
                grade{{section.grading_status.submitted_count ? 's' : ''}}
                submitted

                by {{section.grading_status.submitted_by}}

                on {{section.grading_status.submittedFmt}}

                {{section.grading_status.unsubmitted_count}}
                grade{{section.grading_status.unsubmitted_count ? 's' : ''}}
                to submit

                Submit grades in Gradepage

                {{section.grading_status.grading_status}}

              Grading for secondary section is disabled.
              Grade primary section.

          An error occurred with
          Gradepage. Please try again later.

          Grade submission closes

            {{section.gradingPeriod.deadlineFmt}}

            ({{section.gradingPeriod.deadlineRelative}})

      </template>
      <template v-else-if="section.gradingPeriod.isClosed">

            {{section.grading_status.submitted_count}}
            grade{{section.grading_status.submitted_count ? 's' : ''}}
            submitted

            by {{section.grading_status.submitted_by}}

            on {{section.grading_status.submittedFmt}}

            Grade submission for {{titleCaseWord(section.quarter)}} {{section.year}} closed
            {{section.gradingPeriod.deadlineFmt}}

            {{section.grading_status.grading_status ?
              section.grading_status.grading_status :
              section.grading_status.unsubmitted_count
            }} grade{{section.grading_status.unsubmitted_count ? 's': ''}}
            not submitted through GradePage

            Grade submission for {{titleCaseWord(section.quarter)}} {{section.year}} closed
            {{section.gradingPeriod.deadlineFmt}}

              What can I do now?

      </template>
      <template v-else>

          Grade submission opens {{section.gradingPeriod.openFmt}}

            ({{section.gradingPeriod.openRelative}})

          Grade submission closes
          {{section.gradingPeriod.deadlineFmt}}

      </template>
    </uw-card-property>
  </uw-card-property-group>
</template>


Use templates

Use templates

<template>

Create Your Account

        Welcome to MBU Online! Create your account here to be able to use all
        of the features of this website.

        <button class="delete" @click.prevent="dismissError()"></button>

{{ error }}

      <form class="columns is-multiline">

          Email
          <input type="email"
                  class="input"
                  id="signup-email"
                  placeholder="Your email address"
                  v-model="credentials.email">

          Password
          <input type="password"
                  class="input"
                  id="signup-password"
                  placeholder="Password"
                  v-model="credentials.password">

          Password Confirmation
          <input type="password"
                  class="input"
                  id="signup-password-confirm"
                  placeholder="Confirm your password"
                  v-model="credentials.passwordConfirmation">

          First Name
          <input type="text"
                  class="input"
                  id="signup-first-name"
                  placeholder="First Name"
                  v-model="credentials.firstname">

          Last Name
          <input type="text"
                  class="input"
                  id="signup-last-name"
                  placeholder="Last Name"
                  v-model="credentials.lastname">

          I am a...

            <select class="input"
                    id="signup-role"
                    v-model="credentials.role">
              <option v-for="option in roles" :value="option.value">
                {{ option.text }}
              </option>
            </select>

        <template v-if="credentials.role === 'coordinator'">

            Troop
            <input type="number"
                  class="input"
                  id="signup-troop"
                  placeholder="Troop"
                  v-model="credentials.coordinator.troop">

            District
            <input type="text"
                  class="input"
                  id="signup-district"
                  placeholder="District"
                  v-model="credentials.coordinator.district">

            Council
            <input type="text"
                  class="input"
                  id="signup-council"
                  placeholder="Council"
                  v-model="credentials.coordinator.council">

        </template>
        <template v-if="credentials.role === 'teacher'">

            Chapter/Organization
            <input type="text"
                   class="input"
                   id="signup-chapter"
                   placeholder="Your group"
                   v-model="credentials.teacher.chapter">

        </template>

          <button class="button is-primary" @click.prevent="submit()">Signup</button>

      </form>

</template>

<template>

Create Your Account

        Welcome to MBU Online! Create your account here to be able to use all
        of the features of this website.

        <button class="delete" @click.prevent="dismissError()"></button>

{{ error }}

      <form class="columns is-multiline">

          Email
          <input type="email"
                  class="input"
                  id="signup-email"
                  placeholder="Your email address"
                  v-model="credentials.email">

          Password
          <input type="password"
                  class="input"
                  id="signup-password"
                  placeholder="Password"
                  v-model="credentials.password">

          Password Confirmation
          <input type="password"
                  class="input"
                  id="signup-password-confirm"
                  placeholder="Confirm your password"
                  v-model="credentials.passwordConfirmation">

          First Name
          <input type="text"
                  class="input"
                  id="signup-first-name"
                  placeholder="First Name"
                  v-model="credentials.firstname">

          Last Name
          <input type="text"
                  class="input"
                  id="signup-last-name"
                  placeholder="Last Name"
                  v-model="credentials.lastname">

          I am a...

            <select class="input"
                    id="signup-role"
                    v-model="credentials.role">
              <option v-for="option in roles" :value="option.value">
                {{ option.text }}
              </option>
            </select>

              Troop
              <input type="number"
                    class="input"
                    id="signup-troop"
                    placeholder="Troop"
                    v-model="credentials.coordinator.troop">

              District
              <input type="text"
                    class="input"
                    id="signup-district"
                    placeholder="District"
                    v-model="credentials.coordinator.district">

              Council
              <input type="text"
                    class="input"
                    id="signup-council"
                    placeholder="Council"
                    v-model="credentials.coordinator.council">

            Chapter/Organization
            <input type="text"
                   class="input"
                   id="signup-chapter"
                   placeholder="Your group"
                   v-model="credentials.teacher.chapter">

          <button class="button is-primary" @click.prevent="submit()">Signup</button>

      </form>

</template>


x-number: Fix less variables

x-number: Fix less variables

<template>

    -
    <input v-model.number="value" :name="name" class="vux-number-input" :style="{width: width+'px'}" :readonly="!fillable" pattern="[0-9]*"/>
    +

</template>


Make playlisted shot widget smaller

Make playlisted shot widget smaller

To avoid to display vertical scroll

<template>

  <drag @drag="onDragged" :transfer-data="shot.id">

          <x-icon />

        <light-entity-thumbnail
          :width="150"
          :height="103"
          :preview-file-id="previewFileId"
        />

{{ shot.sequence_name }} / {{ shot.name }}

 0"
      >
        <combobox
          ref="task-type-combobox"
          :thin="true"
          :options="taskTypeOptions"
          v-model="taskTypeId"
        />
        <combobox
          class="version-combo"
          :thin="true"
          :options="previewFileOptions"
          v-model="previewFileId"
        />

        {{ $t('playlists.no_preview') }}

  </drag>
  <drop @drop="onDropped">

  </drop>

</template>

<template>

  <drag @drag="onDragged" :transfer-data="shot.id">

          <x-icon />

        <light-entity-thumbnail
          :width="150"
          :height="103"
          :preview-file-id="previewFileId"
        />

{{ shot.sequence_name }} / {{ shot.name }}

 0"
      >
        <combobox
          ref="task-type-combobox"
          :options="taskTypeOptions"
          v-model="taskTypeId"
        />
        <combobox
          class="version-combo"
          :options="previewFileOptions"
          v-model="previewFileId"
        />

        {{ $t('playlists.no_preview') }}

  </drag>
  <drop @drop="onDropped">

  </drop>

</template>


refactor(pagination): move example for backstop screenshot

<template>

pagination

Normal

    <cdr-pagination
      v-model="page"
      :pages="pages"
      :total-pages="10"
      data-backstop="pagination-default"
    />

{{ datam.title }}

{{ datam.description }}

Using router-link/scoped slot

    <cdr-pagination
      :pages="makePages(20, null)"
      :total-pages="20"
      v-model="ex1Page"
    >

      <template v-slot:prevLink="prevLink">
        <router-link
          v-bind="prevLink.attrs"
          @click.native="prevLink.click"
          :to="{ query: { 'router-page': prevLink.page } }"
          replace
        >
          <component
            :is="prevLink.iconComponent"
            :class="prevLink.iconClass"
          />
          {{ prevLink.content }}
        </router-link>
      </template>

      <template v-slot:link="link">
        <router-link
          v-bind="link.attrs"
          @click.native="link.click"
          :to="{ query: { 'router-page': link.page } }"
          replace
        >
          {{ link.page }}
        </router-link>
      </template>

      <template v-slot:nextLink="nextLink">
        <router-link
          v-bind="nextLink.attrs"
          @click.native="nextLink.click"
          :to="{ query: { 'router-page': nextLink.page } }"
          replace
        >
          {{ nextLink.content }}
          <component
            :is="nextLink.iconComponent"
            :class="nextLink.iconClass"
          />
        </router-link>
      </template>
    </cdr-pagination>

Using p and scoped slot

    <cdr-pagination
      :pages="makePages(20, null)"
      :total-pages="20"
      v-model="paraPage"
    >

      <template v-slot:prevLink="prevLink">

          <component
            :is="prevLink.iconComponent"
            :class="prevLink.iconClass"
          />
          {{ prevLink.content }}

      </template>

      <template v-slot:link="link">

          {{ link.page }}

      </template>

      <template v-slot:nextLink="nextLink">

          {{ nextLink.content }}
          <component
            :is="nextLink.iconComponent"
            :class="nextLink.iconClass"
          />

      </template>
    </cdr-pagination>

Previous/Next only (known total)

    <cdr-pagination
      :pages="makePages(ex2Pages, '/#/pagination?ex2-known-page', ex2PageKnown - 2)"
      :total-pages="10"
      v-model="ex2PageKnown"
    />

Previous/Next only (unknown total)

    <cdr-pagination
      :pages="makePages(ex2Pages, '/#/pagination?ex2-unknown-page', ex2PageUnknown - 2)"
      v-model="ex2PageUnknown"
    />

Only 5 pages provided

    <cdr-pagination
      :pages="makePages(5, '/#/pagination?ex3-page')"
      :total-pages="5"
      v-model="ex3Page"
    />

</template>

<template>

pagination

{{ datam.title }}

{{ datam.description }}

Using router-link/scoped slot

    <cdr-pagination
      :pages="makePages(20, null)"
      :total-pages="20"
      v-model="ex1Page"
    >

      <template v-slot:prevLink="prevLink">
        <router-link
          v-bind="prevLink.attrs"
          @click.native="prevLink.click"
          :to="{ query: { 'router-page': prevLink.page } }"
          replace
        >
          <component
            :is="prevLink.iconComponent"
            :class="prevLink.iconClass"
          />
          {{ prevLink.content }}
        </router-link>
      </template>

      <template v-slot:link="link">
        <router-link
          v-bind="link.attrs"
          @click.native="link.click"
          :to="{ query: { 'router-page': link.page } }"
          replace
        >
          {{ link.page }}
        </router-link>
      </template>

      <template v-slot:nextLink="nextLink">
        <router-link
          v-bind="nextLink.attrs"
          @click.native="nextLink.click"
          :to="{ query: { 'router-page': nextLink.page } }"
          replace
        >
          {{ nextLink.content }}
          <component
            :is="nextLink.iconComponent"
            :class="nextLink.iconClass"
          />
        </router-link>
      </template>
    </cdr-pagination>

Using p and scoped slot

    <cdr-pagination
      :pages="makePages(20, null)"
      :total-pages="20"
      v-model="paraPage"
    >

      <template v-slot:prevLink="prevLink">

          <component
            :is="prevLink.iconComponent"
            :class="prevLink.iconClass"
          />
          {{ prevLink.content }}

      </template>

      <template v-slot:link="link">

          {{ link.page }}

      </template>

      <template v-slot:nextLink="nextLink">

          {{ nextLink.content }}
          <component
            :is="nextLink.iconComponent"
            :class="nextLink.iconClass"
          />

      </template>
    </cdr-pagination>

Previous/Next only (known total)

    <cdr-pagination
      :pages="makePages(ex2Pages, '/#/pagination?ex2-known-page', ex2PageKnown - 2)"
      :total-pages="10"
      v-model="ex2PageKnown"
    />

Previous/Next only (unknown total)

    <cdr-pagination
      :pages="makePages(ex2Pages, '/#/pagination?ex2-unknown-page', ex2PageUnknown - 2)"
      v-model="ex2PageUnknown"
    />

Only 5 pages provided

    <cdr-pagination
      :pages="makePages(5, '/#/pagination?ex3-page')"
      :total-pages="5"
      v-model="ex3Page"
    />

Normal

    <cdr-pagination
      v-model="page"
      :pages="pages"
      :total-pages="10"
      data-backstop="pagination-default"
    />

</template>