diff --git a/.gitignore b/.gitignore index 01cfff0..5f0524b 100755 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ demo/app/*.js demo/*.d.ts demo/platforms demo/node_modules -node_modules \ No newline at end of file +node_modules +src/README.md \ No newline at end of file diff --git a/README.md b/README.md index 86979b3..f0ddd6a 100755 --- a/README.md +++ b/README.md @@ -1,22 +1,24 @@ # NativeScript Slides for iOS and Android -### Supports {N} 2.0+ | {N} 3.0 RC3 + - [![npm](https://img.shields.io/npm/v/nativescript-slides.svg)](https://www.npmjs.com/package/nativescript-slides) [![npm](https://img.shields.io/npm/dt/nativescript-slides.svg?label=npm%20downloads)](https://www.npmjs.com/package/nativescript-slides) ### _The plugin formally known as nativescript-intro-slides_ ### Intro slides example: + [![Nativescript Slides. Click to Play](https://img.youtube.com/vi/kGby8qtSDjM/0.jpg)](https://www.youtube.com/embed/kGby8qtSDjM) ### Image carousel example: + [![Nativescript Slides. Click to Play](https://img.youtube.com/vi/RsEqGAKm62k/0.jpg)](https://www.youtube.com/embed/RsEqGAKm62k) _videos by [Brad Martin](https://github.com/bradmartin)_ ## Example Usage: + ### XML + ```xml @@ -38,40 +40,42 @@ _videos by [Brad Martin](https://github.com/bradmartin)_ ``` + ### CSS + ```css -.slide-1{ +.slide-1 { background-color: darkslateblue; } -.slide-2{ +.slide-2 { background-color: darkcyan; } -.slide-3{ +.slide-3 { background-color: darkgreen; } -.slide-4{ +.slide-4 { background-color: darkgoldenrod; } -.slide-5{ +.slide-5 { background-color: darkslategray; } -Label{ +label { text-align: center; width: 100%; font-size: 35; margin-top: 35; } - ``` + Great for Intros/Tutorials to Image Carousels. -To use the intro slide plugin you need to first import it into your xml layout with `xmlns:Slides="nativescript-slides"` +To use the intro slide plugin you need to first import it into your xml layout with `xmlns:Slides="nativescript-slides"` -when using the intro slide plugin you need at least two ```` views inside of the ````. +when using the intro slide plugin you need at least two `` views inside of the ``. -add as many ```` as you want. +add as many `` as you want. ### Methods for SlideContainer @@ -79,108 +83,108 @@ add as many ```` as you want. - **previousSlide()** - navigate to the previous slide (left direction) - **goToSlide(index)** : - goes to the slide at the specified index - ### Attributes for SlideContainer -- **loop : boolean** - If true will cause the slide to be an endless loop. The suggested use case would be for a Image Carousel or something of that nature. +- **loop : boolean** - If true will cause the slide to be an endless loop. The suggested use case would be for a Image Carousel or something of that nature. - **disablePan : boolean** - If true panning is disabled. So that you can call nextSlide()/previousSlide() functions to change the slide. If slides is used to get details about users like email, phone number, username etc. in this case you don't want users to move from one slide to another slide without filling details. -- **pagerOffset : string** - Margin-top for the pager. Number or percentage, default 88%. +- **pagerOffset : string** - Margin-top for the pager. Number or percentage, default 88%. - **pageIndicators : boolean** - If true adds indicator dots to the bottom of your slides. -- **slideWidth: number - set the width of your slides. (Only currently works on android). +- \*\*slideWidth: number - set the width of your slides. (Only currently works on android). #### Indicators If the property `pageIndicators` is `true` you won't see the page indicators anymore as of 2.0.0 right away. there are two css classes exposed that you can setup however you like for active and inactive indicators. below is an example for semi translucent dots. ```css -.slide-indicator-inactive{ - background-color: #fff; - opacity : 0.4; - width : 10; - height : 10; - margin-left : 2.5; - margin-right : 2.5; - margin-top : 0; - border-radius : 5; +.slide-indicator-inactive { + background-color: #fff; + opacity: 0.4; + width: 10; + height: 10; + margin-left: 2.5; + margin-right: 2.5; + margin-top: 0; + border-radius: 5; } -.slide-indicator-active{ - background-color: #fff; - opacity : 0.9; - width : 10; - height : 10; - margin-left : 2.5; - margin-right : 2.5; - margin-top : 0; - border-radius : 5; +.slide-indicator-active { + background-color: #fff; + opacity: 0.9; + width: 10; + height: 10; + margin-left: 2.5; + margin-right: 2.5; + margin-top: 0; + border-radius: 5; } ``` #### Events + - **start** - Start pan - **changed** - Transition complete - **cancelled** - User didn't complete the transition, or at start\end with no slides - **finished** - Last slide has come into view #### Angular 2 compatibility + I've started working on a Angular 2 version they can be checked out here: -[Angular 2 version of slides](https://github.com/TheOriginalJosh/nativescript-ng2-slides) +[Angular 2 version of slides](https://github.com/JoshDSommer/nativescript-ng2-slides) -If you want to use this plugin with Angular 2 the `registerElement` from `nativescript-angular` you will want to set the `SlideContainer`'s property of `angular` to `true`. Then in your angular component in the `ngAfterViewInit`. you will want to have an instance of your slide container to call the function `constructView()`. -[Follow the example](https://github.com/TheOriginalJosh/nativescript-slides/issues/37#issuecomment-224820901) +If you want to use this plugin with Angular 2 the `registerElement` from `nativescript-angular` you will want to set the `SlideContainer`'s property of `angular` to `true`. Then in your angular component in the `ngAfterViewInit`. you will want to have an instance of your slide container to call the function `constructView()`. +[Follow the example](https://github.com/JoshDSommer/nativescript-slides/issues/37#issuecomment-224820901) #### Plugin Development Work Flow: -* Clone repository to your machine. -* Run `npm run setup` to prepare the demo project -* Build with `npm run build` -* Run and deploy to your device or emulator with `npm run demo.android` or `npm run demo.ios` +- Clone repository to your machine. +- Run `npm run setup` to prepare the demo project +- Build with `npm run build` +- Run and deploy to your device or emulator with `npm run demo.android` or `npm run demo.ios` #### Known issues - * There appears to be a bug with the loop resulting in bad transitions going right to left. - * Currently in Android there is an known issue when a slide component inside of a scroll view. +- There appears to be a bug with the loop resulting in bad transitions going right to left. +- Currently in Android there is an known issue when a slide component inside of a scroll view. #### How To: Load slides dynamically + You want to hook into the loaded event of the view and then create your view elements. -[Demo Code](https://github.com/TheOriginalJosh/nativescript-slides/blob/master/demo/app/dynamic-page.xml) -``` xml +[Demo Code](https://github.com/JoshDSommer/nativescript-slides/blob/master/demo/app/dynamic-page.xml) + +```xml args.object; - - //Construct the slides - slideContainer.addChild(getSlide("Page 1", "slide-1")); - slideContainer.addChild(getSlide("Page 2", "slide-2")); - slideContainer.addChild(getSlide("Page 3", "slide-3")); - slideContainer.addChild(getSlide("Page 4", "slide-4")); - slideContainer.addChild(getSlide("Page 5", "slide-5")); - } +```ts +import * as slides from 'nativescript-slides/nativescript-slides'; - function getSlide(labelText: string, className: string) { - let slide = new slides.Slide(); - slide.className = className; - let label = new labelModule.Label(); - label.text = labelText; - slide.addChild(label) - - return slide; - } +export function onSlideContainerLoaded(args) { + let slideContainer = args.object; + + //Construct the slides + slideContainer.addChild(getSlide('Page 1', 'slide-1')); + slideContainer.addChild(getSlide('Page 2', 'slide-2')); + slideContainer.addChild(getSlide('Page 3', 'slide-3')); + slideContainer.addChild(getSlide('Page 4', 'slide-4')); + slideContainer.addChild(getSlide('Page 5', 'slide-5')); +} +function getSlide(labelText: string, className: string) { + let slide = new slides.Slide(); + slide.className = className; + let label = new labelModule.Label(); + label.text = labelText; + slide.addChild(label); + return slide; +} ``` - ### Thanks to these awesome contributors! [Brad Martin](https://github.com/bradmartin) @@ -203,7 +207,8 @@ And thanks to [Nathan Walker](https://github.com/NathanWalker) for setting up th https://github.com/NathanWalker/nativescript-plugin-seed ## Contributing guidelines -[Contributing guidelines](https://github.com/TheOriginalJosh/nativescript-swiss-army-knife/blob/master/CONTRIBUTING.md) + +[Contributing guidelines](https://github.com/JoshDSommer/nativescript-swiss-army-knife/blob/master/CONTRIBUTING.md) ## License diff --git a/demo/package-lock.json b/demo/package-lock.json new file mode 100644 index 0000000..7dcc74e --- /dev/null +++ b/demo/package-lock.json @@ -0,0 +1,195 @@ +{ + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "glob": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", + "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", + "dev": true, + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "nativescript-dev-typescript": { + "version": "0.7.9", + "resolved": "https://registry.npmjs.org/nativescript-dev-typescript/-/nativescript-dev-typescript-0.7.9.tgz", + "integrity": "sha512-/c/n5qvQ54qu36rSA2uyOLHmKGhcBG1UroZ8d7bjYEpNRZMG0kRgl9HBNgjA9ScaLAXakDfx8FCjxzGJ8IOqAA==", + "dev": true, + "requires": { + "nativescript-hook": "^0.2.0", + "semver": "5.5.0", + "typescript": "~3.1.1" + } + }, + "nativescript-hook": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/nativescript-hook/-/nativescript-hook-0.2.4.tgz", + "integrity": "sha1-5ZHh2a1BWotPMwnBVzFXevRKPdQ=", + "dev": true, + "requires": { + "glob": "^6.0.1", + "mkdirp": "^0.5.1" + } + }, + "nativescript-slides": { + "version": "file:../src", + "requires": { + "nativescript-dom": "^2.0.0" + }, + "dependencies": { + "nativescript-dom": { + "version": "2.0.2", + "bundled": true + }, + "tns-core-modules": { + "version": "3.4.1", + "bundled": true, + "requires": { + "tns-core-modules-widgets": "3.4.0" + } + }, + "tns-core-modules-widgets": { + "version": "3.4.0", + "bundled": true + }, + "tns-platform-declarations": { + "version": "3.4.1", + "bundled": true + }, + "typescript": { + "version": "2.9.2", + "bundled": true + } + } + }, + "nativescript-theme-core": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/nativescript-theme-core/-/nativescript-theme-core-1.0.4.tgz", + "integrity": "sha1-zyiAx/vy/l9D4iNdMJdQeQgD7+E=" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "s": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/s/-/s-0.1.1.tgz", + "integrity": "sha1-bfd3XSqyF2/xMZE/Qn7dtDAvrAw=" + }, + "semver": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", + "dev": true + }, + "tns-core-modules": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/tns-core-modules/-/tns-core-modules-5.1.2.tgz", + "integrity": "sha512-3+jTO/KFs07MMNom2rApIfhTY8B8xffHXJVjLVNB1hOIu6e28QM89cWx++e+1zDSIfY7MEMVfvBsbbZ3OgXPxw==", + "requires": { + "tns-core-modules-widgets": "5.1.2", + "tslib": "^1.9.3" + } + }, + "tns-core-modules-widgets": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/tns-core-modules-widgets/-/tns-core-modules-widgets-5.1.2.tgz", + "integrity": "sha512-Pga3hcC2nWsERG/817AEACoVww+RuYyoDJk6w+FK+drW9TnkFbz4zkT3R65mfvwbi29ncvN81EIPuUQsLEl4BQ==" + }, + "tslib": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", + "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==" + }, + "typescript": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.1.6.tgz", + "integrity": "sha512-tDMYfVtvpb96msS1lDX9MEdHrW4yOuZ4Kdc4Him9oU796XldPYF/t2+uKoX0BBa0hXXwDlqYQbXY5Rzjzc5hBA==", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + } + } +} diff --git a/demo/package.json b/demo/package.json index 956bffa..4127759 100644 --- a/demo/package.json +++ b/demo/package.json @@ -4,14 +4,18 @@ "readme": "NativeScript Application", "repository": "", "nativescript": { - "id": "org.nativescript.demo" + "id": "org.nativescript.demo", + "tns-ios": { + "version": "5.1.1" + } }, "dependencies": { + "nativescript-slides": "file:../src", "nativescript-theme-core": "~1.0.2", - "tns-core-modules": "~3.1.0" + "tns-core-modules": "~5.1.2" }, "devDependencies": { - "nativescript-dev-typescript": "~0.5.0", - "typescript": "~2.2.1" + "nativescript-dev-typescript": "~0.7.9", + "typescript": "~3.1.1" } } diff --git a/demo/tsconfig.json b/demo/tsconfig.json index 2289232..8705301 100644 --- a/demo/tsconfig.json +++ b/demo/tsconfig.json @@ -15,6 +15,9 @@ "*": [ "./node_modules/tns-core-modules/*", "./node_modules/*" + ], + "~/*": [ + "app/*" ] } }, diff --git a/nativescript-slides.ts b/nativescript-slides.ts deleted file mode 100755 index 82cb973..0000000 --- a/nativescript-slides.ts +++ /dev/null @@ -1,635 +0,0 @@ -require("nativescript-dom"); -import * as app from 'application'; -import * as Platform from 'platform'; -import utils = require('utils/utils'); -import { AbsoluteLayout } from 'ui/layouts/absolute-layout'; -import { StackLayout } from 'ui/layouts/stack-layout'; -import { View } from 'ui/core/view'; -import { Button } from 'ui/button'; -import { Label } from 'ui/label'; -import * as AnimationModule from 'ui/animation'; -import * as gestures from 'ui/gestures'; -import { AnimationCurve, Orientation } from 'ui/enums'; -import { Color } from 'color'; -import { Image } from 'ui/image'; - -declare const android: any; -declare const com: any; -declare const java: any; -const SLIDE_INDICATOR_INACTIVE = 'slide-indicator-inactive'; -const SLIDE_INDICATOR_ACTIVE = 'slide-indicator-active'; -const SLIDE_INDICATOR_WRAP = 'slide-indicator-wrap'; -let LayoutParams: any; -if (app.android) { - LayoutParams = android.view.WindowManager.LayoutParams; -} else { - LayoutParams = {}; -} - -export class Slide extends StackLayout { } - -enum direction { - none, - left, - right -} - -enum cancellationReason { - user, - noPrevSlides, - noMoreSlides -} - -export interface ISlideMap { - panel: StackLayout; - index: number; - left?: ISlideMap; - right?: ISlideMap; -} - -export class SlideContainer extends AbsoluteLayout { - private currentPanel: ISlideMap; - private transitioning: boolean; - private direction: direction = direction.none; - private _loaded: boolean; - private _pageWidth: number; - private _loop: boolean; - private _pagerOffset: string; - private _angular: boolean; - private _disablePan: boolean; - private _footer: StackLayout; - private _pageIndicators: boolean; - private _slideMap: ISlideMap[]; - private _slideWidth: string; - - public static startEvent = 'start'; - public static changedEvent = 'changed'; - public static cancelledEvent = 'cancelled'; - public static finishedEvent = 'finished'; - - /* page indicator stuff*/ - get pageIndicators(): boolean { - return this._pageIndicators; - } - set pageIndicators(value: boolean) { - if (typeof value === 'string') { - value = (value == 'true'); - } - this._pageIndicators = value; - } - - get pagerOffset(): string { - return this._pagerOffset; - } - set pagerOffset(value: string) { - this._pagerOffset = value; - } - - get hasNext(): boolean { - return !!this.currentPanel && !!this.currentPanel.right; - } - get hasPrevious(): boolean { - return !!this.currentPanel && !!this.currentPanel.left; - } - - get loop() { - return this._loop; - } - - set loop(value: boolean) { - this._loop = value; - } - - get disablePan() { - return this._disablePan; - } - - set disablePan(value: boolean) { - this._disablePan = value; - } - - get pageWidth() { - if (!this.slideWidth) { - return Platform.screen.mainScreen.widthDIPs; - } - return +this.slideWidth; - } - - get angular(): boolean { - return this._angular; - } - - set angular(value: boolean) { - this._angular = value; - } - - get currentIndex(): number { - return this.currentPanel.index; - } - - get slideWidth(): string { - return this._slideWidth; - } - set slideWidth(width: string) { - this._slideWidth = width; - } - - constructor() { - super(); - this.setupDefaultValues(); - // if being used in an ng2 app we want to prevent it from excuting the constructView - // until it is called manually in ngAfterViewInit. - - this.constructView(true); - } - - private setupDefaultValues(): void { - this.clipToBounds = true; - - - this._loaded = false; - if (this._loop == null) { - this.loop = false; - } - - this.transitioning = false; - - if (this._disablePan == null) { - this.disablePan = false; - } - - if (this._angular == null) { - this.angular = false; - } - - if (this._pageIndicators == null) { - this._pageIndicators = false; - } - - if (this._pagerOffset == null) { - this._pagerOffset = '88%'; //defaults to white. - } - } - - public constructView(constructor: boolean = false): void { - this.on(AbsoluteLayout.loadedEvent, (data: any) => { - //// console.log('LOADDED EVENT'); - if (!this._loaded) { - this._loaded = true; - if (this.angular === true && constructor === true) { - return; - } - - let slides: StackLayout[] = []; - - if (!this.slideWidth) { - this.slideWidth = this.pageWidth; - } - this.width = +(this.slideWidth); - - this.eachLayoutChild((view: View) => { - if (view instanceof StackLayout) { - AbsoluteLayout.setLeft(view, this.pageWidth); - view.width = this.pageWidth; - (view).height = '100%'; //get around compiler - slides.push(view); - } - }); - - if (this.pageIndicators) { - this._footer = this.buildFooter(slides.length, 0); - this.setActivePageIndicator(0); - this.insertChild(this._footer, this.getChildrenCount()); - } - - this.currentPanel = this.buildSlideMap(slides); - if (this.currentPanel) { - - this.positionPanels(this.currentPanel); - - if (this.disablePan === false) { - this.applySwipe(this.pageWidth); - } - if (app.ios) { - this.ios.clipsToBound = true; - } - //handles application orientation change - app.on(app.orientationChangedEvent, (args: app.OrientationChangedEventData) => { - //event and page orientation didn't seem to alwasy be on the same page so setting it in the time out addresses this. - setTimeout(() => { - // console.log('orientationChangedEvent'); - this.width = parseInt(this.slideWidth); - this.eachLayoutChild((view: View) => { - if (view instanceof StackLayout) { - AbsoluteLayout.setLeft(view, this.pageWidth); - view.width = this.pageWidth; - } - }); - - if (this.disablePan === false) { - this.applySwipe(this.pageWidth); - } - - if (this.pageIndicators) { - AbsoluteLayout.setTop(this._footer, 0); - var pageIndicatorsLeftOffset = this.pageWidth / 4; - AbsoluteLayout.setLeft(this._footer, pageIndicatorsLeftOffset); - this._footer.width = this.pageWidth / 2; - this._footer.marginTop = this._pagerOffset; - } - - this.positionPanels(this.currentPanel); - }, 0); - }); - } - } - }); - } - - public nextSlide(): void { - if (!this.hasNext) { - this.triggerCancelEvent(cancellationReason.noMoreSlides); - return; - } - - this.direction = direction.left; - this.transitioning = true; - this.triggerStartEvent(); - this.showRightSlide(this.currentPanel).then(() => { - this.setupPanel(this.currentPanel.right); - this.triggerChangeEventRightToLeft(); - }); - } - public previousSlide(): void { - if (!this.hasPrevious) { - this.triggerCancelEvent(cancellationReason.noPrevSlides); - return; - } - - this.direction = direction.right; - this.transitioning = true; - this.triggerStartEvent(); - this.showLeftSlide(this.currentPanel).then(() => { - this.setupPanel(this.currentPanel.left); - this.triggerChangeEventLeftToRight(); - }); - } - - private setupPanel(panel: ISlideMap) { - this.direction = direction.none; - this.transitioning = false; - this.currentPanel.panel.off('pan'); - this.currentPanel = panel; - - // sets up each panel so that they are positioned to transition either way. - this.positionPanels(this.currentPanel); - - if (this.disablePan === false) { - this.applySwipe(this.pageWidth); - } - - if (this.pageIndicators) { - this.setActivePageIndicator(this.currentPanel.index); - } - } - - private positionPanels(panel: ISlideMap) { - // sets up each panel so that they are positioned to transition either way. - if (panel.left != null) { - panel.left.panel.translateX = -this.pageWidth * 2; - } - panel.panel.translateX = -this.pageWidth; - if (panel.right != null) { - panel.right.panel.translateX = 0; - } - } - - public goToSlide(index: number): void { - if (this._slideMap && this._slideMap.length > 0 && index < this._slideMap.length) { - let previousSlide = this.currentPanel; - - this.setupPanel(this._slideMap[index]); - - this.notify({ - eventName: SlideContainer.changedEvent, - object: this, - eventData: { - direction: direction.none, - newIndex: this.currentPanel.index, - oldIndex: previousSlide.index, - } - }); - } else { - // console.log('invalid index'); - } - } - - public applySwipe(pageWidth: number): void { - let previousDelta = -1; //hack to get around ios firing pan event after release - let endingVelocity = 0; - let startTime, deltaTime; - - this.currentPanel.panel.on('pan', (args: gestures.PanGestureEventData): void => { - if (args.state === gestures.GestureStateTypes.began) { - startTime = Date.now(); - previousDelta = 0; - endingVelocity = 250; - - this.triggerStartEvent(); - } else if (args.state === gestures.GestureStateTypes.ended) { - deltaTime = Date.now() - startTime; - // if velocityScrolling is enabled then calculate the velocitty - - // swiping left to right. - if (args.deltaX > (pageWidth / 3)) { - if (this.hasPrevious) { - this.transitioning = true; - this.showLeftSlide(this.currentPanel, args.deltaX, endingVelocity).then(() => { - this.setupPanel(this.currentPanel.left); - - this.triggerChangeEventLeftToRight(); - }); - } else { - //We're at the start - //Notify no more slides - this.triggerCancelEvent(cancellationReason.noPrevSlides); - } - return; - } - // swiping right to left - else if (args.deltaX < (-pageWidth / 3)) { - if (this.hasNext) { - this.transitioning = true; - this.showRightSlide(this.currentPanel, args.deltaX, endingVelocity).then(() => { - this.setupPanel(this.currentPanel.right); - - // Notify changed - this.triggerChangeEventRightToLeft(); - - if (!this.hasNext) { - // Notify finsihed - this.notify({ - eventName: SlideContainer.finishedEvent, - object: this - }); - } - }); - } else { - // We're at the end - // Notify no more slides - this.triggerCancelEvent(cancellationReason.noMoreSlides); - } - return; - } - - if (this.transitioning === false) { - //Notify cancelled - this.triggerCancelEvent(cancellationReason.user); - this.transitioning = true; - this.currentPanel.panel.animate({ - translate: { x: -this.pageWidth, y: 0 }, - duration: 200, - curve: AnimationCurve.easeOut - }); - if (this.hasNext) { - this.currentPanel.right.panel.animate({ - translate: { x: 0, y: 0 }, - duration: 200, - curve: AnimationCurve.easeOut - }); - if (app.ios) //for some reason i have to set these in ios or there is some sort of bounce back. - this.currentPanel.right.panel.translateX = 0; - } - if (this.hasPrevious) { - this.currentPanel.left.panel.animate({ - translate: { x: -this.pageWidth * 2, y: 0 }, - duration: 200, - curve: AnimationCurve.easeOut - }); - if (app.ios) - this.currentPanel.left.panel.translateX = -this.pageWidth; - - } - if (app.ios) - this.currentPanel.panel.translateX = -this.pageWidth; - - this.transitioning = false; - } - } else { - if (!this.transitioning - && previousDelta !== args.deltaX - && args.deltaX != null - && args.deltaX < 0) { - - if (this.hasNext) { - this.direction = direction.left; - this.currentPanel.panel.translateX = args.deltaX - this.pageWidth; - this.currentPanel.right.panel.translateX = args.deltaX; - - } - } else if (!this.transitioning - && previousDelta !== args.deltaX - && args.deltaX != null - && args.deltaX > 0) { - - if (this.hasPrevious) { - this.direction = direction.right; - this.currentPanel.panel.translateX = args.deltaX - this.pageWidth; - this.currentPanel.left.panel.translateX = -(this.pageWidth * 2) + args.deltaX; - } - } - - if (args.deltaX !== 0) { - previousDelta = args.deltaX; - } - - } - }); - } - - private showRightSlide(panelMap: ISlideMap, offset: number = this.pageWidth, endingVelocity: number = 32): AnimationModule.AnimationPromise { - let animationDuration: number; - animationDuration = 300; // default value - - let transition = new Array(); - - transition.push({ - target: panelMap.right.panel, - translate: { x: -this.pageWidth, y: 0 }, - duration: animationDuration, - curve: AnimationCurve.easeOut - }); - transition.push({ - target: panelMap.panel, - translate: { x: -this.pageWidth * 2, y: 0 }, - duration: animationDuration, - curve: AnimationCurve.easeOut - }); - let animationSet = new AnimationModule.Animation(transition, false); - - return animationSet.play(); - } - - private showLeftSlide(panelMap: ISlideMap, offset: number = this.pageWidth, endingVelocity: number = 32): AnimationModule.AnimationPromise { - - let animationDuration: number; - animationDuration = 300; // default value - let transition = new Array(); - - transition.push({ - target: panelMap.left.panel, - translate: { x: -this.pageWidth, y: 0 }, - duration: animationDuration, - curve: AnimationCurve.easeOut - }); - transition.push({ - target: panelMap.panel, - translate: { x: 0, y: 0 }, - duration: animationDuration, - curve: AnimationCurve.easeOut - }); - let animationSet = new AnimationModule.Animation(transition, false); - - return animationSet.play(); - - } - - private buildFooter(pageCount: number = 5, activeIndex: number = 0): StackLayout { - let footerInnerWrap = new StackLayout(); - - //footerInnerWrap.height = 50; - footerInnerWrap.clipToBounds = false; - footerInnerWrap.className = SLIDE_INDICATOR_WRAP; - - - AbsoluteLayout.setTop(footerInnerWrap, 0); - - footerInnerWrap.orientation = 'horizontal'; - footerInnerWrap.horizontalAlignment = 'center'; - footerInnerWrap.width = this.pageWidth / 2; - - let index = 0; - while (index < pageCount) { - footerInnerWrap.addChild(this.createIndicator(index)); - index++; - } - - let pageIndicatorsLeftOffset = this.pageWidth / 4; - AbsoluteLayout.setLeft(footerInnerWrap, pageIndicatorsLeftOffset); - footerInnerWrap.marginTop = this._pagerOffset; - - return footerInnerWrap; - } - - private setwidthPercent(view: View, percentage: number) { - (view).width = percentage + '%'; - } - - private newFooterButton(name: string): Button { - let button = new Button(); - button.id = 'btn-info-' + name.toLowerCase(); - button.text = name; - this.setwidthPercent(button, 100); - return button; - } - - private buildSlideMap(views: StackLayout[]) { - this._slideMap = []; - views.forEach((view: StackLayout, index: number) => { - this._slideMap.push({ - panel: view, - index: index, - }); - }); - this._slideMap.forEach((mapping: ISlideMap, index: number) => { - if (this._slideMap[index - 1] != null) - mapping.left = this._slideMap[index - 1]; - if (this._slideMap[index + 1] != null) - mapping.right = this._slideMap[index + 1]; - }); - - if (this.loop) { - this._slideMap[0].left = this._slideMap[this._slideMap.length - 1]; - this._slideMap[this._slideMap.length - 1].right = this._slideMap[0]; - } - return this._slideMap[0]; - } - - private triggerStartEvent() { - this.notify({ - eventName: SlideContainer.startEvent, - object: this, - eventData: { - currentIndex: this.currentPanel.index - } - }); - } - - private triggerChangeEventLeftToRight() { - this.notify({ - eventName: SlideContainer.changedEvent, - object: this, - eventData: { - direction: direction.left, - newIndex: this.currentPanel.index, - oldIndex: this.currentPanel.index + 1 - } - }); - } - - private triggerChangeEventRightToLeft() { - this.notify({ - eventName: SlideContainer.changedEvent, - object: this, - eventData: { - direction: direction.right, - newIndex: this.currentPanel.index, - oldIndex: this.currentPanel.index - 1 - } - }); - } - - private triggerCancelEvent(cancelReason: cancellationReason) { - this.notify({ - eventName: SlideContainer.cancelledEvent, - object: this, - eventData: { - currentIndex: this.currentPanel.index, - reason: cancelReason - } - }); - } - - createIndicator(index: number): Label { - let indicator = new Label(); - - (indicator).classList.add(SLIDE_INDICATOR_INACTIVE); - return indicator; - } - - setActivePageIndicator(index: number) { - let indicatorsToDeactivate = (this._footer).getElementsByClassName(SLIDE_INDICATOR_ACTIVE); - - indicatorsToDeactivate.forEach(activeIndicator => { - activeIndicator.classList.remove(SLIDE_INDICATOR_ACTIVE); - activeIndicator.classList.add(SLIDE_INDICATOR_INACTIVE); - }); - - let activeIndicator = (this._footer).getElementsByClassName(SLIDE_INDICATOR_INACTIVE)[index]; - if (activeIndicator) { - activeIndicator.classList.remove(SLIDE_INDICATOR_INACTIVE); - activeIndicator.classList.add(SLIDE_INDICATOR_ACTIVE); - } - - } - - iosProperty(theClass, theProperty) { - if (typeof theProperty === "function") { - // xCode 7 and below - return theProperty.call(theClass); - } else { - // xCode 8+ - return theProperty; - } - } -} diff --git a/package.json b/package.json index 225a4f0..dd148a9 100644 --- a/package.json +++ b/package.json @@ -1,71 +1,26 @@ { "name": "nativescript-slides", - "version": "2.2.10", - "description": "NativeScript Slides plugin.", - "main": "nativescript-slides", + "version": "1.0.0", + "description": "[![npm](https://img.shields.io/npm/v/nativescript-slides.svg)](https://www.npmjs.com/package/nativescript-slides) [![npm](https://img.shields.io/npm/dt/nativescript-slides.svg?label=npm%20downloads)](https://www.npmjs.com/package/nativescript-slides)", + "main": "index.js", + "dependencies": {}, + "devDependencies": {}, "scripts": { "build": "tsc", - "demo.ios": "npm run preparedemo && cd demo && tns run ios", - "demo.android": "npm run preparedemo && cd demo && tns run android", - "preparedemo": "npm run build && cd demo && npm install .. --save", - "setup": "npm install && cd demo && npm install && cd .. && npm run build && cd demo && tns plugin add .. && cd ..", - "ios": "xcproj --project platforms/ios/YourApp.xcodeproj touch; xcproj --project platforms/ios/Pods/Pods.xcodeproj touch; tns livesync ios --emulator --watch" + "demo.ios": "cd src && npm run demo.ios", + "demo.android": "cd src && npm run demo.android", + "preparedemo": "cd src && npm run preparedemo", + "setup": "cd src && npm run setup", + "ios": "cd src && npm run ios" }, "repository": { "type": "git", - "url": "https://github.com/TheOriginalJosh/nativescript-slides.git" + "url": "git+https://github.com/TheOriginalJosh/nativescript-slides.git" }, - "keywords": [ - "NativeScript", - "JavaScript", - "Android", - "iOS", - "TypeScript", - "swipe slides", - "Slides", - "Carousel" - ], - "author": { - "name": "Josh Sommer", - "email": "joshdsommer@gmail.com" - }, - "contributors": [ - { - "name": "Brad Martin", - "email": "bradwaynemartin@gmail.com", - "url": "https://github.com/bradmartin" - }, - { - "name": "Obsessive Inc/Abhijith Reddy", - "email": "mabhijith95a10@gmail.com", - "url": "https://github.com/Obsessive" - }, - { - "name": "Victor Nascimento", - "email": "victormota15@gmail.com", - "url": "https://github.com/vjoao" - }, - { - "name": "Steve McNiven-Scott", - "email": "steve@sitefinitysteve.com", - "url": "https://github.com/sitefinitysteve" - } - ], + "author": "", + "license": "ISC", "bugs": { "url": "https://github.com/TheOriginalJosh/nativescript-slides/issues" }, - "license": { - "type": "MIT", - "url": "https://github.com/TheOriginalJosh/nativescript-slides/blob/master/LICENSE" - }, - "homepage": "https://github.com/TheOriginalJosh/nativescript-slides", - "readmeFilename": "README.md", - "devDependencies": { - "typescript": "^2.2.2", - "tns-platform-declarations": "^3.0.1", - "tns-core-modules": "^3.0.1" - }, - "dependencies": { - "nativescript-dom": "^2.0.0" - } -} \ No newline at end of file + "homepage": "https://github.com/TheOriginalJosh/nativescript-slides#readme" +} diff --git a/.npmignore b/src/.npmignore similarity index 100% rename from .npmignore rename to src/.npmignore diff --git a/nativescript-slides.d.ts b/src/nativescript-slides.d.ts similarity index 100% rename from nativescript-slides.d.ts rename to src/nativescript-slides.d.ts diff --git a/src/nativescript-slides.ts b/src/nativescript-slides.ts new file mode 100755 index 0000000..e6279b3 --- /dev/null +++ b/src/nativescript-slides.ts @@ -0,0 +1,678 @@ +require('nativescript-dom'); +import * as app from 'application'; +import * as Platform from 'platform'; +import * as utils from 'tns-core-modules/utils/utils'; +import { AbsoluteLayout } from 'ui/layouts/absolute-layout'; +import { StackLayout } from 'ui/layouts/stack-layout'; +import { View } from 'ui/core/view'; +import { Button } from 'ui/button'; +import { Label } from 'ui/label'; +import * as AnimationModule from 'ui/animation'; +import * as gestures from 'ui/gestures'; +import { AnimationCurve, Orientation } from 'ui/enums'; +import { Color } from 'color'; +import { Image } from 'ui/image'; + +declare const android: any; +declare const com: any; +declare const java: any; +const SLIDE_INDICATOR_INACTIVE = 'slide-indicator-inactive'; +const SLIDE_INDICATOR_ACTIVE = 'slide-indicator-active'; +const SLIDE_INDICATOR_WRAP = 'slide-indicator-wrap'; +let LayoutParams: any; +if (app.android) { + LayoutParams = android.view.WindowManager.LayoutParams; +} else { + LayoutParams = {}; +} + +export class Slide extends StackLayout {} + +enum direction { + none, + left, + right +} + +enum cancellationReason { + user, + noPrevSlides, + noMoreSlides +} + +export interface ISlideMap { + panel: StackLayout; + index: number; + left?: ISlideMap; + right?: ISlideMap; +} + +export class SlideContainer extends AbsoluteLayout { + private currentPanel: ISlideMap; + private transitioning: boolean = false; + private direction: direction = direction.none; + private _loaded: boolean; + private _pageWidth: number; + private _loop: boolean; + private _pagerOffset: string; + private _angular: boolean; + private _disablePan: boolean; + private _footer: StackLayout; + private _pageIndicators: boolean; + private _slideMap: ISlideMap[]; + private _slideWidth: string; + + public static startEvent = 'start'; + public static changedEvent = 'changed'; + public static cancelledEvent = 'cancelled'; + public static finishedEvent = 'finished'; + + /* page indicator stuff*/ + get pageIndicators(): boolean { + return this._pageIndicators; + } + set pageIndicators(value: boolean) { + if (typeof value === 'string') { + value = value == 'true'; + } + this._pageIndicators = value; + } + + get pagerOffset(): string { + return this._pagerOffset; + } + set pagerOffset(value: string) { + this._pagerOffset = value; + } + + get hasNext(): boolean { + return !!this.currentPanel && !!this.currentPanel.right; + } + get hasPrevious(): boolean { + return !!this.currentPanel && !!this.currentPanel.left; + } + + get loop() { + return this._loop; + } + + set loop(value: boolean) { + this._loop = value; + } + + get disablePan() { + return this._disablePan; + } + + set disablePan(value: boolean) { + if (this._disablePan === value) { + return; + } // Value did not change + + this._disablePan = value; + if (this._loaded && this.currentPanel.panel !== undefined) { + if (value === true) { + this.currentPanel.panel.off('pan'); + } else if (value === false) { + this.applySwipe(this.pageWidth); + } + } + } + + get pageWidth() { + if (!this.slideWidth) { + return Platform.screen.mainScreen.widthDIPs; + } + return +this.slideWidth; + } + + get angular(): boolean { + return this._angular; + } + + set angular(value: boolean) { + this._angular = value; + } + + get currentIndex(): number { + return this.currentPanel.index; + } + + get slideWidth(): string { + return this._slideWidth; + } + set slideWidth(width: string) { + this._slideWidth = width; + } + + constructor() { + super(); + this.setupDefaultValues(); + // if being used in an ng2 app we want to prevent it from excuting the constructView + // until it is called manually in ngAfterViewInit. + + this.constructView(true); + } + + private setupDefaultValues(): void { + this.clipToBounds = true; + + this._loaded = false; + if (this._loop == null) { + this.loop = false; + } + + this.transitioning = false; + + if (this._disablePan == null) { + this.disablePan = false; + } + + if (this._angular == null) { + this.angular = false; + } + + if (this._pageIndicators == null) { + this._pageIndicators = false; + } + + if (this._pagerOffset == null) { + this._pagerOffset = '88%'; //defaults to white. + } + } + + public constructView(constructor: boolean = false): void { + this.on(AbsoluteLayout.loadedEvent, (data: any) => { + //// console.log('LOADDED EVENT'); + if (!this._loaded) { + this._loaded = true; + if (this.angular === true && constructor === true) { + return; + } + + let slides: StackLayout[] = []; + + if (!this.slideWidth) { + this.slideWidth = this.pageWidth; + } + this.width = +this.slideWidth; + + this.eachLayoutChild((view: View) => { + if (view instanceof StackLayout) { + AbsoluteLayout.setLeft(view, this.pageWidth); + view.width = this.pageWidth; + (view).height = '100%'; //get around compiler + slides.push(view); + } + }); + + if (this.pageIndicators) { + this._footer = this.buildFooter(slides.length, 0); + this.setActivePageIndicator(0); + this.insertChild(this._footer, this.getChildrenCount()); + } + + this.currentPanel = this.buildSlideMap(slides); + if (this.currentPanel) { + this.positionPanels(this.currentPanel); + + if (this.disablePan === false) { + this.applySwipe(this.pageWidth); + } + if (app.ios) { + this.ios.clipsToBound = true; + } + //handles application orientation change + app.on( + app.orientationChangedEvent, + (args: app.OrientationChangedEventData) => { + //event and page orientation didn't seem to alwasy be on the same page so setting it in the time out addresses this. + setTimeout(() => { + // console.log('orientationChangedEvent'); + this.width = parseInt(this.slideWidth); + this.eachLayoutChild((view: View) => { + if (view instanceof StackLayout) { + AbsoluteLayout.setLeft(view, this.pageWidth); + view.width = this.pageWidth; + } + }); + + if (this.disablePan === false) { + this.applySwipe(this.pageWidth); + } + + if (this.pageIndicators) { + AbsoluteLayout.setTop(this._footer, 0); + var pageIndicatorsLeftOffset = this.pageWidth / 4; + AbsoluteLayout.setLeft( + this._footer, + pageIndicatorsLeftOffset + ); + this._footer.width = this.pageWidth / 2; + this._footer.marginTop = this._pagerOffset; + } + + this.positionPanels(this.currentPanel); + }, 0); + } + ); + } + } + }); + } + + public nextSlide(): void { + if (!this.hasNext) { + this.triggerCancelEvent(cancellationReason.noMoreSlides); + return; + } + + this.direction = direction.left; + this.transitioning = true; + this.triggerStartEvent(); + this.showRightSlide(this.currentPanel).then(() => { + this.setupPanel(this.currentPanel.right); + this.triggerChangeEventRightToLeft(); + }); + } + public previousSlide(): void { + if (!this.hasPrevious) { + this.triggerCancelEvent(cancellationReason.noPrevSlides); + return; + } + + this.direction = direction.right; + this.transitioning = true; + this.triggerStartEvent(); + this.showLeftSlide(this.currentPanel).then(() => { + this.setupPanel(this.currentPanel.left); + this.triggerChangeEventLeftToRight(); + }); + } + + private setupPanel(panel: ISlideMap) { + this.direction = direction.none; + this.transitioning = false; + this.currentPanel.panel.off('pan'); + this.currentPanel = panel; + + // sets up each panel so that they are positioned to transition either way. + this.positionPanels(this.currentPanel); + + if (this.disablePan === false) { + this.applySwipe(this.pageWidth); + } + + if (this.pageIndicators) { + this.setActivePageIndicator(this.currentPanel.index); + } + } + + private positionPanels(panel: ISlideMap) { + // sets up each panel so that they are positioned to transition either way. + if (panel.left != null) { + panel.left.panel.translateX = -this.pageWidth * 2; + } + panel.panel.translateX = -this.pageWidth; + if (panel.right != null) { + panel.right.panel.translateX = 0; + } + } + + public goToSlide(index: number): void { + if ( + this._slideMap && + this._slideMap.length > 0 && + index < this._slideMap.length + ) { + let previousSlide = this.currentPanel; + + this.setupPanel(this._slideMap[index]); + + this.notify({ + eventName: SlideContainer.changedEvent, + object: this, + eventData: { + direction: direction.none, + newIndex: this.currentPanel.index, + oldIndex: previousSlide.index + } + }); + } else { + // console.log('invalid index'); + } + } + + public applySwipe(pageWidth: number): void { + let previousDelta = -1; //hack to get around ios firing pan event after release + let endingVelocity = 0; + let startTime, deltaTime; + + this.currentPanel.panel.on( + 'pan', + (args: gestures.PanGestureEventData): void => { + if (args.state === gestures.GestureStateTypes.began) { + startTime = Date.now(); + previousDelta = 0; + endingVelocity = 250; + + this.triggerStartEvent(); + } else if (args.state === gestures.GestureStateTypes.ended) { + deltaTime = Date.now() - startTime; + // if velocityScrolling is enabled then calculate the velocitty + + // swiping left to right. + if (args.deltaX > pageWidth / 3) { + if (this.hasPrevious) { + this.transitioning = true; + this.showLeftSlide( + this.currentPanel, + args.deltaX, + endingVelocity + ).then(() => { + this.setupPanel(this.currentPanel.left); + + this.triggerChangeEventLeftToRight(); + }); + } else { + //We're at the start + //Notify no more slides + this.triggerCancelEvent(cancellationReason.noPrevSlides); + } + return; + } + // swiping right to left + else if (args.deltaX < -pageWidth / 3) { + if (this.hasNext) { + this.transitioning = true; + this.showRightSlide( + this.currentPanel, + args.deltaX, + endingVelocity + ).then(() => { + this.setupPanel(this.currentPanel.right); + + // Notify changed + this.triggerChangeEventRightToLeft(); + + if (!this.hasNext) { + // Notify finsihed + this.notify({ + eventName: SlideContainer.finishedEvent, + object: this + }); + } + }); + } else { + // We're at the end + // Notify no more slides + this.triggerCancelEvent(cancellationReason.noMoreSlides); + } + return; + } + + if (this.transitioning === false) { + //Notify cancelled + this.triggerCancelEvent(cancellationReason.user); + this.transitioning = true; + this.currentPanel.panel.animate({ + translate: { x: -this.pageWidth, y: 0 }, + duration: 200, + curve: AnimationCurve.easeOut + }); + if (this.hasNext) { + this.currentPanel.right.panel.animate({ + translate: { x: 0, y: 0 }, + duration: 200, + curve: AnimationCurve.easeOut + }); + if (app.ios) + //for some reason i have to set these in ios or there is some sort of bounce back. + this.currentPanel.right.panel.translateX = 0; + } + if (this.hasPrevious) { + this.currentPanel.left.panel.animate({ + translate: { x: -this.pageWidth * 2, y: 0 }, + duration: 200, + curve: AnimationCurve.easeOut + }); + if (app.ios) + this.currentPanel.left.panel.translateX = -this.pageWidth; + } + if (app.ios) this.currentPanel.panel.translateX = -this.pageWidth; + + this.transitioning = false; + } + } else { + if ( + !this.transitioning && + previousDelta !== args.deltaX && + args.deltaX != null && + args.deltaX < 0 + ) { + if (this.hasNext) { + this.direction = direction.left; + this.currentPanel.panel.translateX = args.deltaX - this.pageWidth; + this.currentPanel.right.panel.translateX = args.deltaX; + } + } else if ( + !this.transitioning && + previousDelta !== args.deltaX && + args.deltaX != null && + args.deltaX > 0 + ) { + if (this.hasPrevious) { + this.direction = direction.right; + this.currentPanel.panel.translateX = args.deltaX - this.pageWidth; + this.currentPanel.left.panel.translateX = + -(this.pageWidth * 2) + args.deltaX; + } + } + + if (args.deltaX !== 0) { + previousDelta = args.deltaX; + } + } + } + ); + } + + private showRightSlide( + panelMap: ISlideMap, + offset: number = this.pageWidth, + endingVelocity: number = 32 + ): AnimationModule.AnimationPromise { + let animationDuration: number; + animationDuration = 300; // default value + + let transition = new Array(); + + transition.push({ + target: panelMap.right.panel, + translate: { x: -this.pageWidth, y: 0 }, + duration: animationDuration, + curve: AnimationCurve.easeOut + }); + transition.push({ + target: panelMap.panel, + translate: { x: -this.pageWidth * 2, y: 0 }, + duration: animationDuration, + curve: AnimationCurve.easeOut + }); + let animationSet = new AnimationModule.Animation(transition, false); + + return animationSet.play(); + } + + private showLeftSlide( + panelMap: ISlideMap, + offset: number = this.pageWidth, + endingVelocity: number = 32 + ): AnimationModule.AnimationPromise { + let animationDuration: number; + animationDuration = 300; // default value + let transition = new Array(); + + transition.push({ + target: panelMap.left.panel, + translate: { x: -this.pageWidth, y: 0 }, + duration: animationDuration, + curve: AnimationCurve.easeOut + }); + transition.push({ + target: panelMap.panel, + translate: { x: 0, y: 0 }, + duration: animationDuration, + curve: AnimationCurve.easeOut + }); + let animationSet = new AnimationModule.Animation(transition, false); + + return animationSet.play(); + } + + private buildFooter( + pageCount: number = 5, + activeIndex: number = 0 + ): StackLayout { + let footerInnerWrap = new StackLayout(); + + //footerInnerWrap.height = 50; + if (app.ios) { + footerInnerWrap.clipToBounds = false; + } + footerInnerWrap.className = SLIDE_INDICATOR_WRAP; + + AbsoluteLayout.setTop(footerInnerWrap, 0); + + footerInnerWrap.orientation = 'horizontal'; + footerInnerWrap.horizontalAlignment = 'center'; + footerInnerWrap.width = this.pageWidth / 2; + + let index = 0; + while (index < pageCount) { + footerInnerWrap.addChild(this.createIndicator(index)); + index++; + } + + let pageIndicatorsLeftOffset = this.pageWidth / 4; + AbsoluteLayout.setLeft(footerInnerWrap, pageIndicatorsLeftOffset); + footerInnerWrap.marginTop = this._pagerOffset; + + return footerInnerWrap; + } + + private setwidthPercent(view: View, percentage: number) { + (view).width = percentage + '%'; + } + + private newFooterButton(name: string): Button { + let button = new Button(); + button.id = 'btn-info-' + name.toLowerCase(); + button.text = name; + this.setwidthPercent(button, 100); + return button; + } + + private buildSlideMap(views: StackLayout[]) { + this._slideMap = []; + views.forEach((view: StackLayout, index: number) => { + this._slideMap.push({ + panel: view, + index: index + }); + }); + this._slideMap.forEach((mapping: ISlideMap, index: number) => { + if (this._slideMap[index - 1] != null) + mapping.left = this._slideMap[index - 1]; + if (this._slideMap[index + 1] != null) + mapping.right = this._slideMap[index + 1]; + }); + + if (this.loop === true) { + this._slideMap[0].left = this._slideMap[this._slideMap.length - 1]; + this._slideMap[this._slideMap.length - 1].right = this._slideMap[0]; + } + return this._slideMap[0]; + } + + private triggerStartEvent() { + this.notify({ + eventName: SlideContainer.startEvent, + object: this, + eventData: { + currentIndex: this.currentPanel.index + } + }); + } + + private triggerChangeEventLeftToRight() { + this.notify({ + eventName: SlideContainer.changedEvent, + object: this, + eventData: { + direction: direction.left, + newIndex: this.currentPanel.index, + oldIndex: this.currentPanel.index + 1 + } + }); + } + + private triggerChangeEventRightToLeft() { + this.notify({ + eventName: SlideContainer.changedEvent, + object: this, + eventData: { + direction: direction.right, + newIndex: this.currentPanel.index, + oldIndex: this.currentPanel.index - 1 + } + }); + } + + private triggerCancelEvent(cancelReason: cancellationReason) { + this.notify({ + eventName: SlideContainer.cancelledEvent, + object: this, + eventData: { + currentIndex: this.currentPanel.index, + reason: cancelReason + } + }); + } + + createIndicator(index: number): Label { + let indicator = new Label(); + + (indicator).classList.add(SLIDE_INDICATOR_INACTIVE); + return indicator; + } + + setActivePageIndicator(index: number) { + let indicatorsToDeactivate = (this._footer).getElementsByClassName( + SLIDE_INDICATOR_ACTIVE + ); + + indicatorsToDeactivate.forEach(activeIndicator => { + activeIndicator.classList.remove(SLIDE_INDICATOR_ACTIVE); + activeIndicator.classList.add(SLIDE_INDICATOR_INACTIVE); + }); + + let activeIndicator = (this._footer).getElementsByClassName( + SLIDE_INDICATOR_INACTIVE + )[index]; + if (activeIndicator) { + activeIndicator.classList.remove(SLIDE_INDICATOR_INACTIVE); + activeIndicator.classList.add(SLIDE_INDICATOR_ACTIVE); + } + } + + iosProperty(theClass, theProperty) { + if (typeof theProperty === 'function') { + // xCode 7 and below + return theProperty.call(theClass); + } else { + // xCode 8+ + return theProperty; + } + } +} diff --git a/src/package-lock.json b/src/package-lock.json new file mode 100644 index 0000000..185670d --- /dev/null +++ b/src/package-lock.json @@ -0,0 +1,40 @@ +{ + "name": "nativescript-slides", + "version": "2.2.12", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "nativescript-dom": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/nativescript-dom/-/nativescript-dom-2.0.2.tgz", + "integrity": "sha512-VEY1X10QRZlJEeZUdrwrGoslKqeS03BloaL5OWaXeHmdtmgzaTo3yjIg4ZJOLFWpHme3xAmn+mEn5HLtUJH+NQ==" + }, + "tns-core-modules": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/tns-core-modules/-/tns-core-modules-3.4.1.tgz", + "integrity": "sha512-sz/yTmoW7WyDPpr4JEC+trlfiEI14X365jGF//tMCT/G6ISzANr43wc17fgbGH1UA1XbKzujbAl0xPNssRHVUA==", + "dev": true, + "requires": { + "tns-core-modules-widgets": "3.4.0" + } + }, + "tns-core-modules-widgets": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/tns-core-modules-widgets/-/tns-core-modules-widgets-3.4.0.tgz", + "integrity": "sha512-WEtjDRTjjKB+C1NhY1CJSNyhK9DPCYzBgM+yKgq5AmphK/QdQEMAP1U2ttOv8yWWfsvLZGOnzyLCzcyeoG0Gfw==", + "dev": true + }, + "tns-platform-declarations": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/tns-platform-declarations/-/tns-platform-declarations-3.4.1.tgz", + "integrity": "sha512-GCvUvmtZ2Nne9GIppYF5xzUQzYP+KF43R+ce9kFMT1erDP0I6thLrRkLEo8JgAYD7ukMqXAb80MlYMv/VDGSCw==", + "dev": true + }, + "typescript": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.2.tgz", + "integrity": "sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==", + "dev": true + } + } +} diff --git a/src/package.json b/src/package.json new file mode 100644 index 0000000..c01271f --- /dev/null +++ b/src/package.json @@ -0,0 +1,79 @@ +{ + "name": "nativescript-slides", + "version": "2.3.0", + "description": "NativeScript Slides plugin.", + "main": "nativescript-slides", + "typings": "nativescript-slides.d.ts", + "nativescript": { + "platforms": { + "android": "5.0.0", + "ios": "5.0.0" + } + }, + "scripts": { + "prepublish": "cp -av ../README.md ./", + "build": "tsc", + "demo.ios": "npm run preparedemo && cd ../demo && tns run ios", + "demo.android": "npm run preparedemo && cd ../demo && tns run android", + "preparedemo": "npm run build && cd ../demo && npm install ../src --save", + "setup": "npm install && cd ../demo && npm install && cd ../src && npm run build && cd ../demo && npm install ../src && cd ..", + "ios": "xcproj --project platforms/ios/YourApp.xcodeproj touch; xcproj --project platforms/ios/Pods/Pods.xcodeproj touch; tns livesync ios --emulator --watch" + }, + "repository": { + "type": "git", + "url": "https://github.com/JoshDSommer/nativescript-slides.git" + }, + "keywords": [ + "NativeScript", + "JavaScript", + "Android", + "iOS", + "TypeScript", + "swipe slides", + "Slides", + "Carousel" + ], + "author": { + "name": "Josh Sommer", + "email": "joshdsommer@gmail.com" + }, + "contributors": [ + { + "name": "Brad Martin", + "email": "bradwaynemartin@gmail.com", + "url": "https://github.com/bradmartin" + }, + { + "name": "Obsessive Inc/Abhijith Reddy", + "email": "mabhijith95a10@gmail.com", + "url": "https://github.com/Obsessive" + }, + { + "name": "Victor Nascimento", + "email": "victormota15@gmail.com", + "url": "https://github.com/vjoao" + }, + { + "name": "Steve McNiven-Scott", + "email": "steve@sitefinitysteve.com", + "url": "https://github.com/sitefinitysteve" + } + ], + "bugs": { + "url": "https://github.com/JoshDSommer/nativescript-slides/issues" + }, + "license": { + "type": "MIT", + "url": "https://github.com/JoshDSommer/nativescript-slides/blob/master/LICENSE" + }, + "homepage": "https://github.com/JoshDSommer/nativescript-slides", + "readmeFilename": "README.md", + "devDependencies": { + "typescript": "^2.2.2", + "tns-platform-declarations": "^3.0.1", + "tns-core-modules": "^3.0.1" + }, + "dependencies": { + "nativescript-dom": "^2.0.0" + } +} diff --git a/tsconfig.json b/src/tsconfig.json similarity index 100% rename from tsconfig.json rename to src/tsconfig.json pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy