List items animation and some other shit

This commit is contained in:
Max Lynch
2013-10-10 15:08:31 -05:00
parent 5d165a8310
commit dedc5e9b87
10 changed files with 376 additions and 22 deletions

26
dist/ionic-angular.js vendored
View File

@ -209,7 +209,6 @@ angular.module('ionic.ui.list', ['ionic.service', 'ngAnimate'])
return { return {
restrict: 'E', restrict: 'E',
replace: true, replace: true,
transclude: true,
scope: { scope: {
isEditing: '=', isEditing: '=',
items: '=', items: '=',
@ -229,8 +228,31 @@ angular.module('ionic.ui.list', ['ionic.service', 'ngAnimate'])
if(attr.animation) { if(attr.animation) {
$element.addClass(attr.animation); $element.addClass(attr.animation);
} }
}
}
}
})
$element.append(transclude($scope)); .directive('listSimple', function() {
return {
restrict: 'E',
replace: true,
transclude: true,
scope: {
isEditing: '=',
items: '=',
animation: '@',
deleteIcon: '@'
},
template: '<ul class="list" ng-class="{\'list-editing\': isEditing}" ng-transclude>' +
'</ul>',
compile: function(element, attr, transclude) {
return function($scope, $element, $attr) {
var lv = new ionic.views.List({el: $element[0]});
if(attr.animation) {
$element.addClass(attr.animation);
}
} }
} }
} }

14
dist/ionic-ios7.css vendored
View File

@ -307,6 +307,13 @@ table {
-moz-box-sizing: border-box; -moz-box-sizing: border-box;
box-sizing: border-box; } box-sizing: border-box; }
a {
-webkit-user-drag: none;
-webkit-tap-highlight-color: transparent; }
a:focus, button:focus {
outline: 0; }
body { body {
position: fixed; position: fixed;
top: 0; top: 0;
@ -1078,6 +1085,9 @@ a.list-item {
.list-item-content > i:last-child { .list-item-content > i:last-child {
float: right; } float: right; }
.list-item-sliding {
-webkit-transition: -webkit-transform 0.1s ease-in-out; }
.list-item-edit { .list-item-edit {
position: absolute; position: absolute;
z-index: 0; z-index: 0;
@ -1096,8 +1106,10 @@ a.list-item {
position: absolute; position: absolute;
z-index: 0; z-index: 0;
right: 0; right: 0;
top: 0; } top: 0;
height: 100%; }
.list-item-buttons .button { .list-item-buttons .button {
height: 100%;
border-radius: 0; border-radius: 0;
border: none; } border: none; }

14
dist/ionic.css vendored
View File

@ -1371,6 +1371,13 @@ table {
-moz-box-sizing: border-box; -moz-box-sizing: border-box;
box-sizing: border-box; } box-sizing: border-box; }
a {
-webkit-user-drag: none;
-webkit-tap-highlight-color: transparent; }
a:focus, button:focus {
outline: 0; }
body { body {
position: fixed; position: fixed;
top: 0; top: 0;
@ -2165,6 +2172,9 @@ a.list-item {
.list-item-content > i:last-child { .list-item-content > i:last-child {
float: right; } float: right; }
.list-item-sliding {
-webkit-transition: -webkit-transform 0.1s ease-in-out; }
.list-item-edit { .list-item-edit {
position: absolute; position: absolute;
z-index: 0; z-index: 0;
@ -2183,8 +2193,10 @@ a.list-item {
position: absolute; position: absolute;
z-index: 0; z-index: 0;
right: 0; right: 0;
top: 0; } top: 0;
height: 100%; }
.list-item-buttons .button { .list-item-buttons .button {
height: 100%;
border-radius: 0; border-radius: 0;
border: none; } border: none; }

139
dist/ionic.js vendored
View File

@ -1785,6 +1785,18 @@ window.ionic = {
this.el = opts.el; this.el = opts.el;
this.dragThresholdX = 10;
this._initDrag();
window.ionic.onGesture('drag', function(e) {
_this._handleDrag(e);
}, this.el);
window.ionic.onGesture('release', function(e) {
_this._handleEndDrag(e);
}, this.el);
/*
window.ionic.onGesture('swipeleft', function(e) { window.ionic.onGesture('swipeleft', function(e) {
_this._handleSwipeLeft(e); _this._handleSwipeLeft(e);
e.gesture.stopDetect(); e.gesture.stopDetect();
@ -1796,9 +1808,130 @@ window.ionic = {
e.gesture.stopDetect(); e.gesture.stopDetect();
return false; return false;
}, this.el); }, this.el);
*/
}; };
ionic.views.List.prototype = { ionic.views.List.prototype = {
_initDrag: function() {
this._offsetX = 0;
this._isDragging = false;
this._currentDrag = null;
},
_startDrag: function(e) {
this._isDragging = false;
// Grab the content item
if(e.target.classList.contains('list-item')) {
content = e.target.querySelector('.list-item-content');
} else if(e.target.classList.contains('list-item-content')) {
content = e.target;
}
if(!content) {
return;
}
content.classList.remove('list-item-sliding');
// Grab the buttons
buttons = content.parentNode.querySelector('.list-item-buttons');
if(!buttons) {
return;
}
buttonsWidth = buttons.offsetWidth;
this._currentDrag = {
buttonsWidth: buttonsWidth,
content: content
};
},
_handleEndDrag: function(e) {
var _this = this;
// If we are currently dragging, we want to snap back into place
if(this._currentDrag) {
// The final resting point X will be the width of the exposed buttons
var restingPoint = -this._currentDrag.buttonsWidth;
// Check if the drag didn't clear the buttons and we aren't moving fast enough to swipe open
if(e.gesture.deltaX > -this._currentDrag.buttonsWidth) {
if(e.gesture.direction == "left" && Math.abs(e.gesture.velocityX) < 0.3) {
restingPoint = 0;
} else if(e.gesture.direction == "right") {
restingPoint = 0;
}
}
var content = this._currentDrag.content;
var onRestingAnimationEnd = function(e) {
if(e.propertyName == '-webkit-transform') {
content.classList.remove('list-item-sliding');
}
e.target.removeEventListener('webkitTransitionEnd', onRestingAnimationEnd);
}
window.requestAnimationFrame(function() {
var currentX = parseFloat(_this._currentDrag.content.style.webkitTransform.replace('translate3d(', '').split(',')[0]) || 0;
if(currentX !== restingPoint) {
_this._currentDrag.content.classList.add('list-item-sliding');
_this._currentDrag.content.addEventListener('webkitTransitionEnd', onRestingAnimationEnd);
}
_this._currentDrag.content.style.webkitTransform = 'translate3d(' + restingPoint + 'px, 0, 0)';
_this._initDrag();
});
} else {
this._initDrag();
}
},
/**
* Process the drag event to move the item to the left or right.
*/
_handleDrag: function(e) {
var _this = this, content, buttons;
if(!this._currentDrag) {
this._startDrag(e);
}
window.requestAnimationFrame(function() {
if(!_this._currentDrag) {
return;
}
// Calculate difference from the tap points
if(!_this._isDragging && Math.abs(e.gesture.deltaX) > _this.dragThresholdX) {
_this._isDragging = true;
// Grab the starting X point for this item
_this._offsetX = parseFloat(_this._currentDrag.content.style.webkitTransform.replace('translate3d(', '').split(',')[0]) || 0;
}
if(_this._isDragging) {
// Grab the new X point, capping it at zero
var newX = Math.min(0, _this._offsetX + e.gesture.deltaX);
if(newX < -buttonsWidth && !_this._deltaSlowX) {
_this._deltaSlowX = e.gesture.deltaX;
}
if(newX < -buttonsWidth) {
newX = Math.min(_this._deltaSlowX, _this._deltaSlowX + (((e.gesture.deltaX - _this._deltaSlowX) * 0.4)));
}
console.log(newX);
_this._currentDrag.content.style.webkitTransform = 'translate3d(' + newX + 'px, 0, 0)';
}
});
},
_handleSwipeLeft: function(e) { _handleSwipeLeft: function(e) {
window.requestAnimationFrame(function() { window.requestAnimationFrame(function() {
@ -1806,12 +1939,6 @@ window.ionic = {
cl = item.classList, cl = item.classList,
content, buttons, buttonsWidth; content, buttons, buttonsWidth;
// Grab the content item
if(cl.contains('list-item')) {
content = item.querySelector('.list-item-content');
} else if(cl.contains('list-item-content')) {
content = item;
}
if(!content) { if(!content) {
return; return;

View File

@ -127,18 +127,24 @@
</list> </list>
</div> </div>
</div> </div>
<!-- The projects side menu -->
<menu side="left"> <menu side="left">
<header class="bar bar-header bar-secondary"> <header class="bar bar-header bar-secondary">
<button class="button button-clear button-primary">Edit</button> <button class="button button-clear button-primary" ng-click="toggleProjectEditing()">Edit</button>
<div class="toderp-small-logo"></div> <div class="toderp-small-logo"></div>
<button class="button button-icon" ng-click="showSettings()"><i class="icon-gear-a"></i></button> <button class="button button-icon" ng-click="showSettings()"><i class="icon-gear-a"></i></button>
</header> </header>
<content has-header="true"> <content has-header="true">
<form ng-submit="addProject(newProject)"> <form ng-submit="addProject(newProject)">
<input type="text" ng-model="newProject.title" placeholder="Create a new list..."> <input type="text" ng-model="newProject.title" placeholder="Create a new list...">
</form> </form>
<list> <list-simple is-editing="isEditingProjects">
<li class="list-item list-item-primary" ng-class="{active: project.$id == activeProject.project.name()}" ng-repeat="project in projects"> <li class="list-item list-item-primary" ng-class="{active: project.$id == activeProject.project.name()}" ng-repeat="project in projects">
<div class="list-item-edit">
<i class="icon-minus-circled"></i>
</div>
<div class="list-item-content" ng-click="selectProject(project)"> <div class="list-item-content" ng-click="selectProject(project)">
{{project.title}} {{project.title}}
</div> </div>
@ -146,7 +152,7 @@
<button class="button button-danger" ng-click="deleteProject(project)">Delete</button> <button class="button button-danger" ng-click="deleteProject(project)">Delete</button>
</div> </div>
</li> </li>
</list> </list-simple>
</content> </content>
</menu> </menu>
</side-menu-ctrl> </side-menu-ctrl>

View File

@ -74,6 +74,8 @@ angular.module('ionic.todo.controllers', ['ionic.todo'])
$scope.lastProject = null; $scope.lastProject = null;
*/ */
$scope.isEditingProjects = false;
// Load our settings modal // Load our settings modal
Modal.fromTemplateUrl('settings.html', function(modal) { Modal.fromTemplateUrl('settings.html', function(modal) {
$scope.settingsModal = modal; $scope.settingsModal = modal;
@ -183,6 +185,10 @@ angular.module('ionic.todo.controllers', ['ionic.todo'])
}); });
}; };
$scope.toggleProjectEditing = function() {
$scope.isEditingProjects = !$scope.isEditingProjects;
};
var projectsRef = new Firebase(FIREBASE_URL + '/project_list'); var projectsRef = new Firebase(FIREBASE_URL + '/project_list');
$scope.projects = angularFireCollection(projectsRef.limit(100), function(snapshot) { $scope.projects = angularFireCollection(projectsRef.limit(100), function(snapshot) {
if(!snapshot.val()) { if(!snapshot.val()) {

View File

@ -27,7 +27,6 @@ angular.module('ionic.ui.list', ['ionic.service', 'ngAnimate'])
return { return {
restrict: 'E', restrict: 'E',
replace: true, replace: true,
transclude: true,
scope: { scope: {
isEditing: '=', isEditing: '=',
items: '=', items: '=',
@ -47,8 +46,31 @@ angular.module('ionic.ui.list', ['ionic.service', 'ngAnimate'])
if(attr.animation) { if(attr.animation) {
$element.addClass(attr.animation); $element.addClass(attr.animation);
} }
}
$element.append(transclude($scope)); }
}
})
.directive('listSimple', function() {
return {
restrict: 'E',
replace: true,
transclude: true,
scope: {
isEditing: '=',
items: '=',
animation: '@',
deleteIcon: '@'
},
template: '<ul class="list" ng-class="{\'list-editing\': isEditing}" ng-transclude>' +
'</ul>',
compile: function(element, attr, transclude) {
return function($scope, $element, $attr) {
var lv = new ionic.views.List({el: $element[0]});
if(attr.animation) {
$element.addClass(attr.animation);
}
} }
} }
} }

View File

@ -5,6 +5,18 @@
this.el = opts.el; this.el = opts.el;
this.dragThresholdX = 10;
this._initDrag();
window.ionic.onGesture('drag', function(e) {
_this._handleDrag(e);
}, this.el);
window.ionic.onGesture('release', function(e) {
_this._handleEndDrag(e);
}, this.el);
/*
window.ionic.onGesture('swipeleft', function(e) { window.ionic.onGesture('swipeleft', function(e) {
_this._handleSwipeLeft(e); _this._handleSwipeLeft(e);
e.gesture.stopDetect(); e.gesture.stopDetect();
@ -16,9 +28,130 @@
e.gesture.stopDetect(); e.gesture.stopDetect();
return false; return false;
}, this.el); }, this.el);
*/
}; };
ionic.views.List.prototype = { ionic.views.List.prototype = {
_initDrag: function() {
this._offsetX = 0;
this._isDragging = false;
this._currentDrag = null;
},
_startDrag: function(e) {
this._isDragging = false;
// Grab the content item
if(e.target.classList.contains('list-item')) {
content = e.target.querySelector('.list-item-content');
} else if(e.target.classList.contains('list-item-content')) {
content = e.target;
}
if(!content) {
return;
}
content.classList.remove('list-item-sliding');
// Grab the buttons
buttons = content.parentNode.querySelector('.list-item-buttons');
if(!buttons) {
return;
}
buttonsWidth = buttons.offsetWidth;
this._currentDrag = {
buttonsWidth: buttonsWidth,
content: content
};
},
_handleEndDrag: function(e) {
var _this = this;
// If we are currently dragging, we want to snap back into place
if(this._currentDrag) {
// The final resting point X will be the width of the exposed buttons
var restingPoint = -this._currentDrag.buttonsWidth;
// Check if the drag didn't clear the buttons and we aren't moving fast enough to swipe open
if(e.gesture.deltaX > -this._currentDrag.buttonsWidth) {
if(e.gesture.direction == "left" && Math.abs(e.gesture.velocityX) < 0.3) {
restingPoint = 0;
} else if(e.gesture.direction == "right") {
restingPoint = 0;
}
}
var content = this._currentDrag.content;
var onRestingAnimationEnd = function(e) {
if(e.propertyName == '-webkit-transform') {
content.classList.remove('list-item-sliding');
}
e.target.removeEventListener('webkitTransitionEnd', onRestingAnimationEnd);
}
window.requestAnimationFrame(function() {
var currentX = parseFloat(_this._currentDrag.content.style.webkitTransform.replace('translate3d(', '').split(',')[0]) || 0;
if(currentX !== restingPoint) {
_this._currentDrag.content.classList.add('list-item-sliding');
_this._currentDrag.content.addEventListener('webkitTransitionEnd', onRestingAnimationEnd);
}
_this._currentDrag.content.style.webkitTransform = 'translate3d(' + restingPoint + 'px, 0, 0)';
_this._initDrag();
});
} else {
this._initDrag();
}
},
/**
* Process the drag event to move the item to the left or right.
*/
_handleDrag: function(e) {
var _this = this, content, buttons;
if(!this._currentDrag) {
this._startDrag(e);
}
window.requestAnimationFrame(function() {
if(!_this._currentDrag) {
return;
}
// Calculate difference from the tap points
if(!_this._isDragging && Math.abs(e.gesture.deltaX) > _this.dragThresholdX) {
_this._isDragging = true;
// Grab the starting X point for this item
_this._offsetX = parseFloat(_this._currentDrag.content.style.webkitTransform.replace('translate3d(', '').split(',')[0]) || 0;
}
if(_this._isDragging) {
// Grab the new X point, capping it at zero
var newX = Math.min(0, _this._offsetX + e.gesture.deltaX);
if(newX < -buttonsWidth && !_this._deltaSlowX) {
_this._deltaSlowX = e.gesture.deltaX;
}
if(newX < -buttonsWidth) {
newX = Math.min(_this._deltaSlowX, _this._deltaSlowX + (((e.gesture.deltaX - _this._deltaSlowX) * 0.4)));
}
console.log(newX);
_this._currentDrag.content.style.webkitTransform = 'translate3d(' + newX + 'px, 0, 0)';
}
});
},
_handleSwipeLeft: function(e) { _handleSwipeLeft: function(e) {
window.requestAnimationFrame(function() { window.requestAnimationFrame(function() {
@ -26,12 +159,6 @@
cl = item.classList, cl = item.classList,
content, buttons, buttonsWidth; content, buttons, buttonsWidth;
// Grab the content item
if(cl.contains('list-item')) {
content = item.querySelector('.list-item-content');
} else if(cl.contains('list-item-content')) {
content = item;
}
if(!content) { if(!content) {
return; return;

View File

@ -98,6 +98,7 @@ a.list-item {
} }
} }
.list-item-content { .list-item-content {
position: relative; position: relative;
@ -115,6 +116,10 @@ a.list-item {
} }
} }
.list-item-sliding {
-webkit-transition: -webkit-transform 0.1s ease-in-out;
}
.list-item-edit { .list-item-edit {
position: absolute; position: absolute;
z-index: 0; z-index: 0;
@ -138,8 +143,10 @@ a.list-item {
z-index: 0; z-index: 0;
right: 0; right: 0;
top: 0; top: 0;
height: 100%;
.button { .button {
height: 100%;
border-radius: 0; border-radius: 0;
border: none; border: none;
} }

View File

@ -4,6 +4,17 @@
@include box-sizing(border-box); @include box-sizing(border-box);
} }
a {
-webkit-user-drag: none;
-webkit-tap-highlight-color: transparent;
}
a, button {
&:focus {
outline: 0;
}
}
body { body {
position: fixed; position: fixed;
top: 0; top: 0;
@ -20,8 +31,10 @@ body {
text-rendering: optimizeLegibility; text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-webkit-text-size-adjust: none; -webkit-text-size-adjust: none;
text-size-adjust: none; text-size-adjust: none;
-webkit-tap-highlight-color: transparent; -webkit-tap-highlight-color: transparent;
-webkit-user-drag: none; -webkit-user-drag: none;
-webkit-user-select: none; -webkit-user-select: none;