From e79973fe5db5c71bc330e6c4bc029ca0a9abe7e4 Mon Sep 17 00:00:00 2001 From: Andrew Date: Wed, 1 Apr 2015 09:33:48 -0600 Subject: [PATCH] add util/dom --- gulpfile.js | 4 +- src/components.js | 14 ++-- src/components/aside/aside.js | 3 +- src/components/ion.js | 2 - src/components/item/extensions/ios.scss | 3 +- src/components/item/item-options.js | 13 +++ src/components/item/item-swipe-buttons.js | 74 ++++++++++++++++ src/components/item/item.js | 42 +++++++--- src/components/item/item.scss | 28 +++++++ src/components/item/test/basic/main.html | 78 ++++------------- src/components/item/test/basic/main.js | 21 +++++ src/util.js | 84 +------------------ src/util/dom.js | 33 ++++++++ .../test/util.spec.js} | 0 src/util/util.js | 71 ++++++++++++++++ 15 files changed, 305 insertions(+), 165 deletions(-) create mode 100644 src/components/item/item-options.js create mode 100644 src/components/item/item-swipe-buttons.js create mode 100644 src/util/dom.js rename src/{util-test.spec.js => util/test/util.spec.js} (100%) create mode 100644 src/util/util.js diff --git a/gulpfile.js b/gulpfile.js index ffd1c91d99..e565a233fc 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,6 +1,6 @@ -///// +// // Mostly stolen from https://github.com/pkozlowski-opensource/ng2-play -///// +// var _ = require('lodash') var buildConfig = require('./scripts/build/config') diff --git a/src/components.js b/src/components.js index 99e4d19a52..6b4d6e891a 100644 --- a/src/components.js +++ b/src/components.js @@ -1,7 +1,11 @@ // export all components as array -import {Aside} from 'ionic2/components/aside/aside'; - -export let ionicComponents = [ - Aside, -]; +export * from 'ionic2/components/aside/aside' +export * from 'ionic2/components/checkbox/checkbox' +export * from 'ionic2/components/content/content' +export * from 'ionic2/components/icon/icon' +export * from 'ionic2/components/item/item' +export * from 'ionic2/components/list/list' +export * from 'ionic2/components/nav-view/nav-view' +export * from 'ionic2/components/toolbar/toolbar' +export * from 'ionic2/components/view/view' diff --git a/src/components/aside/aside.js b/src/components/aside/aside.js index 92b4af05b9..512465efab 100644 --- a/src/components/aside/aside.js +++ b/src/components/aside/aside.js @@ -1,6 +1,7 @@ import {Component, Template, Inject, Parent, NgElement} from 'angular2/angular2' import * as types from 'ionic2/components/aside/extensions/types' import * as gestures from 'ionic2/components/aside/extensions/gestures'; +import {dom} from 'ionic2/util' import {IonicComponent} from 'ionic2/config/component' @Component({ @@ -50,7 +51,7 @@ export class Aside { if (isOpen !== this.isOpen) { this.isOpen = isOpen this.setChanging(true) - requestAnimationFrame(() => { + return dom.rafPromise().then(() => { this.typeDelegate.setOpen(isOpen) }) } diff --git a/src/components/ion.js b/src/components/ion.js index 3498173d07..45440ad23a 100644 --- a/src/components/ion.js +++ b/src/components/ion.js @@ -1,5 +1,3 @@ -import * as util from 'ionic2/util'; - export class Ion {} // export class IonElement extends Ion { diff --git a/src/components/item/extensions/ios.scss b/src/components/item/extensions/ios.scss index 6030f5c134..69d964ca32 100644 --- a/src/components/item/extensions/ios.scss +++ b/src/components/item/extensions/ios.scss @@ -18,7 +18,6 @@ $item-ios-border-color: $list-ios-border-color !default; .item { background: $item-ios-background-color; min-height: $item-ios-min-height; - padding-left: $item-ios-padding-left; } .item-media + .item-content { @@ -27,7 +26,7 @@ $item-ios-border-color: $list-ios-border-color !default; .item-content { min-height: $item-ios-min-height; - padding: 0; + padding: 0 0 0 $item-ios-padding-left; &:after { position: absolute; diff --git a/src/components/item/item-options.js b/src/components/item/item-options.js new file mode 100644 index 0000000000..b93b73f6f0 --- /dev/null +++ b/src/components/item/item-options.js @@ -0,0 +1,13 @@ + +@Decorator({ + selector: 'ion-primary-options' +}) +export class ItemPrimaryOptions { +} + +@Decorator({ + selector: 'ion-secondary-options' +}) +export class ItemSecondaryOptions { +} + diff --git a/src/components/item/item-swipe-buttons.js b/src/components/item/item-swipe-buttons.js new file mode 100644 index 0000000000..605bd1f112 --- /dev/null +++ b/src/components/item/item-swipe-buttons.js @@ -0,0 +1,74 @@ +import {Parent, NgElement, Decorator} from 'angular2/angular2' +import {Item} from 'ionic2/components' +import {SlideGesture} from 'ionic2/gestures/slide-gesture' + +@Decorator({ + selector: 'ion-primary-swipe-buttons' +}) +export class ItemPrimarySwipeButtons { + constructor( + @NgElement() element: NgElement, + @Parent() item: Item + ) { + this.domElement = element.domElement + this.parentItem = item + this.gesture = new ItemSlideGesture(this) + this.gesture.listen() + + this.domElement.addEventListener('transitionend', () => { + this.domElement.classList.remove('changing') + }) + } + + setOpen(isOpen) { + if (isOpen !== this.isOpen) { + this.isOpen = isOpen + requestAnimationFrame(() => { + this.domElement.classList[isOpen?'add':'remove'](isOpen) + }) + } + } +} + +@Decorator({ + selector: 'ion-secondary-swipe-buttons' +}) +export class ItemSecondarySwipeButtons { +} + +class ItemSlideGesture extends SlideGesture { + constructor(buttons) { + super(buttons.parentItem.domElement) + this.buttons = buttons + } + + getSlideBoundaries() { + return { + min: -this.buttons.domElement.offsetWidth, + max: 0, + }; + } + + getElementStartPos(slide, ev) { + return this.buttons.isOpen ? slide.max : slide.min; + } + + onSlideBeforeStart() { + this.buttons.domElement.classList.add('changing') + this.buttons.domElement.classList.add('no-transition') + return new Promise(resolve => { + requestAnimationFrame(resolve) + }) + } + onSlide(slide, ev) { + this.buttons.domElement.style.transform = 'translate3d(' + slide.distance + 'px,0,0)'; + } + onSlideEnd(slide, ev) { + this.buttons.domElement.style.transform = '' + this.buttons.domElement.classList.remove('no-transition') + if (Math.abs(ev.velocityX) > 0.2 || Math.abs(slide.delta) > Math.abs(slide.max) * 0.5) { + this.buttons.setOpen(!this.buttons.isOpen); + } + } + +} diff --git a/src/components/item/item.js b/src/components/item/item.js index 7c8e662da7..f2e40cbec9 100644 --- a/src/components/item/item.js +++ b/src/components/item/item.js @@ -1,22 +1,44 @@ import {NgElement, Component, Template} from 'angular2/angular2' import {IonicComponent} from 'ionic2/config/component' +import { + ItemPrimaryOptions, ItemSecondaryOptions +} from 'ionic2/components/item/item-options' +import { + ItemPrimarySwipeButtons, ItemSecondarySwipeButtons +} from 'ionic2/components/item/item-swipe-buttons' @Component({ selector: 'ion-item' }) @Template({ - inline: `
-
-
-
- -
-
-
-
` + inline: ` + + +
+
+
+
+ +
+
+ +
+
+ + + `, + direcetives: [ + ItemPrimarySwipeButtons, + ItemSecondarySwipeButtons, + ItemPrimaryOptions, + ItemSecondaryOptions + ] }) export class Item { - constructor(@NgElement() ele:NgElement) { + constructor( + @NgElement() ele:NgElement + ) { + this.domElement = ele.domElement Item.config.invoke(this) } } diff --git a/src/components/item/item.scss b/src/components/item/item.scss index 87a3db4bee..f70e7e46eb 100644 --- a/src/components/item/item.scss +++ b/src/components/item/item.scss @@ -17,7 +17,32 @@ $item-min-height: 44px !default; padding: 0; } +ion-primary-swipe-buttons, .item-content { + transition: transform 0.3s; +} + +ion-primary-swipe-buttons { + position: absolute; + top: 0; + left: 0; + bottom: 0; + z-index: 100; + transform: translate3d(-100%,0,0); + + &:not(.open):not(.changing) { + display: none; + } + &.open { + transform: translate3d(100%, 0, 0); + } +} + +.item-content { + // TODO add proper bg to cover up swipe buttons + background: white; + transform: translate3d(0,0,0); + position: relative; @include flex-display(); @@ -36,6 +61,7 @@ $item-min-height: 44px !default; @include flex-shrink(0); @include flex-wrap(nowrap); @include flex-align-items(center); + @include flex-order(1); min-height: $item-min-height; @@ -47,6 +73,7 @@ $item-min-height: 44px !default; @include flex(1); @include flex-shrink(1); + @include flex-order(2); max-width: 100%; @@ -58,6 +85,7 @@ $item-min-height: 44px !default; .item-accessory { @include flex-display(); @include flex-shrink(0); + @include flex-order(3); margin-left: 5px; max-height: 28px; diff --git a/src/components/item/test/basic/main.html b/src/components/item/test/basic/main.html index b41ace4001..ed586961bc 100644 --- a/src/components/item/test/basic/main.html +++ b/src/components/item/test/basic/main.html @@ -1,65 +1,19 @@ -
+ + + + List Header + -
- -
- iOS List/Item Default CSS Tests -
- -
- -
- -
- List Header + + +
+
+ Item {{item}} + + Label {{item}} + +
-
    - -
  • -
    -
    - Item 1 -
    -
    - Label -
    -
    -
  • - -
  • -
    -
    - Item 2 -
    -
    - Label -
    -
    -
  • - -
  • -
    -
    - Item 3 -
    -
    - Label -
    -
    -
  • - -
- - - -
- - -
- -
- -
+
+
diff --git a/src/components/item/test/basic/main.js b/src/components/item/test/basic/main.js index e69de29bb2..7337888590 100644 --- a/src/components/item/test/basic/main.js +++ b/src/components/item/test/basic/main.js @@ -0,0 +1,21 @@ +import {bootstrap} from 'angular2/core' +import {Component, Template, For} from 'angular2/angular2' +import {Item, View, List} from 'ionic2/components' + +import {ItemPrimarySwipeButtons} from 'ionic2/components/item/item-swipe-buttons' + +@Component({ + selector: '[ion-app]' +}) +@Template({ + url: 'main.html', + directives: [Item, View, List, For, ItemPrimarySwipeButtons] +}) +class App{ + constructor() { + this.items = [1, 2, 3, 4, 5] + } +} + +bootstrap(App) + diff --git a/src/util.js b/src/util.js index c0ff70d90d..a7edf761db 100644 --- a/src/util.js +++ b/src/util.js @@ -1,82 +1,4 @@ -export function noop() {} +import * as domUtil from 'ionic2/util/dom' +export const dom = domUtil -export function clamp(min, n, max) { - return Math.max(min, Math.min(n, max)); -} - -export function extend(dest) { - for (var i = 1, ii = arguments.length; i < ii; i++) { - var source = arguments[i] || {}; - for (var key in source) { - if (source.hasOwnProperty(key)) { - dest[key] = source[key]; - } - } - } - return dest; -} - -export function defaults(dest) { - for (let i = arguments.length - 1; i >= 1; i--) { - let source = arguments[i] || {}; - for (let key in source) { - if (source.hasOwnProperty(key) && !dest.hasOwnProperty(key)) { - dest[key] = source[key]; - } - } - } - return dest; -} - -export const isString = val => typeof val === 'string' -export const isFunction = val => typeof val === 'function' -export const isDefined = val => typeof val === 'undefined' -export const isObject = val => typeof val === 'object' -export const isArray = Array.isArray - -export function pascalCaseToDashCase(str = '') { - return str.charAt(0).toLowerCase() + str.substring(1).replace(/[A-Z]/g, match => { - return '-' + match.toLowerCase() - }) -} - -export let array = { - unique(array) { - return array.filter((value, index) => { - return array.indexOf(value) === index - }) - } -} - -export class Log { - static log(...args) { - console.log.apply(console, args) - } - static info(...args) { - console.info.apply(console, args) - } - static dir(...args) { - console.dir.apply(console, args) - } - static warn(...args) { - console.warn.apply(console, args) - } - static error(...args) { - console.error.apply(console, args) - } -} - -export function readQueryParams() { - var queryParams = {} - const startIndex = window.location.href.indexOf('?') - if (startIndex !== -1) { - const queries = window.location.href.slice(startIndex + 1).split('&') - if (queries.length) { - queries.forEach((param) => { - var split = param.split('=') - queryParams[split[0]] = split[1] - }) - } - } - return queryParams -} +export * from 'ionic2/util/util' diff --git a/src/util/dom.js b/src/util/dom.js new file mode 100644 index 0000000000..06fee40e12 --- /dev/null +++ b/src/util/dom.js @@ -0,0 +1,33 @@ + +const nativeRaf= window.requestAnimationFrame || + window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame +const nativeCancelRaf = window.cancelAnimationFrame || + window.webkitCancelAnimationFrame || + window.webkitCancelRequestAnimationFrame + +export const raf = nativeRaf || function(callback) { + return window.setTimeout(callback, 16.6667) +} +export const rafCancel = nativeRaf ? nativeCancelRaf : function(id) { + return window.cancelTimeout(id) +} + +export function rafPromise() { + return new Promise(resolve => raf(resolve)) +} + + +// We only need to test for webkit in our supported browsers. Webkit is the only browser still +// using prefixes. +// Code adapted from angular-animate.js +export let css = {} +if (window.ontransitionend === undefined && window.onwebkittransitionend !== undefined) { + css.prefix = 'webkit' + css.transition = 'webkitTransition' + css.transitionEnd = 'webkitTransitionEnd transitionend' +} else { + css.prefix = '' + css.transition = 'transition' + css.transitionEnd = 'tranistionend' +} diff --git a/src/util-test.spec.js b/src/util/test/util.spec.js similarity index 100% rename from src/util-test.spec.js rename to src/util/test/util.spec.js diff --git a/src/util/util.js b/src/util/util.js new file mode 100644 index 0000000000..e236709ae3 --- /dev/null +++ b/src/util/util.js @@ -0,0 +1,71 @@ +export function noop() {} + +export function clamp(min, n, max) { + return Math.max(min, Math.min(n, max)); +} + +export function extend(dest) { + for (var i = 1, ii = arguments.length; i < ii; i++) { + var source = arguments[i] || {}; + for (var key in source) { + if (source.hasOwnProperty(key)) { + dest[key] = source[key]; + } + } + } + return dest; +} + +export function defaults(dest) { + for (let i = arguments.length - 1; i >= 1; i--) { + let source = arguments[i] || {}; + for (let key in source) { + if (source.hasOwnProperty(key) && !dest.hasOwnProperty(key)) { + dest[key] = source[key]; + } + } + } + return dest; +} + +export const isString = val => typeof val === 'string' +export const isFunction = val => typeof val === 'function' +export const isDefined = val => typeof val === 'undefined' +export const isObject = val => typeof val === 'object' +export const isArray = Array.isArray + +export function pascalCaseToDashCase(str = '') { + return str.charAt(0).toLowerCase() + str.substring(1).replace(/[A-Z]/g, match => { + return '-' + match.toLowerCase() + }) +} + +export class Log { + static log(...args) { + console.log.apply(console, args) + } + static info(...args) { + console.info.apply(console, args) + } + static warn(...args) { + console.warn.apply(console, args) + } + static error(...args) { + console.error.apply(console, args) + } +} + +export function readQueryParams() { + var queryParams = {} + const startIndex = window.location.href.indexOf('?') + if (startIndex !== -1) { + const queries = window.location.href.slice(startIndex + 1).split('&') + if (queries.length) { + queries.forEach((param) => { + var split = param.split('=') + queryParams[split[0]] = split[1] + }) + } + } + return queryParams +}