Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(sortable): module #1295

Merged
merged 22 commits into from
Jan 6, 2017
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
eddede5
Added sortable-list module
Le0Michine Dec 5, 2016
75b634f
added sortable-list module into the main module
Le0Michine Dec 5, 2016
0dca2b1
renamed sortable-list to sortable
Le0Michine Dec 6, 2016
b20bb27
removed sortable module from root index.ts
Le0Michine Dec 6, 2016
5a6553b
inlined html template
Le0Michine Dec 6, 2016
6d08383
created docs page for sortable component
Le0Michine Dec 6, 2016
556d97b
removed console.log
Le0Michine Dec 7, 2016
9db1056
added tests for reordering
Le0Michine Dec 7, 2016
7eb8e4e
added tests for onZoneDragover method
Le0Michine Dec 7, 2016
2edce40
added test for insert item from another container
Le0Michine Dec 7, 2016
65f479f
fixed quotes
Le0Michine Dec 7, 2016
40377ff
fixed insertion test
Le0Michine Dec 7, 2016
0287049
finished component covering
Le0Michine Dec 7, 2016
ca95219
Merge remote-tracking branch 'upstream/development' into development
Le0Michine Dec 8, 2016
2dfd04f
Merge remote-tracking branch 'upstream/development' into development
Le0Michine Dec 8, 2016
92ea666
Merge branch 'development' of https://github.com/Le0Michine/ng2-boots…
Le0Michine Dec 8, 2016
b1abbdf
changed dirs structure
Le0Michine Dec 18, 2016
3d37cee
use dumb object instead of Event
Le0Michine Dec 18, 2016
5b8ed5a
Merge remote-tracking branch 'upstream/development' into development
Le0Michine Dec 30, 2016
6efb630
updated docs
Le0Michine Dec 30, 2016
c469581
update docs (added doc comments)
Le0Michine Dec 30, 2016
cae3a62
fixed compatibility with firefox
Le0Michine Dec 30, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { ModalModule } from './modal/modal.module';
import { PaginationModule } from './pagination/pagination.module';
import { ProgressbarModule } from './progressbar/progressbar.module';
import { RatingModule } from './rating/rating.module';
import { SortableListModule } from './sortable-list';
import { TabsModule } from './tabs/tabs.module';
import { TimepickerModule } from './timepicker/timepicker.module';
import { TooltipModule } from './tooltip/tooltip.module';
Expand All @@ -20,7 +21,7 @@ import { ComponentsHelper } from './utils/components-helper.service';
@NgModule({
exports: [
AccordionModule, AlertModule, ButtonsModule, CarouselModule, CollapseModule, DatepickerModule, DropdownModule,
ModalModule, PaginationModule, ProgressbarModule, RatingModule, TabsModule, TimepickerModule, TooltipModule,
ModalModule, PaginationModule, ProgressbarModule, RatingModule, SortableListModule, TabsModule, TimepickerModule, TooltipModule,

This comment was marked as off-topic.

This comment was marked as off-topic.

This comment was marked as off-topic.

TypeaheadModule
],
providers: [
Expand All @@ -41,6 +42,7 @@ export * from './dropdown';
export * from './pagination';
export * from './progressbar';
export * from './rating';
export * from './sortable-list';
export * from './tabs';
export * from './timepicker';
export * from './tooltip';
Expand Down
1 change: 1 addition & 0 deletions src/sortable-list/components/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './sortable-list.component';
27 changes: 27 additions & 0 deletions src/sortable-list/components/sortable-list.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<div
[ngClass]="wrapperClass"
[ngStyle]="wrapperStyle"
[ngStyle]="wrapperStyle"
(dragover)="onZoneDragover($event)"
(drop)="resetActiveItem()"
(mouseleave)="resetActiveItem()"
>
<div
*ngIf="showPlaceholder"
[ngClass]="placeholderClass"
[ngStyle]="placeholderStyle"
(dragover)="onItemDragover($event, 0)"
>{{placeholderItem}}</div>
<div
[@flyInOut]="'in'"
(@flyInOut.done)="updatePlaceholderState()"
(@flyInOut.start)="showPlaceholder = false"
*ngFor="let item of items; let i=index;"
[ngClass]="[ itemClass, i === activeItem ? itemActiveClass : '' ]"
[ngStyle]="getItemStyle(i === activeItem)"
draggable="true"
(dragstart)="onItemDragstart($event, item, i)"
(dragend)="resetActiveItem()"
(dragover)="onItemDragover($event, i)"
>{{item.value}}</div>
</div>
167 changes: 167 additions & 0 deletions src/sortable-list/components/sortable-list.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
import { Component, Input, Output, EventEmitter, forwardRef, animate, style, state, transition, keyframes, trigger } from '@angular/core';
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';
import 'rxjs/add/operator/first';

import { DraggableItem } from '../models';
import { DraggableItemService } from '../services';

const nullCallback = (arg?: any): void => { return void 0; };

/* tslint:disable */
@Component({
selector: 'ng2-sortable-list',
templateUrl: './sortable-list.component.html',

This comment was marked as off-topic.

This comment was marked as off-topic.

This comment was marked as off-topic.

providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => SortableComponent), multi: true }],
animations: [
trigger('flyInOut', [
state('in', style({ height: '*', width: '*' })),
transition('void => *', [
style({ height: 0, width: 0 }),
animate('100ms ease-out')
]),
transition('* => void', [
style({ height: '*', width: '*' }),
animate('100ms ease-out', style({ height: 0, width: 0 }))
])
])
]
})
/* tslint:enable */
export class SortableComponent implements ControlValueAccessor {
private static globalZoneIndex: number = 0;

@Input() public fieldName: string;
@Input() public wrapperClass: string = '';
@Input() public wrapperStyle: {} = {};
@Input() public itemClass: string = '';
@Input() public itemStyle: {} = {};
@Input() public itemActiveClass: string = '';
@Input() public itemActiveStyle: {} = {};
@Input() public placeholderClass: string = '';
@Input() public placeholderStyle: {} = {};
@Input() public placeholderItem: string = '';

@Output() public onChange: EventEmitter<any[]> = new EventEmitter<any[]>();

private _items: SortableItem[];

private showPlaceholder: boolean = false;

private get items(): SortableItem[] {
return this._items;
}

private set items(value: SortableItem[]) {
this._items = value;
let out = this.items.map((x: SortableItem) => x.initData);
this.onChanged(out);
this.onChange.emit(out);
}

private onTouched: () => void = nullCallback;
private onChanged: (_: any) => void = nullCallback;

private transfer: DraggableItemService;
private currentZoneIndex: number;
private activeItem: number = -1;

public constructor(transfer: DraggableItemService) {
this.transfer = transfer;
this.currentZoneIndex = SortableComponent.globalZoneIndex++;
this.transfer.onCaptureItem().subscribe((item: DraggableItem) => this.onDrop(item));
}

public onItemDragstart(event: DragEvent, item: SortableItem, i: number): void {
this.onTouched();
this.transfer.dragStart({
event,
item,
i,
initialIndex: i,
lastZoneIndex: this.currentZoneIndex,
overZoneIndex: this.currentZoneIndex
});
}

public onItemDragover(event: DragEvent, i: number): void {
if (!this.transfer.getItem()) {
return;
}
event.preventDefault();
let dragItem = this.transfer.captureItem(this.currentZoneIndex, this.items.length);
let newArray: any[] = [];
if (!this.items.length) {
newArray = [ dragItem.item ];
} else if (dragItem.i > i) {
newArray = [
...this.items.slice(0, i),
dragItem.item,
...this.items.slice(i, dragItem.i),
...this.items.slice(dragItem.i + 1)
];
} else { // this.draggedItem.i < i
newArray = [
...this.items.slice(0, dragItem.i),
...this.items.slice(dragItem.i + 1, i + 1),
dragItem.item,
...this.items.slice(i + 1)
];
}
this.items = newArray;
dragItem.i = i;
this.activeItem = i;
}

public onZoneDragover(event: DragEvent): void {
if (!this.transfer.getItem()) {
return;
}
event.preventDefault();
}

public onDrop(item: DraggableItem): void {
if (item &&
item.overZoneIndex !== this.currentZoneIndex &&
item.lastZoneIndex === this.currentZoneIndex
) {
this.items = this.items.filter((x: SortableItem, i: number) => i !== item.i);
}
this.resetActiveItem();
}

public resetActiveItem(): void {
this.activeItem = -1;
}

public registerOnChange(callback: (_: any) => void): void {
this.onChanged = callback;
}

public registerOnTouched(callback: () => void): void {
this.onTouched = callback;
}

public writeValue(value: any[]): void {
if (value) {
this.items = value.map((x: any, i: number) => ({ id: i, initData: x, value: this.fieldName ? x[this.fieldName] : x }));
console.log('items', this.items);
} else {
this.items = [];
}
this.updatePlaceholderState();
}

public updatePlaceholderState(): void {
this.showPlaceholder = !this._items.length;
}

public getItemStyle(isActive: boolean): {} {
return isActive ? Object.assign({}, this.itemStyle, this.itemActiveStyle) : this.itemStyle;
}
}

export declare interface SortableItem {
id: number;
value: string;
initData: any;
}
1 change: 1 addition & 0 deletions src/sortable-list/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './sortable-list.module';

This comment was marked as off-topic.

8 changes: 8 additions & 0 deletions src/sortable-list/models/draggable-item.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export interface DraggableItem {
event: DragEvent;
item: any;
i: number;
initialIndex: number;
lastZoneIndex: number;
overZoneIndex: number;
}
1 change: 1 addition & 0 deletions src/sortable-list/models/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './draggable-item';
37 changes: 37 additions & 0 deletions src/sortable-list/services/draggable-item.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
import { DraggableItem } from '../models';

@Injectable()
export class DraggableItemService {
private draggableItem: DraggableItem;

private onCapture: Subject<DraggableItem> = new Subject();

public dragStart(item: DraggableItem): void {
this.draggableItem = item;
}

public getItem(): DraggableItem {
return this.draggableItem;
}

public captureItem(overZoneIndex: number, newIndex: number): DraggableItem {
if (this.draggableItem.overZoneIndex !== overZoneIndex) {
this.draggableItem.lastZoneIndex = this.draggableItem.overZoneIndex;
this.draggableItem.overZoneIndex = overZoneIndex;
this.onCapture.next(this.draggableItem);
this.draggableItem = Object.assign(
{},
this.draggableItem,
{ overZoneIndex, i: newIndex }
);
}
return this.draggableItem;
}

public onCaptureItem(): Observable<DraggableItem> {
return this.onCapture;
}
}
1 change: 1 addition & 0 deletions src/sortable-list/services/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './draggable-item.service';
22 changes: 22 additions & 0 deletions src/sortable-list/sortable-list.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { SortableComponent } from './components';
import { DraggableItemService } from './services';

@NgModule({
declarations: [
SortableComponent
],
imports: [
BrowserModule
],
exports: [
BrowserModule,
SortableComponent
],
providers: [
DraggableItemService
]
})
export class SortableListModule { }