Implemented OrderList

pull/41/head
cagataycivici 2019-07-16 15:47:00 +03:00
parent 7af106bf43
commit e158ddca9d
8 changed files with 682 additions and 0 deletions

View File

@ -58,6 +58,7 @@
<router-link to="/datatable">&#9679; DataTable</router-link>
<router-link to="/dataview">&#9679; DataView</router-link>
<router-link to="/fullcalendar">&#9679; FullCalendar</router-link>
<router-link to="/orderlist">&#9679; OrderList</router-link>
<router-link to="/paginator">&#9679; Paginator</router-link>
</div>
</div>

View File

View File

@ -0,0 +1,411 @@
<template>
<div class="p-orderlist p-component">
<div class="p-orderlist-controls">
<OLButton type="button" icon="pi pi-angle-up" @click="moveUp"></OLButton>
<OLButton type="button" icon="pi pi-angle-double-up" @click="moveTop"></OLButton>
<OLButton type="button" icon="pi pi-angle-down" @click="moveDown"></OLButton>
<OLButton type="button" icon="pi pi-angle-double-down" @click="moveBottom"></OLButton>
</div>
<div class="p-orderlist-list-container">
<div class="p-orderlist-caption" v-if="$slots.header">
<slot name="header"></slot>
</div>
<ul ref="list" class="p-orderlist-list" :style="listStyle">
<li tabindex="0" v-for="(item, i) of value" :key="getItemKey(item, i)" :class="['p-orderlist-item', {'p-highlight': isSelected(item)}]"
@click="onItemClick($event, item, i)" @keydown="onItemKeyDown($event, item, i)" @touchend="onItemTouchEnd($event)">
<slot name="item" :item="item" :index="i"> </slot>
</li>
</ul>
</div>
</div>
</template>
<script>
import Button from '../button/Button';
import ObjectUtils from '../utils/ObjectUtils';
import DomHandler from '../utils/DomHandler';
export default {
props: {
value: {
type: Array,
default: null
},
selection: {
type: Array,
default: null
},
dataKey: {
type: String,
default: null
},
listStyle: {
type: null,
default: null
},
metaKeySelection: {
type: Boolean,
default: true
},
},
itemTouched: false,
reorderDirection: null,
data() {
return {
d_selection: this.selection
}
},
updated() {
if (this.reorderDirection) {
this.updateListScroll();
this.reorderDirection = null;
}
},
methods: {
getItemKey(item, index) {
return this.dataKey ? ObjectUtils.resolveFieldData(rowData, this.dataKey): index;
},
isSelected(item) {
return ObjectUtils.findIndexInList(item, this.d_selection) != -1;
},
moveUp() {
if (this.d_selection) {
let value = [...this.value];
for (let i = 0; i < this.d_selection.length; i++) {
let selectedItem = this.d_selection[i];
let selectedItemIndex = ObjectUtils.findIndexInList(selectedItem, value);
if (selectedItemIndex !== 0) {
let movedItem = value[selectedItemIndex];
let temp = value[selectedItemIndex - 1];
value[selectedItemIndex - 1] = movedItem;
value[selectedItemIndex] = temp;
}
else {
break;
}
}
this.reorderDirection = 'up';
this.$emit('input', value);
this.$emit('reorder', {
originalEvent: event,
value: value,
direction: this.reorderDirection
});
}
},
moveTop() {
if(this.d_selection) {
let value = [...this.value];
for (let i = 0; i < this.d_selection.length; i++) {
let selectedItem = this.d_selection[i];
let selectedItemIndex = ObjectUtils.findIndexInList(selectedItem, value);
if (selectedItemIndex !== 0) {
let movedItem = value.splice(selectedItemIndex, 1)[0];
value.unshift(movedItem);
}
else {
break;
}
}
this.reorderDirection = 'top';
this.$emit('input', value);
this.$emit('reorder', {
originalEvent: event,
value: value,
direction: this.reorderDirection
});
}
},
moveDown() {
if(this.d_selection) {
let value = [...this.value];
for (let i = this.d_selection.length - 1; i >= 0; i--) {
let selectedItem = this.d_selection[i];
let selectedItemIndex = ObjectUtils.findIndexInList(selectedItem, value);
if (selectedItemIndex !== (value.length - 1)) {
let movedItem = value[selectedItemIndex];
let temp = value[selectedItemIndex + 1];
value[selectedItemIndex + 1] = movedItem;
value[selectedItemIndex] = temp;
}
else {
break;
}
}
this.reorderDirection = 'down';
this.$emit('input', value);
this.$emit('reorder', {
originalEvent: event,
value: value,
direction: this.reorderDirection
});
}
},
moveBottom() {
if (this.d_selection) {
let value = [...this.value];
for (let i = this.d_selection.length - 1; i >= 0; i--) {
let selectedItem = this.d_selection[i];
let selectedItemIndex = ObjectUtils.findIndexInList(selectedItem, value);
if (selectedItemIndex !== (value.length - 1)) {
let movedItem = value.splice(selectedItemIndex, 1)[0];
value.push(movedItem);
}
else {
break;
}
}
this.reorderDirection = 'bottom';
this.$emit('input', value);
this.$emit('reorder', {
originalEvent: event,
value: value,
direction: this.reorderDirection
});
}
},
onItemClick(event, item, index) {
this.itemTouched = false;
let selectedIndex = ObjectUtils.findIndexInList(item, this.d_selection);
let selected = (selectedIndex != -1);
let metaSelection = this.itemTouched ? false : this.metaKeySelection;
if (metaSelection) {
let metaKey = (event.metaKey || event.ctrlKey);
if (selected && metaKey) {
this.d_selection = this.d_selection.filter((val, index) => index !== selectedIndex);
}
else {
this.d_selection = (metaKey) ? this.d_selection ? [...this.d_selection] : [] : [];
ObjectUtils.insertIntoOrderedArray(item, index, this.d_selection, this.value);
}
}
else {
if (selected) {
this.d_selection = this.d_selection.filter((val, index) => index !== selectedIndex);
}
else {
this.d_selection = this.d_selection ? [...this.d_selection] : [];
ObjectUtils.insertIntoOrderedArray(item, index, this.d_selection, this.value);
}
}
this.$emit('update:selection', this.d_selection);
this.$emit('selection-change', {
originalEvent:event,
value: this.d_selection
});
},
onItemTouchEnd(event) {
this.itemTouched = true;
},
onItemKeyDown(event, item, index) {
let listItem = event.currentTarget;
switch(event.which) {
//down
case 40:
var nextItem = this.findNextItem(listItem);
if (nextItem) {
nextItem.focus();
}
event.preventDefault();
break;
//up
case 38:
var prevItem = this.findPrevItem(listItem);
if (prevItem) {
prevItem.focus();
}
event.preventDefault();
break;
//enter
case 13:
this.onItemClick(event, item, index);
event.preventDefault();
break;
default:
break;
}
},
findNextItem(item) {
let nextItem = item.nextElementSibling;
if (nextItem)
return !DomHandler.hasClass(nextItem, 'p-orderlist-item') ? this.findNextItem(nextItem) : nextItem;
else
return null;
},
findPrevItem(item) {
let prevItem = item.previousElementSibling;
if (prevItem)
return !DomHandler.hasClass(prevItem, 'p-orderlist-item') ? this.findPrevItem(prevItem) : prevItem;
else
return null;
},
updateListScroll() {
const listItems = DomHandler.find(this.$refs.list, '.p-orderlist-item.p-highlight');
if (listItems && listItems.length) {
switch(this.reorderDirection) {
case 'up':
DomHandler.scrollInView(this.$refs.list, listItems[0]);
break;
case 'top':
this.$refs.list.scrollTop = 0;
break;
case 'down':
DomHandler.scrollInView(this.$refs.list, listItems[listItems.length - 1]);
break;
case 'bottom':
this.$refs.list.scrollTop = this.$refs.list.scrollHeight;
break;
default:
break;
}
}
}
},
computed: {
},
components: {
'OLButton': Button
}
}
</script>
<style>
.p-orderlist {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
}
.p-orderlist-controls-left {
flex-direction: row;
}
.p-orderlist-controls-right {
flex-direction: row-reverse;
}
.p-orderlist-controls,
.p-orderlist-list-container {
-webkit-box-flex: 0;
-ms-flex: 0 0 auto;
flex: 0 0 auto;
}
.p-orderlist-controls {
padding: 0 .25em;
width: 16.66666%;
align-self: center;
}
.p-orderlist-controls .p-button.p-button-icon-only {
display: block;
margin-bottom: 0.25em;
width: 100%;
}
.p-orderlist-list-container {
width: 83.33333%;
}
.p-orderlist-list {
list-style-type: none;
margin: 0;
padding: 0;
overflow:auto;
height: 12.5em;
}
.p-orderlist-caption {
text-align: center;
padding: .5em .75em;
border-bottom: 0 none;
}
.p-orderlist-item {
margin: 1px;
padding: .125em;
cursor: pointer;
border: 0 none;
font-weight: inherit;
}
.p-orderlist-filter-container {
position: relative;
width: 100%;
padding: .5em .6em;
border-bottom: 0 none;
}
.p-orderlist-filter-container .p-inputtext {
text-indent: 1.1em;
width: 100%;
}
.p-orderlist-filter-container .p-orderlist-filter-icon {
position: absolute;
top: 50%;
left: 1em;
margin-top: -.6em;
}
.p-orderlist.p-state-disabled .p-orderlist-item,
.p-orderlist.p-state-disabled .p-button {
cursor: default;
}
.p-orderlist.p-state-disabled .p-orderlist-list {
overflow:hidden;
}
.p-orderlist .p-orderlist-droppoint {
height: 6px;
list-style-type: none;
}
@media (max-width: 767px) {
.p-orderlist-controls {
width: 100%;
text-align: center;
}
.p-orderlist .p-orderlist-list-container {
width: 100%;
}
.p-orderlist .p-orderlist-controls .p-button.p-button.p-button-icon-only {
display: inline-block;
width: 20%;
margin-right: .25em;
}
}
</style>

View File

@ -130,4 +130,25 @@ export default class ObjectUtils {
return false;
}
static insertIntoOrderedArray(item, index, arr, sourceArr) {
if (arr.length > 0) {
let injected = false;
for (let i = 0; i < arr.length; i++) {
let currentItemIndex = this.findIndexInList(arr[i], sourceArr);
if (currentItemIndex > index) {
arr.splice(i, 0, item);
injected = true;
break;
}
}
if (!injected) {
arr.push(item);
}
}
else {
arr.push(item);
}
}
}

View File

@ -26,6 +26,7 @@ import Listbox from './components/listbox/Listbox';
import Menu from './components/menu/Menu';
import Message from './components/message/Message';
import MultiSelect from './components/multiselect/MultiSelect';
import OrderList from './components/orderlist/OrderList';
import OverlayPanel from './components/overlaypanel/OverlayPanel';
import Paginator from './components/paginator/Paginator';
import Panel from './components/panel/Panel';
@ -87,6 +88,7 @@ Vue.component('Listbox', Listbox);
Vue.component('Menu', Menu);
Vue.component('Message', Message);
Vue.component('MultiSelect', MultiSelect);
Vue.component('OrderList', OrderList);
Vue.component('OverlayPanel', OverlayPanel);
Vue.component('Paginator', Paginator);
Vue.component('Panel', Panel);

View File

@ -240,6 +240,11 @@ export default new Router({
path: '/multiselect',
name: 'multiselect',
component: () => import('./views/multiselect/MultiSelectDemo.vue')
},
{
path: '/orderlist',
name: 'orderlist',
component: () => import('./views/orderlist/OrderListDemo.vue')
},
{
path: '/overlaypanel',

View File

@ -0,0 +1,48 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>OrderList</h1>
<p>OrderList is used to managed the order of a collection.</p>
</div>
</div>
<div class="content-section implementation">
<OrderList v-model="cars" header="List of Cars" listStyle="height:20em">
<template #header>
List of Cars
</template>
<template #item="slotProps">
<div class="p-clearfix">
<img :src="'demo/images/car/' + slotProps.item.brand + '.png'" style="display:inline-block;margin:2px 0 2px 2px" width="48">
<div style="font-size:14px;float:right;margin:15px 5px 0 0">{{slotProps.item.brand}} - {{slotProps.item.year}} - {{slotProps.item.color}}</div>
</div>
</template>
</OrderList>
</div>
<OrderListDoc />
</div>
</template>
<script>
import OrderListDoc from './OrderListDoc';
import CarService from '../../service/CarService';
export default {
data() {
return {
cars: null
}
},
carService: null,
created() {
this.carService = new CarService();
},
mounted() {
this.carService.getCarsSmall().then(data => this.cars = data);
},
components: {
'OrderListDoc': OrderListDoc
}
}
</script>

View File

@ -0,0 +1,194 @@
<template>
<div class="content-section documentation">
<TabView>
<TabPanel header="Documentation">
<h3>Import</h3>
<CodeHighlight lang="javascript">
import Panel from 'primevue/panel';
</CodeHighlight>
<h3>Getting Started</h3>
<p>Panel is a container component that accepts content as its children.</p>
<CodeHighlight>
&lt;Panel header="Godfather I"&gt;
The story begins as Don Vito Corleone, the head of a New York Mafia family, oversees his daughter's wedding.
His beloved son Michael has just come home from the war, but does not intend to become part of his father's business.
Through Michael's life the nature of the family business becomes clear. The business of the family is just like the head of the family,
kind and benevolent to those who give respect, but given to ruthless violence whenever anything stands against the good of the family.
&lt;/Panel&gt;
</CodeHighlight>
<h3>Custom Header</h3>
<p>Header of the panel is either defined with the <i>header</i> property or the header template.</p>
<CodeHighlight>
&lt;Panel&gt;
&lt;template #header&gt;
Header Content
&lt;/template&gt;
Content
&lt;/Panel&gt;
</CodeHighlight>
<h3>Toggleable</h3>
<p>Content of the panel can be expanded and collapsed using <i>toggleable</i> option.</p>
<CodeHighlight>
&lt;Panel header="Godfather I" :toggleable="true"&gt;
The story begins as Don Vito Corleone, the head of a New York Mafia family, oversees his daughter's wedding.
His beloved son Michael has just come home from the war, but does not intend to become part of his father's business.
Through Michael's life the nature of the family business becomes clear. The business of the family is just like the head of the family,
kind and benevolent to those who give respect, but given to ruthless violence whenever anything stands against the good of the family.
&lt;/Panel&gt;
</CodeHighlight>
<p>To control the initial state of the toggleable panel, use the <i>collapsed</i> property.</p>
<CodeHighlight>
&lt;Panel header="Header Text" :toggleable="true" :collapsed="true"&gt;
Content
&lt;/Panel&gt;
</CodeHighlight>
<p>Use the sync operator to enable two-way binding.</p>
<CodeHighlight>
&lt;button type="button" @click="isCollapsed = !isCollapsed">Toggle Programmatically&lt;/button&gt;
&lt;Panel header="Header Text" :toggleable="true" :collapsed.sync="isCollapsed"&gt;
Content
&lt;/Panel&gt;
</CodeHighlight>
<h3>Properties</h3>
<p>Any attribute such as style and class are passed to the main container element. Following are the additional properties to configure the component.</p>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Default</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>header</td>
<td>string</td>
<td>null</td>
<td>Header text of the panel.</td>
</tr>
<tr>
<td>toggleable</td>
<td>boolean</td>
<td>null</td>
<td>Defines if content of panel can be expanded and collapsed.</td>
</tr>
<tr>
<td>collapsed</td>
<td>boolean</td>
<td>null</td>
<td>Defines the initial state of panel content.</td>
</tr>
</tbody>
</table>
</div>
<h3>Events</h3>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Parameters</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>toggle</td>
<td>event.originalEvent: browser event <br />
event.value: collapsed state as a boolean
</td>
<td>Callback to invoke when a tab toggle.</td>
</tr>
</tbody>
</table>
</div>
<h3>Styling</h3>
<p>Following is the list of structural style classes, for theming classes visit <router-link to="/theming">theming</router-link> page.</p>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Element</th>
</tr>
</thead>
<tbody>
<tr>
<td>p-panel</td>
<td>Container element.</td>
</tr>
<tr>
<td>p-panel-titlebar</td>
<td>Header section.</td>
</tr>
<tr>
<td>p-panel-title</td>
<td>Title text of panel.</td>
</tr>
<tr>
<td>p-panel-titlebar-toggler</td>
<td>Toggle icon.</td>
</tr>
<tr>
<td>p-panel-content</td>
<td>Content of panel.</td>
</tr>
</tbody>
</table>
</div>
<h3>Dependencies</h3>
<p>None.</p>
</TabPanel>
<TabPanel header="Source">
<a href="https://github.com/primefaces/primevue/tree/master/src/views/panel" class="btn-viewsource" target="_blank" rel="noopener noreferrer">
<span>View on GitHub</span>
</a>
<CodeHighlight>
<template v-pre>
&lt;template&gt;
&lt;div&gt;
&lt;div class="content-section introduction"&gt;
&lt;div class="feature-intro"&gt;
&lt;h1&gt;Panel&lt;/h1&gt;
&lt;p&gt;Panel is a grouping component with the optional content toggle feature.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="content-section implementation"&gt;
&lt;h3 class="first"&gt;Regular&lt;/h3&gt;
&lt;Panel header="Godfather I"&gt;
The story begins as Don Vito Corleone, the head of a New York Mafia family, oversees his daughter's wedding.
His beloved son Michael has just come home from the war, but does not intend to become part of his father's business.
Through Michael's life the nature of the family business becomes clear. The business of the family is just like the head of the family,
kind and benevolent to those who give respect, but given to ruthless violence whenever anything stands against the good of the family.
&lt;/Panel&gt;
&lt;h3&gt;Toggleable&lt;/h3&gt;
&lt;Panel header="Godfather I" :toggleable="true"&gt;
The story begins as Don Vito Corleone, the head of a New York Mafia family, oversees his daughter's wedding.
His beloved son Michael has just come home from the war, but does not intend to become part of his father's business.
Through Michael's life the nature of the family business becomes clear. The business of the family is just like the head of the family,
kind and benevolent to those who give respect, but given to ruthless violence whenever anything stands against the good of the family.
&lt;/Panel&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/template&gt;
</template>
</CodeHighlight>
</TabPanel>
</TabView>
</div>
</template>