mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-19 03:32:21 +08:00
Merge branch 'master' into alpha38
Conflicts: ionic/components/popup/popup.ts
This commit is contained in:
@ -1,4 +1,8 @@
|
|||||||
import {Directive, ElementRef} from 'angular2/angular2';
|
import {Directive, ElementRef, Host, Optional} from 'angular2/angular2';
|
||||||
|
import {Content} from '../content/content';
|
||||||
|
import {throttle} from '../../util/util';
|
||||||
|
import {position, offset, CSS} from '../../util/dom';
|
||||||
|
import {IonicConfig} from '../../config/config';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO
|
* TODO
|
||||||
@ -34,8 +38,126 @@ export class ItemGroupTitle {
|
|||||||
* TODO
|
* TODO
|
||||||
* @param {ElementRef} elementRef TODO
|
* @param {ElementRef} elementRef TODO
|
||||||
*/
|
*/
|
||||||
constructor(elementRef: ElementRef) {
|
constructor(elementRef: ElementRef, config: IonicConfig, @Host() content: Content) {
|
||||||
this.isSticky = true;
|
this.isSticky = true;
|
||||||
|
this.content = content;
|
||||||
this.ele = elementRef.nativeElement;
|
this.ele = elementRef.nativeElement;
|
||||||
|
this.parent = this.ele.parentNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
onInit() {
|
||||||
|
|
||||||
|
this.scrollContent = this.content.elementRef.nativeElement.children[0];
|
||||||
|
|
||||||
|
this.scrollMin = 0;
|
||||||
|
this.scrollMax = 0;
|
||||||
|
this.scrollTransition = 0;
|
||||||
|
this.isSticking = false;
|
||||||
|
|
||||||
|
|
||||||
|
this.scrollContent.addEventListener('scroll', event => this.scrollEvent(event));
|
||||||
|
|
||||||
|
this.calculateScrollLimits = scrollTop => {
|
||||||
|
var containerPosition = position(this.parent);
|
||||||
|
var elementOffset = offset(this.ele);
|
||||||
|
|
||||||
|
var containerTop = containerPosition.top;
|
||||||
|
var containerHeight = containerPosition.height;
|
||||||
|
|
||||||
|
var affixHeight = elementOffset.height;
|
||||||
|
|
||||||
|
this.scrollMin = containerTop;
|
||||||
|
this.scrollMax = this.scrollMin + containerHeight;
|
||||||
|
this.scrollTransition = this.scrollMax - affixHeight;
|
||||||
|
};
|
||||||
|
|
||||||
|
// throttled version of the same calculation
|
||||||
|
let CALCULATION_THROTTLE_MS = 500;
|
||||||
|
this.throttledCalculateScrollLimits = throttle(
|
||||||
|
this.calculateScrollLimits,
|
||||||
|
CALCULATION_THROTTLE_MS,
|
||||||
|
{trailing: false}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
applyTransform(element, transformString) {
|
||||||
|
// do not apply the transformation if it is already applied
|
||||||
|
if (element.style[CSS.transform] == transformString) {
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
element.style[CSS.transform] = transformString;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
translateUp(element, dy, executeImmediately) {
|
||||||
|
var translateDyPixelsUp = dy == 0 ? 'translate3d(0px, 0px, 0px)' : 'translate3d(0px, -' + dy + 'px, 0px)';
|
||||||
|
// if immediate execution is requested, then just execute immediately
|
||||||
|
// if not, execute in the animation frame.
|
||||||
|
if (executeImmediately) {
|
||||||
|
this.applyTransform(element, translateDyPixelsUp);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// see http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
|
||||||
|
// see http://ionicframework.com/docs/api/utility/ionic.DomUtil/
|
||||||
|
requestAnimationFrame( a => this.applyTransform(element, translateDyPixelsUp) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
createAffixClone() {
|
||||||
|
var clone = this.ele.cloneNode(true);
|
||||||
|
clone.style.position = 'absolute';
|
||||||
|
clone.style.top = 0;
|
||||||
|
clone.style.left = 0;
|
||||||
|
clone.style.right = 0;
|
||||||
|
|
||||||
|
this.scrollContent.parentNode.appendChild(clone);
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollEvent(event) {
|
||||||
|
var scrollTop = event.target.scrollTop;
|
||||||
|
|
||||||
|
// when scroll to top, we should always execute the immediate calculation.
|
||||||
|
// this is because of some weird problem which is hard to describe.
|
||||||
|
// if you want to experiment, always use the throttled one and just click on the page
|
||||||
|
// you will see all affix elements stacked on top
|
||||||
|
if (scrollTop == 0) {
|
||||||
|
this.calculateScrollLimits(scrollTop);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.throttledCalculateScrollLimits(scrollTop);
|
||||||
|
}
|
||||||
|
|
||||||
|
// when we scrolled to the container, create the clone of element and place it on top
|
||||||
|
if (scrollTop >= this.scrollMin && scrollTop <= this.scrollMax) {
|
||||||
|
// we need to track if we created the clone just now
|
||||||
|
// that is important since normally we apply the transforms in the animation frame
|
||||||
|
// but, we need to apply the transform immediately when we add the element for the first time. otherwise it is too late!
|
||||||
|
var cloneCreatedJustNow = false;
|
||||||
|
|
||||||
|
if (!this.affixClone) {
|
||||||
|
this.affixClone = this.createAffixClone();
|
||||||
|
cloneCreatedJustNow = true;
|
||||||
|
this.isSticking = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we're reaching towards the end of the container, apply some nice translation to move up/down the clone
|
||||||
|
// but if we're reached already to the container and we're far away than the end, move clone to top
|
||||||
|
if (scrollTop > this.scrollTransition) {
|
||||||
|
this.translateUp(this.affixClone, Math.floor(scrollTop - this.scrollTransition), cloneCreatedJustNow);
|
||||||
|
} else {
|
||||||
|
this.translateUp(this.affixClone, 0, cloneCreatedJustNow);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.removeAffixClone();
|
||||||
|
this.isSticking = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
removeAffixClone() {
|
||||||
|
if (this.affixClone) {
|
||||||
|
this.scrollContent.parentNode.removeChild(this.affixClone);
|
||||||
|
this.affixClone = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,14 +26,16 @@ $item-ios-divider-bg: #f5f5f5 !default;
|
|||||||
$item-ios-divider-color: #222 !default;
|
$item-ios-divider-color: #222 !default;
|
||||||
$item-ios-divider-padding: 5px 15px !default;
|
$item-ios-divider-padding: 5px 15px !default;
|
||||||
|
|
||||||
|
.item-group-title {
|
||||||
|
padding: $item-ios-padding-top $item-ios-padding-right $item-ios-padding-bottom $item-ios-padding-left;
|
||||||
|
background-color: $item-ios-divider-bg;
|
||||||
|
color: $item-ios-divider-color;
|
||||||
|
}
|
||||||
|
|
||||||
.list {
|
.list {
|
||||||
|
|
||||||
|
|
||||||
.item-group-title {
|
|
||||||
padding: $item-ios-padding-top $item-ios-padding-right $item-ios-padding-bottom $item-ios-padding-left;
|
|
||||||
background-color: $item-ios-divider-bg;
|
|
||||||
color: $item-ios-divider-color;
|
|
||||||
}
|
|
||||||
.item-group {
|
.item-group {
|
||||||
// Make sure the first and last items don't have borders
|
// Make sure the first and last items don't have borders
|
||||||
> .item:first-of-type:before {
|
> .item:first-of-type:before {
|
||||||
|
@ -1,15 +1,10 @@
|
|||||||
|
<ion-content padding #content>
|
||||||
|
|
||||||
<ion-view nav-title="List">
|
<ion-list inset virtual [items]="items" [content]="content">
|
||||||
|
<ion-item *cell #item>
|
||||||
|
{{item.title}}
|
||||||
|
</ion-item>
|
||||||
|
</ion-list>
|
||||||
|
<f style="height: 15000px; width: 100%; background-color: green"></f>
|
||||||
|
|
||||||
<ion-content padding #content>
|
</ion-content>
|
||||||
|
|
||||||
<ion-list inset virtual [items]="items" [content]="content">
|
|
||||||
<ion-item *cell #item>
|
|
||||||
{{item.title}}
|
|
||||||
</ion-item>
|
|
||||||
</ion-list>
|
|
||||||
<f style="height: 15000px; width: 100%; background-color: green"></f>
|
|
||||||
|
|
||||||
</ion-content>
|
|
||||||
|
|
||||||
</ion-view>
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<ion-view nav-title="Pull to refresh">
|
<!-- <ion-view nav-title="Pull to refresh"> -->
|
||||||
<ion-toolbar><ion-title>Scroll</ion-title></ion-toolbar>
|
<ion-toolbar><ion-title>Scroll</ion-title></ion-toolbar>
|
||||||
|
|
||||||
<ion-content>
|
<ion-content>
|
||||||
@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
</ion-content>
|
</ion-content>
|
||||||
|
|
||||||
</ion-view>
|
<!-- </ion-view> -->
|
||||||
<style>
|
<style>
|
||||||
f { display: block; height: 400px; width: 100%; background-color: #387ef5; margin-bottom: 15px; }
|
f { display: block; height: 400px; width: 100%; background-color: #387ef5; margin-bottom: 15px; }
|
||||||
#counter {
|
#counter {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<ion-view nav-title="Pull to refresh">
|
<!-- <ion-view nav-title="Pull to refresh"> -->
|
||||||
<ion-toolbar><ion-title>Pull To Refresh</ion-title></ion-toolbar>
|
<ion-toolbar><ion-title>Pull To Refresh</ion-title></ion-toolbar>
|
||||||
|
|
||||||
<ion-content>
|
<ion-content>
|
||||||
@ -13,7 +13,7 @@
|
|||||||
<f></f>
|
<f></f>
|
||||||
</ion-content>
|
</ion-content>
|
||||||
|
|
||||||
</ion-view>
|
<!-- </ion-view> -->
|
||||||
<style>
|
<style>
|
||||||
f { display: block; height: 400px; width: 100%; background-color: #387ef5; margin-bottom: 15px; }
|
f { display: block; height: 400px; width: 100%; background-color: #387ef5; margin-bottom: 15px; }
|
||||||
#counter {
|
#counter {
|
||||||
|
@ -2,13 +2,15 @@
|
|||||||
// iOS Search Bar
|
// iOS Search Bar
|
||||||
// --------------------------------------------------
|
// --------------------------------------------------
|
||||||
|
|
||||||
$search-bar-ios-background-color: #c9c9ce !default;
|
$search-bar-ios-background-color: rgba(0, 0, 0, 0.2) !default;
|
||||||
$search-bar-ios-border-color: $item-ios-border-color !default;
|
$search-bar-ios-border-color: rgba(0, 0, 0, 0.05) !default;
|
||||||
$search-bar-ios-padding: 0 8px !default;
|
$search-bar-ios-padding: 0 8px !default;
|
||||||
$search-bar-ios-input-height: 28px !default;
|
$search-bar-ios-input-height: 28px !default;
|
||||||
$search-bar-ios-background-svg: "<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 13 13'><path fill='#939398' d='M5,1c2.2,0,4,1.8,4,4S7.2,9,5,9S1,7.2,1,5S2.8,1,5,1 M5,0C2.2,0,0,2.2,0,5s2.2,5,5,5s5-2.2,5-5S7.8,0,5,0 L5,0z'/><line stroke='#939398' stroke-miterlimit='10' x1='12.6' y1='12.6' x2='8.2' y2='8.2'/></svg>" !default;
|
$search-bar-ios-input-text-color: #9D9D9D !default;
|
||||||
$search-bar-ios-background-size: 13px 13px !default;
|
$search-bar-ios-input-background-color: #FFFFFF !default;
|
||||||
|
$search-bar-ios-input-icon-color: #767676 !default;
|
||||||
|
$search-bar-ios-input-background-svg: "<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 13 13'><path fill='" + $search-bar-ios-input-icon-color + "' d='M5,1c2.2,0,4,1.8,4,4S7.2,9,5,9S1,7.2,1,5S2.8,1,5,1 M5,0C2.2,0,0,2.2,0,5s2.2,5,5,5s5-2.2,5-5S7.8,0,5,0 L5,0z'/><line stroke='#939398' stroke-miterlimit='10' x1='12.6' y1='12.6' x2='8.2' y2='8.2'/></svg>" !default;
|
||||||
|
$search-bar-ios-background-size: 13px 13px !default;
|
||||||
|
|
||||||
.search-bar {
|
.search-bar {
|
||||||
padding: $search-bar-ios-padding;
|
padding: $search-bar-ios-padding;
|
||||||
@ -22,7 +24,7 @@ $search-bar-ios-background-size: 13px 13px !default;
|
|||||||
|
|
||||||
transform: translateX(calc(50% - 60px));
|
transform: translateX(calc(50% - 60px));
|
||||||
|
|
||||||
@include svg-background-image($search-bar-ios-background-svg);
|
@include svg-background-image($search-bar-ios-input-background-svg);
|
||||||
background-size: $search-bar-ios-background-size;
|
background-size: $search-bar-ios-background-size;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -38,20 +40,26 @@ $search-bar-ios-background-size: 13px 13px !default;
|
|||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
|
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
color: #000;
|
color: $search-bar-ios-input-text-color;
|
||||||
background-color: #fff;
|
background-color: $search-bar-ios-input-background-color;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position: 8px center;
|
background-position: 8px center;
|
||||||
|
|
||||||
@include calc(padding-left, "50% - 28px");
|
@include calc(padding-left, "50% - 28px");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.search-bar-input-container.left-align {
|
.search-bar-input-container.left-align {
|
||||||
.search-bar-icon {
|
.search-bar-icon {
|
||||||
transform: translateX(0);
|
transform: translateX(0);
|
||||||
|
-webkit-transition: all 0.3s cubic-bezier(.25, .45, .05, 1);
|
||||||
|
-moz-transition: all 0.3s cubic-bezier(.25, .45, .05, 1);
|
||||||
}
|
}
|
||||||
.search-bar-input {
|
.search-bar-input {
|
||||||
padding-left: 28px;
|
padding-left: 28px;
|
||||||
|
-webkit-transition: all 0.3s cubic-bezier(.25, .45, .05, 1);
|
||||||
|
-moz-transition: all 0.3s cubic-bezier(.25, .45, .05, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import {ElementRef, Pipe} from 'angular2/angular2';
|
import {ElementRef, Pipe, NgControl, Renderer} from 'angular2/angular2';
|
||||||
|
//import {ControlGroup} from 'angular2/forms'
|
||||||
|
|
||||||
import {Ion} from '../ion';
|
import {Ion} from '../ion';
|
||||||
import {IonicConfig} from '../../config/config';
|
import {IonicConfig} from '../../config/config';
|
||||||
@ -9,6 +10,7 @@ import {IonicComponent, IonicView} from '../../config/decorators';
|
|||||||
*/
|
*/
|
||||||
@IonicComponent({
|
@IonicComponent({
|
||||||
selector: 'ion-search-bar',
|
selector: 'ion-search-bar',
|
||||||
|
appInjector: [NgControl],
|
||||||
properties: [
|
properties: [
|
||||||
'list',
|
'list',
|
||||||
'query'
|
'query'
|
||||||
@ -24,6 +26,7 @@ import {IonicComponent, IonicView} from '../../config/decorators';
|
|||||||
<div class="search-bar-icon"></div>
|
<div class="search-bar-icon"></div>
|
||||||
<input (focus)="inputFocused()" (blur)="inputBlurred()"
|
<input (focus)="inputFocused()" (blur)="inputBlurred()"
|
||||||
(input)="inputChanged($event)" class="search-bar-input" type="search" [attr.placeholder]="placeholder">
|
(input)="inputChanged($event)" class="search-bar-input" type="search" [attr.placeholder]="placeholder">
|
||||||
|
<div class="search-bar-close-icon"></div>
|
||||||
</div>
|
</div>
|
||||||
<button class="search-bar-cancel">{{cancelText}}</button>`
|
<button class="search-bar-cancel">{{cancelText}}</button>`
|
||||||
})
|
})
|
||||||
@ -35,12 +38,21 @@ export class SearchBar extends Ion {
|
|||||||
*/
|
*/
|
||||||
constructor(
|
constructor(
|
||||||
elementRef: ElementRef,
|
elementRef: ElementRef,
|
||||||
config: IonicConfig//,
|
config: IonicConfig,
|
||||||
//cd:ControlDirective
|
ngControl: NgControl,
|
||||||
|
renderer: Renderer
|
||||||
) {
|
) {
|
||||||
super(elementRef, config);
|
super(elementRef, config);
|
||||||
// this.controlDirective = cd;
|
this.renderer = renderer;
|
||||||
// cd.valueAccessor = this; //ControlDirective should inject CheckboxControlDirective
|
this.elementRef = elementRef;
|
||||||
|
if(!ngControl) {
|
||||||
|
// They don't want to do anything that works, so we won't do anything that breaks
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.ngControl = ngControl;
|
||||||
|
|
||||||
|
ngControl.valueAccessor = this;
|
||||||
|
|
||||||
this.query = '';
|
this.query = '';
|
||||||
}
|
}
|
||||||
@ -51,13 +63,28 @@ export class SearchBar extends Ion {
|
|||||||
*/
|
*/
|
||||||
writeValue(value) {
|
writeValue(value) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
|
console.log('writeValue', value);
|
||||||
|
this.renderer.setElementProperty(this.elementRef, 'value', this.value);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
registerOnChange(val) {
|
||||||
|
console.log('registerONChange', val);
|
||||||
|
}
|
||||||
|
|
||||||
|
registerOnTouched(val) {
|
||||||
|
console.log('register on touched', val);
|
||||||
}
|
}
|
||||||
|
|
||||||
inputChanged(event) {
|
inputChanged(event) {
|
||||||
this.value = event.target.value;
|
this.value = event.target.value;
|
||||||
console.log('Search changed', this.value);
|
console.log('Search changed', this.value);
|
||||||
|
this.ngControl.valueAccessor.writeValue(this.value);
|
||||||
|
this.ngControl.control.updateValue(this.value);
|
||||||
|
// this.ngControl.valueAccessor.updateValue(this.value);
|
||||||
|
// this.ngControl.updateValue(this.value);
|
||||||
// TODO: Better way to do this?
|
// TODO: Better way to do this?
|
||||||
this.controlDirective._control().updateValue(event.target.value);
|
//this.controlDirective._control().updateValue(event.target.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
inputFocused() {
|
inputFocused() {
|
||||||
|
@ -1,16 +1,19 @@
|
|||||||
import {FormBuilder, Validators, Control, ControlGroup} from 'angular2/angular2';
|
import {NgControl} from 'angular2/angular2';
|
||||||
|
import {FORM_DIRECTIVES, FormBuilder, Validators, Control, ControlGroup} from 'angular2/forms';
|
||||||
|
|
||||||
import {App} from 'ionic/ionic';
|
import {App} from 'ionic/ionic';
|
||||||
import {SearchPipe} from 'ionic/components/search-bar/search-bar';
|
import {SearchPipe} from 'ionic/components/search-bar/search-bar';
|
||||||
|
|
||||||
|
|
||||||
function randomTitle() {
|
function randomTitle() {
|
||||||
var items = ['Pizza', 'Pumpkin', 'Apple', 'Bologna'];
|
var items = ['Soylent', 'Pizza', 'Pumpkin', 'Apple', 'Bologna', 'Turkey', 'Kabob', 'Salad', 'Fruit bowl', 'Fish Tacos', 'Chimichongas', 'Meatloaf'];
|
||||||
return items[Math.floor(Math.random() * items.length)];
|
return items[Math.floor(Math.random() * items.length)];
|
||||||
}
|
}
|
||||||
|
|
||||||
@App({
|
@App({
|
||||||
templateUrl: 'main.html'
|
templateUrl: 'main.html',
|
||||||
|
bindings: [NgControl],
|
||||||
|
directives: [FORM_DIRECTIVES]
|
||||||
})
|
})
|
||||||
class IonicApp {
|
class IonicApp {
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -19,9 +22,6 @@ class IonicApp {
|
|||||||
searchQuery: ['', Validators.required]
|
searchQuery: ['', Validators.required]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
this.query = 'HELLO';
|
|
||||||
|
|
||||||
this.items = []
|
this.items = []
|
||||||
for(let i = 0; i < 100; i++) {
|
for(let i = 0; i < 100; i++) {
|
||||||
this.items.push({
|
this.items.push({
|
||||||
|
@ -1,17 +1,16 @@
|
|||||||
|
|
||||||
<ion-view nav-title="Search Bar">
|
<!-- <ion-view nav-title="Search Bar"> -->
|
||||||
|
|
||||||
<ion-content [control-group]="form">
|
<ion-content>
|
||||||
|
<form [ng-form-model]="form">
|
||||||
<ion-search-bar control="searchQuery"></ion-search-bar>
|
|
||||||
|
|
||||||
<ion-list #list>
|
|
||||||
|
|
||||||
<ion-item *ng-for="#item of getItems()"><!--items | search:form.controls.searchControl.value">-->
|
|
||||||
{{item.title}}
|
|
||||||
</ion-item>
|
|
||||||
</ion-list>
|
|
||||||
|
|
||||||
|
<ion-search-bar ng-control="searchQuery"></ion-search-bar>
|
||||||
|
<ion-list inset #list>
|
||||||
|
<ion-item *ng-for="#item of getItems()">
|
||||||
|
{{item.title}}
|
||||||
|
</ion-item>
|
||||||
|
</ion-list>
|
||||||
|
</form>
|
||||||
</ion-content>
|
</ion-content>
|
||||||
|
|
||||||
</ion-view>
|
<!-- </ion-view> -->
|
||||||
|
21
ionic/components/search-bar/test/floating/index.ts
Normal file
21
ionic/components/search-bar/test/floating/index.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import {NgControl} from 'angular2/angular2';
|
||||||
|
import {FORM_DIRECTIVES, FormBuilder, Validators, Control, ControlGroup} from 'angular2/forms';
|
||||||
|
|
||||||
|
import {App} from 'ionic/ionic';
|
||||||
|
import {SearchPipe} from 'ionic/components/search-bar/search-bar';
|
||||||
|
|
||||||
|
@App({
|
||||||
|
templateUrl: 'main.html',
|
||||||
|
bindings: [NgControl, FormBuilder],
|
||||||
|
directives: [FORM_DIRECTIVES]
|
||||||
|
})
|
||||||
|
class IonicApp {
|
||||||
|
constructor(fb: FormBuilder) {
|
||||||
|
this.form = fb.group({
|
||||||
|
searchQuery: ['', Validators.required]
|
||||||
|
});
|
||||||
|
this.toolbarForm = fb.group({
|
||||||
|
toolbarSearchQuery: ['', Validators.required]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
13
ionic/components/search-bar/test/floating/main.html
Normal file
13
ionic/components/search-bar/test/floating/main.html
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<!-- <ion-toolbar>
|
||||||
|
<form [ng-form-model]="toolbarForm">
|
||||||
|
<ion-search-bar ng-control="toolbarSearchQuery"></ion-search-bar>
|
||||||
|
</form>
|
||||||
|
</ion-toolbar> -->
|
||||||
|
<ion-content>
|
||||||
|
<form [ng-form-model]="form">
|
||||||
|
<label> Default Search </label>
|
||||||
|
<ion-search-bar ng-control="searchQuery"></ion-search-bar>
|
||||||
|
<label> Placeholder Search </label>
|
||||||
|
<ion-search-bar ng-control="searchQuery" placeholder="Filter"></ion-search-bar>
|
||||||
|
</form>
|
||||||
|
</ion-content>
|
@ -57,11 +57,13 @@ ion-segment {
|
|||||||
|
|
||||||
&:first-of-type {
|
&:first-of-type {
|
||||||
border-radius: $button-border-radius 0px 0px $button-border-radius;
|
border-radius: $button-border-radius 0px 0px $button-border-radius;
|
||||||
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:last-of-type {
|
&:last-of-type {
|
||||||
border-right-width: 1px;
|
border-right-width: 1px;
|
||||||
border-radius: 0px $button-border-radius $button-border-radius 0px;
|
border-radius: 0px $button-border-radius $button-border-radius 0px;
|
||||||
|
margin-left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,16 @@
|
|||||||
|
<nav-bar></nav-bar>
|
||||||
<ion-tabs tab-bar-placement="bottom">
|
<ion-tabs tab-bar-placement="bottom">
|
||||||
|
|
||||||
<ion-tab tab-title="Tab 1">
|
<ion-tab tab-title="Tab 1">
|
||||||
<ion-view nav-title="Tab 1">
|
<ion-content padding>
|
||||||
<ion-content padding>
|
Tab 1 Content
|
||||||
Tab 1 Content
|
</ion-content>
|
||||||
</ion-content>
|
|
||||||
</ion-view>
|
|
||||||
</ion-tab>
|
</ion-tab>
|
||||||
|
|
||||||
<ion-tab tab-title="Tab 2">
|
<ion-tab tab-title="Tab 2">
|
||||||
<ion-view nav-title="Tab 2">
|
<ion-content padding>
|
||||||
<ion-content padding>
|
Tab 2 Content
|
||||||
Tab 2 Content
|
</ion-content>
|
||||||
</ion-content>
|
|
||||||
</ion-view>
|
|
||||||
</ion-tab>
|
</ion-tab>
|
||||||
|
|
||||||
</ion-tabs>
|
</ion-tabs>
|
||||||
|
@ -268,3 +268,70 @@ export function flushDimensionCache() {
|
|||||||
|
|
||||||
let dimensionCache = {};
|
let dimensionCache = {};
|
||||||
let dimensionIds = 0;
|
let dimensionIds = 0;
|
||||||
|
|
||||||
|
function getStyle(el, cssprop) {
|
||||||
|
if (el.currentStyle) { //IE
|
||||||
|
return el.currentStyle[cssprop];
|
||||||
|
} else if (window.getComputedStyle) {
|
||||||
|
return window.getComputedStyle(el)[cssprop];
|
||||||
|
}
|
||||||
|
// finally try and get inline style
|
||||||
|
return el.style[cssprop];
|
||||||
|
}
|
||||||
|
|
||||||
|
function isStaticPositioned(element) {
|
||||||
|
return (getStyle(element, 'position') || 'static') === 'static';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the closest, non-statically positioned parentOffset of a given element
|
||||||
|
* @param element
|
||||||
|
*/
|
||||||
|
export function parentOffsetEl(element) {
|
||||||
|
var offsetParent = element.offsetParent || document;
|
||||||
|
while (offsetParent && offsetParent !== document && isStaticPositioned(offsetParent)) {
|
||||||
|
offsetParent = offsetParent.offsetParent;
|
||||||
|
}
|
||||||
|
return offsetParent || document;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current coordinates of the element, relative to the offset parent.
|
||||||
|
* Read-only equivalent of [jQuery's position function](http://api.jquery.com/position/).
|
||||||
|
* @param {element} element The element to get the position of.
|
||||||
|
* @returns {object} Returns an object containing the properties top, left, width and height.
|
||||||
|
*/
|
||||||
|
export function position(element) {
|
||||||
|
var elBCR = offset(element);
|
||||||
|
var offsetParentBCR = { top: 0, left: 0 };
|
||||||
|
var offsetParentEl = parentOffsetEl(element);
|
||||||
|
if (offsetParentEl != document) {
|
||||||
|
offsetParentBCR = offset(offsetParentEl);
|
||||||
|
offsetParentBCR.top += offsetParentEl.clientTop - offsetParentEl.scrollTop;
|
||||||
|
offsetParentBCR.left += offsetParentEl.clientLeft - offsetParentEl.scrollLeft;
|
||||||
|
}
|
||||||
|
|
||||||
|
var boundingClientRect = element.getBoundingClientRect();
|
||||||
|
return {
|
||||||
|
width: boundingClientRect.width || element.prop('offsetWidth'),
|
||||||
|
height: boundingClientRect.height || element.prop('offsetHeight'),
|
||||||
|
top: elBCR.top - offsetParentBCR.top,
|
||||||
|
left: elBCR.left - offsetParentBCR.left
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current coordinates of the element, relative to the document.
|
||||||
|
* Read-only equivalent of [jQuery's offset function](http://api.jquery.com/offset/).
|
||||||
|
* @param {element} element The element to get the offset of.
|
||||||
|
* @returns {object} Returns an object containing the properties top, left, width and height.
|
||||||
|
*/
|
||||||
|
export function offset(element) {
|
||||||
|
var boundingClientRect = element.getBoundingClientRect();
|
||||||
|
return {
|
||||||
|
width: boundingClientRect.width || element.prop('offsetWidth'),
|
||||||
|
height: boundingClientRect.height || element.prop('offsetHeight'),
|
||||||
|
top: boundingClientRect.top + (window.pageYOffset || document.documentElement.scrollTop),
|
||||||
|
left: boundingClientRect.left + (window.pageXOffset || document.documentElement.scrollLeft)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
@ -180,3 +180,35 @@ export function getQuerystring(url, key) {
|
|||||||
}
|
}
|
||||||
return queryParams;
|
return queryParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Throttle the given fun, only allowing it to be
|
||||||
|
* called at most every `wait` ms.
|
||||||
|
*/
|
||||||
|
export function throttle(func, wait, options) {
|
||||||
|
var context, args, result;
|
||||||
|
var timeout = null;
|
||||||
|
var previous = 0;
|
||||||
|
options || (options = {});
|
||||||
|
var later = function() {
|
||||||
|
previous = options.leading === false ? 0 : Date.now();
|
||||||
|
timeout = null;
|
||||||
|
result = func.apply(context, args);
|
||||||
|
};
|
||||||
|
return function() {
|
||||||
|
var now = Date.now();
|
||||||
|
if (!previous && options.leading === false) previous = now;
|
||||||
|
var remaining = wait - (now - previous);
|
||||||
|
context = this;
|
||||||
|
args = arguments;
|
||||||
|
if (remaining <= 0) {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
timeout = null;
|
||||||
|
previous = now;
|
||||||
|
result = func.apply(context, args);
|
||||||
|
} else if (!timeout && options.trailing !== false) {
|
||||||
|
timeout = setTimeout(later, remaining);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user