├── .gitignore ├── README.md ├── index.ts ├── package.json └── src ├── split.directive.ts ├── split.module.ts └── splitArea.directive.ts /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | 7 | # dependencies 8 | /node_modules 9 | /bower_components 10 | 11 | # IDEs and editors 12 | /.idea 13 | /.vscode 14 | .project 15 | .classpath 16 | *.launch 17 | .settings/ 18 | 19 | # misc 20 | /.sass-cache 21 | /connect.lock 22 | /coverage/* 23 | /libpeerconnection.log 24 | npm-debug.log 25 | testem.log 26 | /typings 27 | 28 | # e2e 29 | /e2e/*.js 30 | /e2e/*.map 31 | 32 | #System Files 33 | .DS_Store 34 | Thumbs.db -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## **Deprecated library** 2 | ## **Please use [angular-split](https://github.com/bertrandg/angular-split).** 3 | 4 | # ng2-split 5 | Angular2 wrapper for [Split.js](https://github.com/nathancahill/Split.js) 6 | 7 | [![npm version](https://badge.fury.io/js/ng2-split.svg)](https://badge.fury.io/js/ng2-split) 8 | 9 | View documentation and examples: 10 | [https://bertrandg.github.io/ng2-split/](https://bertrandg.github.io/ng2-split/) 11 | -------------------------------------------------------------------------------- /index.ts: -------------------------------------------------------------------------------- 1 | export * from './src/split.module' 2 | export * from './src/split.directive' 3 | export * from './src/splitArea.directive' -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ng2-split", 3 | "version": "0.1.6", 4 | "description": "[Deprecated] Angular2 wrapper for Split.js library (http://nathancahill.github.io/Split.js/)", 5 | "main": "index.ts", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/bertrandg/ng2-split.git" 12 | }, 13 | "keywords": [ 14 | "angular2", 15 | "directive", 16 | "split", 17 | "split.js" 18 | ], 19 | "author": "bertrandg", 20 | "license": "ISC", 21 | "bugs": { 22 | "url": "https://github.com/bertrandg/ng2-split/issues" 23 | }, 24 | "homepage": "https://github.com/bertrandg/ng2-split#readme", 25 | "dependencies": { 26 | "@angular/core": "^2.1.2", 27 | "rxjs": "^5.0.0-beta.12", 28 | "split.js": "^1.1.1", 29 | "zone.js": "^0.6.21" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/split.directive.ts: -------------------------------------------------------------------------------- 1 | import { Directive, ElementRef, HostBinding, ChangeDetectionStrategy, AfterViewChecked, OnChanges, EventEmitter, Input, Output, Renderer, OnDestroy, ViewChildren } from '@angular/core'; 2 | import { Subject } from 'rxjs/Subject' 3 | import { Subscription } from 'rxjs/Subscription' 4 | import { Observable } from 'rxjs/Observable' 5 | import 'rxjs/add/operator/debounceTime' 6 | 7 | import {SplitAreaDirective, IAreaData} from './splitArea.directive' 8 | 9 | 10 | declare var Split; 11 | 12 | @Directive({ 13 | selector: 'split' 14 | }) 15 | export class SplitDirective implements OnChanges, OnDestroy { 16 | @Input() direction: string = 'horizontal' 17 | @Input() width: string 18 | @Input() height: string 19 | 20 | @Output() dragStart = new EventEmitter(false) 21 | @Output() drag = new EventEmitter(false) 22 | @Output() dragEnd = new EventEmitter(false) 23 | 24 | private areas:Array = [] 25 | private splitInstance: any 26 | private build$ = new Subject() 27 | private sub: Subscription 28 | 29 | constructor(public el: ElementRef, 30 | public renderer: Renderer) { 31 | this.sub = this.build$.debounceTime(1).subscribe(() => this.build()); 32 | } 33 | 34 | public addArea(area: IAreaData) { 35 | this.areas.push(area); 36 | this.build$.next(true); 37 | } 38 | 39 | public removeArea(area: IAreaData) { 40 | const index = this.areas.indexOf(area); 41 | if(index !== -1) { 42 | this.areas.splice(index, 1); 43 | this.build$.next(true); 44 | } 45 | } 46 | 47 | public ngOnChanges(changes) { 48 | this.renderer.setElementStyle(this.el.nativeElement, 'display', 'block'); 49 | this.renderer.setElementStyle(this.el.nativeElement, 'width', this.width && Number.isNaN(Number(this.width)) === false ? this.width+'px' : '100%'); 50 | this.renderer.setElementStyle(this.el.nativeElement, 'height', this.height && Number.isNaN(Number(this.height)) === false ? this.height+'px' : '100%'); 51 | 52 | this.build$.next(true); 53 | } 54 | 55 | private getSpecificChildren(className: string): Array { 56 | return Array.from(this.el.nativeElement.children).filter(elem => Array.from((elem as HTMLElement).classList).indexOf(className) > -1) as Array; 57 | } 58 | 59 | private destroy() { 60 | const gutters = this.getSpecificChildren('gutter'); 61 | 62 | for(let i = gutters.length - 1; i >= 0; i--) { 63 | const gutter = gutters[i]; 64 | if(gutter.parentNode) { 65 | gutter.parentNode.removeChild(gutter); 66 | } 67 | } 68 | 69 | this.splitInstance = null; 70 | } 71 | 72 | private build() { 73 | this.destroy(); 74 | 75 | if(this.areas.length === 0 || this.areas.some(a => a.element === undefined)) { 76 | return; 77 | } 78 | 79 | if(this.areas.length === 1) { 80 | this.renderer.setElementStyle(this.areas[0].element, 'width', '100%'); 81 | this.renderer.setElementStyle(this.areas[0].element, 'height', '100%'); 82 | return; 83 | } 84 | 85 | this.areas.forEach(a => this.renderer.setElementStyle(a.element, 'height', null)); 86 | 87 | // reorder areas following DOM order 88 | this.areas = this.areas.sort((a, b) => { 89 | if(a.element.previousElementSibling === null || b.element.nextElementSibling === null) return -1; 90 | if(a.element.nextElementSibling === null || b.element.previousElementSibling === null) return 1; 91 | if(a.element.nextElementSibling === b.element || b.element.previousElementSibling === a.element) return -1; 92 | if(b.element.nextElementSibling === a.element || a.element.previousElementSibling === b.element) return 1; 93 | return 0; 94 | }); 95 | 96 | // calculate sizes 97 | const validSizes = this.areas.map(a => a.size).filter(s => Number.isNaN(s) === false); 98 | let sizes; 99 | 100 | if(validSizes.length === this.areas.length && validSizes.reduce((acc, s) => acc+s, 0) === 100) { 101 | sizes = validSizes; 102 | } 103 | else { 104 | const v = 100/this.areas.length; 105 | sizes = this.areas.map(() => v); 106 | } 107 | 108 | // build split 109 | const elements = this.areas.map(a => a.element); 110 | const params = { 111 | direction: this.direction, 112 | sizes: sizes, 113 | gutterSize: 8, 114 | minSize: 10, 115 | onDragStart: () => this.dragStart.emit(null), 116 | onDrag: () => this.drag.emit(null), 117 | onDragEnd: () => { 118 | this.dragEnd.emit(null); 119 | 120 | // Split.js remove cursor after send 'onDragEnd' event (line 247) 121 | // add it again 122 | setTimeout(() => { 123 | const gutters = this.getSpecificChildren('gutter'); 124 | 125 | gutters.forEach(gutter => { 126 | if(Array.from(gutter.classList).indexOf('gutter-horizontal') > -1) { 127 | this.renderer.setElementStyle(gutter, 'cursor', 'ew-resize'); 128 | } 129 | else if(Array.from(gutter.classList).indexOf('gutter-vertical') > -1) { 130 | this.renderer.setElementStyle(gutter, 'cursor', 'ns-resize'); 131 | } 132 | }); 133 | }); 134 | } 135 | } 136 | 137 | this.splitInstance = Split(elements, params); 138 | this.addStyles(); 139 | } 140 | 141 | private addStyles() { 142 | const gutters = this.getSpecificChildren('gutter'); 143 | 144 | gutters.forEach(gutter => { 145 | this.renderer.setElementStyle(gutter, 'background-color', '#eee'); 146 | this.renderer.setElementStyle(gutter, 'background-repeat', 'no-repeat'); 147 | this.renderer.setElementStyle(gutter, 'background-position', '50%'); 148 | 149 | if(Array.from(gutter.classList).indexOf('gutter-horizontal') > -1) { 150 | this.renderer.setElementStyle(gutter, 'cursor', 'ew-resize'); 151 | this.renderer.setElementStyle(gutter, 'background-image', `url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAeCAYAAADkftS9AAAAIklEQVQoU2M4c+bMfxAGAgYYmwGrIIiDjrELjpo5aiZeMwF+yNnOs5KSvgAAAABJRU5ErkJggg=='`); 152 | this.renderer.setElementStyle(gutter, 'height', '100%'); 153 | this.renderer.setElementStyle(gutter, 'float', 'left'); 154 | } 155 | else if(Array.from(gutter.classList).indexOf('gutter-vertical') > -1) { 156 | this.renderer.setElementStyle(gutter, 'cursor', 'ns-resize'); 157 | this.renderer.setElementStyle(gutter, 'background-image', `url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAFCAMAAABl/6zIAAAABlBMVEUAAADMzMzIT8AyAAAAAXRSTlMAQObYZgAAABRJREFUeAFjYGRkwIMJSeMHlBkOABP7AEGzSuPKAAAAAElFTkSuQmCC)`); 158 | } 159 | }); 160 | 161 | const splits = this.getSpecificChildren('split'); 162 | 163 | splits.forEach(split => { 164 | this.renderer.setElementStyle(split, 'box-sizing', 'border-box'); 165 | this.renderer.setElementStyle(split, 'overflow-x', 'hidden'); 166 | this.renderer.setElementStyle(split, 'overflow-y', 'auto'); 167 | 168 | if(Array.from(split.classList).indexOf('split-horizontal') > -1) { 169 | this.renderer.setElementStyle(split, 'height', '100%'); 170 | this.renderer.setElementStyle(split, 'float', 'left'); 171 | } 172 | }) 173 | } 174 | 175 | public ngOnDestroy():void { 176 | if(this.sub) this.sub.unsubscribe(); 177 | this.destroy(); 178 | } 179 | } -------------------------------------------------------------------------------- /src/split.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core' 2 | 3 | import { SplitDirective } from './split.directive' 4 | import { SplitAreaDirective } from './splitArea.directive' 5 | 6 | @NgModule({ 7 | declarations: [ 8 | SplitDirective, 9 | SplitAreaDirective 10 | ], 11 | exports: [ 12 | SplitDirective, 13 | SplitAreaDirective 14 | ] 15 | }) 16 | export class SplitModule {} 17 | -------------------------------------------------------------------------------- /src/splitArea.directive.ts: -------------------------------------------------------------------------------- 1 | import { Directive, ElementRef, Input, Renderer, ChangeDetectionStrategy, OnInit, OnDestroy, ViewChildren, HostBinding } from '@angular/core' 2 | 3 | import {SplitDirective} from './split.directive' 4 | 5 | export interface IAreaData { 6 | element: HTMLElement 7 | size: number 8 | } 9 | 10 | 11 | @Directive({ 12 | selector: 'split-area' 13 | }) 14 | export class SplitAreaDirective implements OnInit, OnDestroy { 15 | @Input() size: number 16 | conf: IAreaData 17 | 18 | constructor(public split: SplitDirective, 19 | public el: ElementRef, 20 | public renderer: Renderer) {} 21 | 22 | public ngOnInit():void { 23 | this.renderer.setElementClass(this.el.nativeElement, 'split', true); 24 | this.renderer.setElementClass(this.el.nativeElement, 'split-horizontal', this.split.direction === 'horizontal'); 25 | this.renderer.setElementClass(this.el.nativeElement, 'split-vertical', this.split.direction === 'vertical'); 26 | 27 | this.renderer.setElementStyle(this.el.nativeElement, 'display', 'block'); 28 | this.renderer.setElementStyle(this.el.nativeElement, 'height', this.split.direction === 'horizontal' ? '100%' : null); 29 | 30 | this.conf = { 31 | element: this.el.nativeElement, 32 | size: Number(this.size) 33 | } 34 | 35 | this.split.addArea(this.conf); 36 | } 37 | 38 | public ngOnDestroy():void { 39 | this.split.removeArea(this.conf); 40 | } 41 | } --------------------------------------------------------------------------------