diff --git a/dist/ionic-simple.js b/dist/ionic-simple.js index e69de29bb2..fdc2fa738a 100644 --- a/dist/ionic-simple.js +++ b/dist/ionic-simple.js @@ -0,0 +1,203 @@ + +(function(window, document, ionic) { + + ionic.Components = []; + + ionic.registerComponent = function(instance) { + ionic.Components.push(instance); + }; + + ionic.component = function(el) { + if(el) { + if(el.component) { + // this element has already been initialized as a component + return el.component; + } + for(var x = 0; x < ionic.Components.length; x++) { + if( ionic.Components[x].isComponent(el) ) { + // this element is a component, init its view + return ionic.Components[x].init(el); + } + } + } + }; + + function componentEvent(eventName, e) { + if (!e.gesture || !e.gesture.srcEvent || !e.gesture.srcEvent.target) return; + + var + component, + el = e.gesture.srcEvent.target; // get the original source event's target + + while(el) { + // climb up the tree looking to see if the target + // is or is in a registered component. If its already + // been set that its NOT a component don't bother. + if(el.isComponent !== false) { + component = ionic.component(el); + if(component) { + component[eventName] && component[eventName](e.gesture.srcEvent); + return; + } + // not sure if this element is a component yet, + // keep climbing up the tree and check again + // remember that this element is not a component so + // it can skip this process in the future + el.isComponent = false; + } + el = el.parentElement; + } + } + + function onTap(e) { + componentEvent("tap", e); + } + ionic.on("tap", onTap, window); + + function onDrag(e) { + componentEvent("drag", e); + } + ionic.on("drag", onDrag, window); + + function onRelease(e) { + componentEvent("release", e); + } + ionic.on("release", onRelease, window); + + + function initalize() { + // remove the ready listeners + document.removeEventListener( "DOMContentLoaded", initalize, false ); + window.removeEventListener( "load", initalize, false ); + + // trigger that the DOM is ready + ionic.trigger("domready"); + } + + // When the DOM is ready, initalize the webapp + if ( document.readyState === "complete" ) { + // DOM is already ready + setTimeout( initalize ); + } else { + // DOM isn't ready yet, add event listeners + document.addEventListener( "DOMContentLoaded", initalize, false ); + window.addEventListener( "load", initalize, false ); + } + +})(this, document, ionic);; +(function(ionic) { + + ionic.registerComponent({ + + name: "listview", + + isComponent: function(element) { + return false; + }, + + tap: function(e) { + + } + + }); + +})(ionic);; +(function(window, document, ionic) { + + ionic.fn = { + val: function() { + var ret, x; + for(x = 0; x < this.length; x++) { + ret = this[x].component.val.apply(this[x].component, arguments); + } + return ret; + } + } + + if (window.jQuery) { + // if jQuery is present then it should be the default + jq = window.jQuery; + + // extend the methods which are in ionic.fn and in jQuery.fn + for(var name in ionic.fn) { + var jQueryFn = jq.fn[name]; + jq.fn[name] = function() { + var + x, + ret; // if incase this isn't an ionic component + + for(x = 0; x < this.length; x++) { + ionic.component( this[x] ); + if( this[x].component ) { + ret = this[x].component[name].apply(this[x].component, arguments); + } + } + + // if this isn't an ionic component, run the usual jQuery fn + return jQueryFn.apply(this, arguments); + } + } + + } else { + // jQuery is not already present, so use our 'lil version instead + jq = { + + init: function(selector, context) { + context = context || document; + var + x, + dom = context.querySelectorAll(selector) || []; + for(x = 0; x < dom.length; x++) { + ionic.component( dom[x] ); + } + dom.__proto__ = ionic.fn; + dom.selector = selector || ''; + return dom; + } + + }; + + $ = function(selector, context) { + return jq.init(selector, context); + } + } + +})(this, document, ionic); +; +(function(ionic) { + + ionic.registerComponent({ + + isComponent: function(el) { + // this is a Toggle component if it has a "toggle" classname + return el.classList.contains("toggle"); + }, + + init: function(el) { + if(el) { + + // check if we've already created a Toggle instance for this element + if(!el.component) { + + // find all the required elements that make up a toggle + var opts = { + el: el, + checkbox: el.querySelector("input[type='checkbox']"), + track: el.querySelector(".track"), + handle: el.querySelector(".handle") + }; + + // validate its a well formed toggle with the required pieces + if(!opts.checkbox || !opts.track || !opts.handle) return; + + // initialize an instance of a Toggle + el.component = new ionic.views.Toggle(opts); + } + + return el.component; + } + } + + }); + +})(ionic); \ No newline at end of file diff --git a/dist/ionic.js b/dist/ionic.js index bc536e512d..7981acbd10 100644 --- a/dist/ionic.js +++ b/dist/ionic.js @@ -4,67 +4,50 @@ window.ionic = { controllers: {}, views: {} }; -;(function(ionic) { +; +(function(ionic) { + ionic.Animator = { + animate: function(element, className, fn) { + return { + leave: function() { + var endFunc = function() { + console.log('Animation finished for element', element); - ionic.Platform = { - detect: function() { - var platforms = []; + element.classList.remove('leave'); + element.classList.remove('leave-active'); - this._checkPlatforms(platforms); + element.removeEventListener('webkitTransitionEnd', endFunc); + element.removeEventListener('transitionEnd', endFunc); + }; + element.addEventListener('webkitTransitionEnd', endFunc); + element.addEventListener('transitionEnd', endFunc); - for(var i = 0; i < platforms.length; i++) { - document.body.classList.add('platform-' + platforms[i]); - } + element.classList.add('leave'); + element.classList.add('leave-active'); + return this; + }, + enter: function() { + var endFunc = function() { + console.log('Animation finished for element', element); - }, - _checkPlatforms: function(platforms) { - if(this.isCordova()) { - platforms.push('cordova'); - } - if(this.isIOS7()) { - platforms.push('ios7'); - } - }, + element.classList.remove('enter'); + element.classList.remove('enter-active'); - // Check if we are running in Cordova, which will have - // window.device available. - isCordova: function() { - return (window.cordova || window.PhoneGap || window.phonegap); - //&& /^file:\/{3}[^\/]/i.test(window.location.href) - //&& /ios|iphone|ipod|ipad|android/i.test(navigator.userAgent); - }, - isIOS7: function() { - if(!window.device) { - return false; - } - return parseFloat(window.device.version) >= 7.0; - } - } + element.removeEventListener('webkitTransitionEnd', endFunc); + element.removeEventListener('transitionEnd', endFunc); + }; + element.addEventListener('webkitTransitionEnd', endFunc); + element.addEventListener('transitionEnd', endFunc); - ionic.Platform.detect(); -})(window.ionic); -;(function(ionic) { - - ionic.Utils = { - /** - * extend method, - * also used for cloning when dest is an empty object - * @param {Object} dest - * @param {Object} src - * @parm {Boolean} merge do a merge - * @returns {Object} dest - */ - extend: function extend(dest, src, merge) { - for (var key in src) { - if(dest[key] !== undefined && merge) { - continue; + element.classList.add('enter'); + element.classList.add('enter-active'); + + return this; } - dest[key] = src[key]; - } - return dest; - }, - } -})(window.ionic); + }; + } + }; +})(ionic); ;/** * ion-events.js * @@ -270,6 +253,8 @@ window.ionic = { if(this === this.window) { // this is a window, then only allow the Tap gesture to be added ionic.Gestures.detection.register(ionic.Gestures.gestures.Tap); + ionic.Gestures.detection.register(ionic.Gestures.gestures.Drag); + ionic.Gestures.detection.register(ionic.Gestures.gestures.Release); } else { // everything else but the window for(var name in ionic.Gestures.gestures) { @@ -1610,61 +1595,121 @@ window.ionic = { }; })(window.ionic); ;(function(ionic) { - ionic.Animator = { - animate: function(element, className, fn) { - return { - leave: function() { - var endFunc = function() { - console.log('Animation finished for element', element); - element.classList.remove('leave'); - element.classList.remove('leave-active'); + ionic.Platform = { + detect: function() { + var platforms = []; - element.removeEventListener('webkitTransitionEnd', endFunc); - element.removeEventListener('transitionEnd', endFunc); - }; - element.addEventListener('webkitTransitionEnd', endFunc); - element.addEventListener('transitionEnd', endFunc); + this._checkPlatforms(platforms); - element.classList.add('leave'); - element.classList.add('leave-active'); - return this; - }, - enter: function() { - var endFunc = function() { - console.log('Animation finished for element', element); + for(var i = 0; i < platforms.length; i++) { + document.body.classList.add('platform-' + platforms[i]); + } - element.classList.remove('enter'); - element.classList.remove('enter-active'); - - element.removeEventListener('webkitTransitionEnd', endFunc); - element.removeEventListener('transitionEnd', endFunc); - }; - element.addEventListener('webkitTransitionEnd', endFunc); - element.addEventListener('transitionEnd', endFunc); - - element.classList.add('enter'); - element.classList.add('enter-active'); - - return this; - } - }; - } - }; -})(window.ionic); -;(function(ionic) { - ionic.ViewController = function(options) { - this.init(); - }; - - ionic.ViewController.prototype = { - // Initialize this view controller - init: function() { }, - // Destroy this view controller, including all child views - destroy: function() { + _checkPlatforms: function(platforms) { + if(this.isCordova()) { + platforms.push('cordova'); + } + if(this.isIOS7()) { + platforms.push('ios7'); + } + }, + + // Check if we are running in Cordova, which will have + // window.device available. + isCordova: function() { + return (window.cordova || window.PhoneGap || window.phonegap); + //&& /^file:\/{3}[^\/]/i.test(window.location.href) + //&& /ios|iphone|ipod|ipad|android/i.test(navigator.userAgent); + }, + isIOS7: function() { + if(!window.device) { + return false; + } + return parseFloat(window.device.version) >= 7.0; } - }; + } + + ionic.Platform.detect(); +})(window.ionic); +;(function(window, document, ionic) { + + // polyfill use to simulate native "tap" + function inputTapPolyfill(ele, e) { + if(ele.type === "radio" || ele.type === "checkbox") { + ele.checked = !ele.checked; + } else if(ele.type === "submit" || ele.type === "button") { + ele.click(); + } else { + ele.focus(); + } + e.stopPropagation(); + e.preventDefault(); + return false; + } + + function tapPolyfill(e) { + // if the source event wasn't from a touch event then don't use this polyfill + if(!e.gesture || e.gesture.pointerType !== "touch" || !e.gesture.srcEvent) return; + + var + e = e.gesture.srcEvent, // evaluate the actual source event, not the created event by gestures.js + ele = e.target; + + while(ele) { + if( ele.tagName === "INPUT" || ele.tagName === "TEXTAREA" || ele.tagName === "SELECT" ) { + return inputTapPolyfill(ele, e); + } else if( ele.tagName === "LABEL" ) { + if(ele.control) { + return inputTapPolyfill(ele.control, e); + } + } else if( ele.tagName === "A" || ele.tagName === "BUTTON" ) { + ele.click(); + e.stopPropagation(); + e.preventDefault(); + return false; + } + ele = ele.parentElement; + } + + // they didn't tap one of the above elements + // if the currently active element is an input, and they tapped outside + // of the current input, then unset its focus (blur) so the keyboard goes away + var activeElement = document.activeElement; + if(activeElement && (activeElement.tagName === "INPUT" || activeElement.tagName === "TEXTAREA" || activeElement.tagName === "SELECT")) { + activeElement.blur(); + e.stopPropagation(); + e.preventDefault(); + return false; + } + } + + // global tap event listener polyfill for HTML elements that were "tapped" by the user + ionic.on("tap", tapPolyfill, window); + +})(this, document, ionic); +;(function(ionic) { + + ionic.Utils = { + /** + * extend method, + * also used for cloning when dest is an empty object + * @param {Object} dest + * @param {Object} src + * @parm {Boolean} merge do a merge + * @returns {Object} dest + */ + extend: function extend(dest, src, merge) { + for (var key in src) { + if(dest[key] !== undefined && merge) { + continue; + } + dest[key] = src[key]; + } + return dest; + }, + } })(window.ionic); ; (function(ionic) { @@ -1710,7 +1755,8 @@ window.ionic = { }; })(ionic); -;(function(ionic) { +; +(function(ionic) { ionic.views.HeaderBar = function(opts) { this.el = opts.el; @@ -1736,6 +1782,31 @@ window.ionic = { } }; +})(ionic); +; +(function(ionic) { + + ionic.views.SideMenu = function(opts) { + this.el = opts.el; + this.width = opts.width; + this.isEnabled = opts.isEnabled || true; + }; + + ionic.views.SideMenu.prototype = { + getFullWidth: function() { + return this.width; + }, + setIsEnabled: function(isEnabled) { + this.isEnabled = isEnabled; + }, + bringUp: function() { + this.el.style.zIndex = 0; + }, + pushDown: function() { + this.el.style.zIndex = -1; + } + }; + })(ionic); ;(function(ionic) { @@ -1939,31 +2010,6 @@ ionic.views.TabBar.prototype = { })(window.ionic); ; -(function(ionic) { - - ionic.views.SideMenu = function(opts) { - this.el = opts.el; - this.width = opts.width; - this.isEnabled = opts.isEnabled || true; - }; - - ionic.views.SideMenu.prototype = { - getFullWidth: function() { - return this.width; - }, - setIsEnabled: function(isEnabled) { - this.isEnabled = isEnabled; - }, - bringUp: function() { - this.el.style.zIndex = 0; - }, - pushDown: function() { - this.el.style.zIndex = -1; - } - }; - -})(ionic); -; (function(ionic) { ionic.views.Toggle = function(opts) { @@ -1971,6 +2017,7 @@ ionic.views.TabBar.prototype = { this.checkbox = opts.checkbox; this.track = opts.track; this.handle = opts.handle; + this.openPercent = -1; // remember that this element, and all its children are apart of a component // and assign the component instance to each element so the lookups @@ -1980,21 +2027,55 @@ ionic.views.TabBar.prototype = { this.track.isComponent = true; this.handle.component = this; this.handle.isComponent = true; - - // ensure the handle is draggable - this.handle.draggable = true; }; ionic.views.Toggle.prototype = { tap: function(e) { - e.stopPropa - return false; + this.val( !this.checkbox.checked ); + }, + + drag: function(e) { + var slidePageLeft = this.track.offsetLeft + (this.handle.offsetWidth / 2); + var slidePageRight = this.track.offsetLeft + this.track.offsetWidth - (this.handle.offsetWidth / 2); + + if(e.pageX >= slidePageRight - 4) { + this.val(true); + } else if(e.pageX <= slidePageLeft) { + this.val(false); + } else { + this.setOpenPercent( Math.round( (1 - ((slidePageRight - e.pageX) / (slidePageRight - slidePageLeft) )) * 100) ); + } + }, + + setOpenPercent: function(openPercent) { + // only make a change if the new open percent has changed + if(this.openPercent < 0 || (openPercent < (this.openPercent - 3) || openPercent > (this.openPercent + 3) ) ) { + this.openPercent = openPercent; + + if(openPercent === 0) { + this.val(false); + } else if(openPercent === 100) { + this.val(true); + } else { + var openPixel = Math.round( (openPercent / 100) * this.track.offsetWidth - (this.handle.offsetWidth) ); + openPixel = (openPixel < 1 ? 0 : openPixel); + this.handle.style.webkitTransform = 'translate3d(' + openPixel + 'px,0,0)'; + } + } + }, + + release: function(e) { + this.val( this.openPercent >= 50 ); }, val: function(value) { if(value === true || value === false) { + if(this.handle.style.webkitTransform !== "") { + this.handle.style.webkitTransform = ""; + } this.checkbox.checked = value; + this.openPercent = (value ? 100 : 0); } return this.checkbox.checked; } @@ -2535,59 +2616,17 @@ ionic.controllers.TabBarController.prototype = { } })(window.ionic); -;(function(window, document, ionic) { +;(function(ionic) { + ionic.ViewController = function(options) { + this.init(); + }; - // polyfill use to simulate native "tap" - function inputTapPolyfill(ele, e) { - if(ele.type === "radio" || ele.type === "checkbox") { - ele.checked = !ele.checked; - } else if(ele.type === "submit" || ele.type === "button") { - ele.click(); - } else { - ele.focus(); + ionic.ViewController.prototype = { + // Initialize this view controller + init: function() { + }, + // Destroy this view controller, including all child views + destroy: function() { } - e.stopPropagation(); - e.preventDefault(); - return false; - } - - function tapPolyfill(e) { - // if the source event wasn't from a touch event then don't use this polyfill - if(!e.gesture || e.gesture.pointerType !== "touch" || !e.gesture.srcEvent) return; - - var - e = e.gesture.srcEvent, // evaluate the actual source event, not the created event by gestures.js - ele = e.target; - - while(ele) { - if( ele.tagName === "INPUT" || ele.tagName === "TEXTAREA" || ele.tagName === "SELECT" ) { - return inputTapPolyfill(ele, e); - } else if( ele.tagName === "LABEL" ) { - if(ele.control) { - return inputTapPolyfill(ele.control, e); - } - } else if( ele.tagName === "A" || ele.tagName === "BUTTON" ) { - ele.click(); - e.stopPropagation(); - e.preventDefault(); - return false; - } - ele = ele.parentElement; - } - - // they didn't tap one of the above elements - // if the currently active element is an input, and they tapped outside - // of the current input, then unset its focus (blur) so the keyboard goes away - var activeElement = document.activeElement; - if(activeElement && (activeElement.tagName === "INPUT" || activeElement.tagName === "TEXTAREA" || activeElement.tagName === "SELECT")) { - activeElement.blur(); - e.stopPropagation(); - e.preventDefault(); - return false; - } - } - - // global tap event listener polyfill for HTML elements that were "tapped" by the user - ionic.on("tap", tapPolyfill, window); - -})(this, document, ionic); + }; +})(window.ionic); diff --git a/js/ext/angular/src/directive/ionicContent.js b/js/ext/angular/src/directive/ionicContent.js new file mode 100644 index 0000000000..8ae4e723b8 --- /dev/null +++ b/js/ext/angular/src/directive/ionicContent.js @@ -0,0 +1,46 @@ +angular.module('ionic.ui.content', {}) + +/* +.directive('content', function() { + return { + restrict: 'E', + replace: true, + template: '
' + } +}); +*/ + +/* +.directive('content', function() { + return { + restrict: 'E', + replace: true, + transclude: true, + scope: { + hasHeader: '@', + hasTabs: '@' + }, + template: '
' + } +}) +*/ + +.directive('content', function() { + return { + restrict: 'E', + replace: true, + transclude: true, + scope: true, + template: '
', + compile: function(element, attr, transclude, navCtrl) { + return function($scope, $element, $attr) { + $scope.hasHeader = attr.hasHeader; + $scope.hasTabs = attr.hasTabs; + + var newScope = $scope.$parent.$new(); + + $element.append(transclude(newScope)); + }; + } + } +}) diff --git a/js/ext/angular/src/ionicNav.js b/js/ext/angular/src/directive/ionicNav.js similarity index 78% rename from js/ext/angular/src/ionicNav.js rename to js/ext/angular/src/directive/ionicNav.js index 6fa71ef83f..baf1b719cc 100644 --- a/js/ext/angular/src/ionicNav.js +++ b/js/ext/angular/src/directive/ionicNav.js @@ -1,24 +1,8 @@ -angular.module('ionic.ui', ['ngTouch']) - -.directive('content', function() { - return { - restrict: 'E', - replace: true, - transclude: true, - scope: true, - template: '
', - compile: function(element, attr, transclude, navCtrl) { - return function($scope, $element, $attr) { - $scope.hasHeader = attr.hasHeader; - }; - } - } -}) +angular.module('ionic.ui.nav', ['ionic.ui']) .controller('NavCtrl', function($scope, $element, $compile) { var _this = this; - angular.extend(this, ionic.controllers.NavController.prototype); ionic.controllers.NavController.call(this, { @@ -42,7 +26,6 @@ angular.module('ionic.ui', ['ngTouch']) } $scope.pushController = function(controller) { - //console.log('PUSHING OCNTROLLER', controller); _this.push(controller); } diff --git a/js/ext/angular/src/ionicSideMenu.js b/js/ext/angular/src/directive/ionicSideMenu.js similarity index 98% rename from js/ext/angular/src/ionicSideMenu.js rename to js/ext/angular/src/directive/ionicSideMenu.js index a3ec635fd2..37e6826bcd 100644 --- a/js/ext/angular/src/ionicSideMenu.js +++ b/js/ext/angular/src/directive/ionicSideMenu.js @@ -1,4 +1,4 @@ -angular.module('ionic.ui', []) +angular.module('ionic.ui.sideMenu', []) .controller('SideMenuCtrl', function($scope) { var _this = this; diff --git a/js/ext/angular/src/ionicTabBar.js b/js/ext/angular/src/directive/ionicTabBar.js similarity index 88% rename from js/ext/angular/src/ionicTabBar.js rename to js/ext/angular/src/directive/ionicTabBar.js index e442a6473a..2985d6da92 100644 --- a/js/ext/angular/src/ionicTabBar.js +++ b/js/ext/angular/src/directive/ionicTabBar.js @@ -1,17 +1,4 @@ -angular.module('ionic.ui', []) - -.directive('content', function() { - return { - restrict: 'E', - replace: true, - transclude: true, - scope: { - hasHeader: '@', - hasTabs: '@' - }, - template: '
' - } -}) +angular.module('ionic.ui.tabs', ['ionic.ui.content']) .controller('TabsCtrl', function($scope) { var _this = this; diff --git a/js/ext/angular/src/ionicContent.js b/js/ext/angular/src/ionicContent.js deleted file mode 100644 index ac4a2d091b..0000000000 --- a/js/ext/angular/src/ionicContent.js +++ /dev/null @@ -1,9 +0,0 @@ -angular.module('ionic.ui.content', {}) - -.directive('content', function() { - return { - restrict: 'E', - replace: true, - template: '
' - } -}); diff --git a/js/ext/angular/test/nav.html b/js/ext/angular/test/nav.html index e27c1e8feb..b69c28c8d0 100644 --- a/js/ext/angular/test/nav.html +++ b/js/ext/angular/test/nav.html @@ -48,7 +48,8 @@ - + + - + + + + + + + +
+
+ +

Slide me

+
+
+

Slide me side to side!

+
+
+ +

Left

+ +
+ +

Items

+ +
+
+

Tab Bars

+
+ +

Home

+ +
+
+ +
+
+

About

+
+ +

About Us

+
+
+ +
+
+

Settings

+
+ +

Settings

+
+
+
+
+
+ + + + + + + diff --git a/js/ext/angular/test/tabs.html b/js/ext/angular/test/tabs.html index 9434d435fc..0d548143f9 100644 --- a/js/ext/angular/test/tabs.html +++ b/js/ext/angular/test/tabs.html @@ -50,7 +50,8 @@ - + +