From 97e3e57082f97757c941166d978b68e7c3c29921 Mon Sep 17 00:00:00 2001 From: Gustavo Bobrow Date: Thu, 9 Oct 2014 17:41:13 -0300 Subject: [PATCH 1/9] removing JQUERY, lost fade in and slow scrolling effects though --- bower.json | 3 +-- demo/index.html | 3 --- package.json | 2 +- src/tour/tour.js | 40 +++++++++++++++++++++------------------- 4 files changed, 23 insertions(+), 25 deletions(-) diff --git a/bower.json b/bower.json index 57043e0..39ef260 100644 --- a/bower.json +++ b/bower.json @@ -31,8 +31,7 @@ "package.json" ], "dependencies": { - "angular": "~1.2.x", - "jquery": "~2.0.3" + "angular": "~1.2.x" }, "devDependencies": { "angular-mocks": "~1.x", diff --git a/demo/index.html b/demo/index.html index 523fde8..f0c5f98 100644 --- a/demo/index.html +++ b/demo/index.html @@ -18,9 +18,6 @@ - - - diff --git a/package.json b/package.json index b91b085..5da9a48 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "grunt-ngmin-concat": "~0.1.0", "grunt-karma": "~0.7.1", "grunt-html2js": "~0.1.3", - "karma": "~0.10.4", + "karma": "~0.12.0", "jshint-stylish": "~0.1.3", "load-grunt-tasks": "~0.2.0", "matchdep": "~0.1.1", diff --git a/src/tour/tour.js b/src/tour/tour.js index d2a19c6..124abfd 100644 --- a/src/tour/tour.js +++ b/src/tour/tour.js @@ -191,11 +191,13 @@ angular.module('angular-tour.tour', []) return; } - if(scope.ttAnimation) + /*if(scope.ttAnimation) tourtip.fadeIn(); else { tourtip.css({ display: 'block' }); - } + }*/ + tourtip.css({ display: 'block' }); + tourtip.removeClass('ng-hide'); // Append it to the dom element.after( tourtip ); @@ -209,38 +211,38 @@ angular.module('angular-tour.tour', []) var updatePosition = function() { // Get the position of the directive element - position = targetElement.position(); + position = targetElement[0]; - ttWidth = tourtip.width(); - ttHeight = tourtip.height(); + ttWidth = tourtip[0].offsetWidth; + ttHeight = tourtip[0].offsetHeight; - width = targetElement.width(); - height = targetElement.height(); + width = targetElement[0].offsetWidth; + height = targetElement[0].offsetHeight; // Calculate the tourtip's top and left coordinates to center it switch ( scope.ttPlacement ) { case 'right': ttPosition = { - top: position.top, - left: position.left + width + scope.ttOffset + top: position.offsetTop, + left: position.offsetLeft + width + scope.ttOffset }; break; case 'bottom': ttPosition = { - top: position.top + height + scope.ttOffset, - left: position.left + top: position.offsetTop + height + scope.ttOffset, + left: position.offsetLeft }; break; case 'left': ttPosition = { - top: position.top, - left: position.left - ttWidth - scope.ttOffset + top: position.offsetTop, + left: position.offsetLeft - ttWidth - scope.ttOffset }; break; default: ttPosition = { - top: position.top - ttHeight - scope.ttOffset, - left: position.left + top: position.offsetTop - ttHeight - scope.ttOffset, + left: position.offsetLeft }; break; } @@ -262,7 +264,7 @@ angular.module('angular-tour.tour', []) } function hide() { - tourtip.detach(); + tourtip.addClass('ng-hide'); angular.element($window).unbind('resize.' + scope.$id); } @@ -375,15 +377,15 @@ angular.module('angular-tour.tour', []) * ScrollTo * Smoothly scroll to a dom element */ - .factory('scrollTo', function() { + .factory('scrollTo', function($window) { return function(target, offsetY, offsetX, speed) { if(target) { offsetY = offsetY || -100; offsetX = offsetX || -100; speed = speed || 500; - $('html,body').stop().animate({scrollTop: target.offset().top + offsetY, scrollLeft: target.offset().left + offsetX}, speed); + $window.scrollTo(target[0].offsetLeft + offsetX, target[0].offsetTop + offsetY); } else { - $('html,body').stop().animate({scrollTop: 0}, speed); + $window.scrollTo(0, 0); } }; }); \ No newline at end of file From 41703f20c828327d87707348fb4f7d8b548407b2 Mon Sep 17 00:00:00 2001 From: britztopher Date: Thu, 16 Oct 2014 09:17:06 -0400 Subject: [PATCH 2/9] added fade in for tourtips --- src/tour/tour.scss | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/tour/tour.scss b/src/tour/tour.scss index 6fb1aad..807161f 100644 --- a/src/tour/tour.scss +++ b/src/tour/tour.scss @@ -10,6 +10,10 @@ font-weight: 400; max-width: 400px; border-radius: 10px; + -webkit-animation: fadeIn 0.3s both ease-in; + -moz-animation: fadeIn 0.3s both ease-in; + animation: fadeIn 0.3s both ease-in; + p { color: #CBD0D4; font-size: .9em; @@ -95,4 +99,32 @@ color: #eee!important; } } + + @-webkit-keyframes fadeIn { + from { + opacity: 0; + } + + to { + opacity: 1; + } + } + @-moz-keyframes fadeIn { + from { + opacity: 0; + } + + to { + opacity: 1; + } + } + @keyframes fadeIn { + from { + opacity: 0; + } + + to { + opacity: 1; + } + } } From 7c3d384671dcefae489253e1beb486e37aac46d9 Mon Sep 17 00:00:00 2001 From: Brian Yanosik Date: Fri, 22 May 2015 14:14:58 -0400 Subject: [PATCH 3/9] enabled smooth scrolling. --- src/tour/tour.js | 697 ++++++++++++++++++++++++++--------------------- 1 file changed, 383 insertions(+), 314 deletions(-) diff --git a/src/tour/tour.js b/src/tour/tour.js index d2a19c6..74230ce 100644 --- a/src/tour/tour.js +++ b/src/tour/tour.js @@ -2,23 +2,23 @@ angular.module('angular-tour.tour', []) - /** - * tourConfig - * Default configuration, can be customized by injecting tourConfig into your app and modifying it - */ - .constant('tourConfig', { - placement : 'top', // default placement relative to target. 'top', 'right', 'left', 'bottom' - animation : true, // if tips fade in - nextLabel : 'Next', // default text in the next tip button - scrollSpeed : 500, // page scrolling speed in milliseconds - offset : 28 // how many pixels offset the tip is from the target - }) - - /** - * TourController - * the logic for the tour, which manages all the steps - */ - .controller('TourController', function($scope, orderedList) { +/** + * tourConfig + * Default configuration, can be customized by injecting tourConfig into your app and modifying it + */ +.constant('tourConfig', { + placement: 'top', // default placement relative to target. 'top', 'right', 'left', 'bottom' + animation: true, // if tips fade in + nextLabel: 'Next', // default text in the next tip button + scrollSpeed: 500, // page scrolling speed in milliseconds + offset: 28 // how many pixels offset the tip is from the target +}) + +/** + * TourController + * the logic for the tour, which manages all the steps + */ +.controller('TourController', function($scope, $timeout, orderedList) { var self = this, steps = self.steps = orderedList(); @@ -28,362 +28,431 @@ angular.module('angular-tour.tour', []) self.currentStep = 0; // if currentStep changes, select the new step - $scope.$watch( function() { return self.currentStep; }, - function ( val ) { - self.select(val); - } + $scope.$watch(function() { + return self.currentStep; + }, + function(val) { + self.select(val); + } ); self.select = function(nextIndex) { - if(!angular.isNumber(nextIndex)) return; + if (!angular.isNumber(nextIndex)) return; - self.unselectAllSteps(); - var step = steps.get(nextIndex); - if(step) { - step.ttOpen = true; - } + self.unselectAllSteps(); + var step = steps.get(nextIndex); + if (step) { + step.ttOpen = true; + } - // update currentStep if we manually selected this index - if(self.currentStep !== nextIndex) { - self.currentStep = nextIndex; - } + // update currentStep if we manually selected this index + if (self.currentStep !== nextIndex) { + self.currentStep = nextIndex; + } - if(nextIndex >= steps.getCount()) { - self.postTourCallback(); - } - self.postStepCallback(); + if (nextIndex >= steps.getCount()) { + self.postTourCallback(); + } + self.postStepCallback(); }; self.addStep = function(step) { - if(angular.isNumber(step.index) && !isNaN(step.index)) { - steps.set(step.index, step); - } else { - steps.push(step); - } + if (angular.isNumber(step.index) && !isNaN(step.index)) { + steps.set(step.index, step); + } else { + steps.push(step); + } }; self.unselectAllSteps = function() { - steps.forEach(function (step) { - step.ttOpen = false; - }); + steps.forEach(function(step) { + step.ttOpen = false; + }); }; - self.cancelTour = function () { - self.unselectAllSteps(); - self.postTourCallback(); + self.cancelTour = function() { + self.unselectAllSteps(); + self.postTourCallback(); }; $scope.openTour = function() { - // open at first step if we've already finished tour - var startStep = self.currentStep >= steps.getCount() || self.currentStep < 0 ? 0 : self.currentStep; - self.select(startStep); + // open at first step if we've already finished tour + var startStep = self.currentStep >= steps.getCount() || self.currentStep < 0 ? 0 : self.currentStep; + self.select(startStep); }; $scope.closeTour = function() { - self.cancelTour(); + self.cancelTour(); }; - }) +}) - /** - * Tour - * directive that allows you to control the tour - */ - .directive('tour', function ($parse) { +/** + * Tour + * directive that allows you to control the tour + */ +.directive('tour', function($parse) { return { - controller: 'TourController', - restrict: 'EA', - scope: true, - link: function (scope, element, attrs, ctrl) { - if(!angular.isDefined(attrs.step)) { - throw('The directive requires a `step` attribute to bind the current step to.'); + controller: 'TourController', + restrict: 'EA', + scope: true, + link: function(scope, element, attrs, ctrl) { + if (!angular.isDefined(attrs.step)) { + throw ('The directive requires a `step` attribute to bind the current step to.'); + } + var model = $parse(attrs.step); + + // Watch current step view model and update locally + scope.$watch(attrs.step, function(newVal) { + ctrl.currentStep = newVal; + }); + + ctrl.postTourCallback = function() { + if (angular.isDefined(attrs.postTour)) { + scope.$parent.$eval(attrs.postTour); + } + }; + + ctrl.postStepCallback = function() { + if (angular.isDefined(attrs.postStep)) { + scope.$parent.$eval(attrs.postStep); + } + }; + + // update the current step in the view as well as in our controller + scope.setCurrentStep = function(val) { + model.assign(scope.$parent, val); + ctrl.currentStep = val; + }; + + scope.getCurrentStep = function() { + return ctrl.currentStep; + }; } - var model = $parse(attrs.step); - - // Watch current step view model and update locally - scope.$watch(attrs.step, function(newVal){ - ctrl.currentStep = newVal; - }); - - ctrl.postTourCallback = function() { - if(angular.isDefined(attrs.postTour)) { - scope.$parent.$eval(attrs.postTour); - } - }; - - ctrl.postStepCallback = function() { - if(angular.isDefined(attrs.postStep)) { - scope.$parent.$eval(attrs.postStep); - } - }; - - // update the current step in the view as well as in our controller - scope.setCurrentStep = function(val) { - model.assign(scope.$parent, val); - ctrl.currentStep = val; - }; - - scope.getCurrentStep = function() { - return ctrl.currentStep; - }; - } }; - }) +}) - /** - * Tourtip - * tourtip manages the state of the tour-popup directive - */ - .directive('tourtip', function ($window, $compile, $interpolate, $timeout, scrollTo, tourConfig) { +/** + * Tourtip + * tourtip manages the state of the tour-popup directive + */ +.directive('tourtip', function($window, $compile, $interpolate, $timeout, scrollTo, tourConfig) { var startSym = $interpolate.startSymbol(), endSym = $interpolate.endSymbol(); var template = '
'; return { - require: '^tour', - restrict: 'EA', - scope: true, - link: function (scope, element, attrs, tourCtrl) { - attrs.$observe( 'tourtip', function ( val ) { - scope.ttContent = val; - }); - - attrs.$observe( 'tourtipPlacement', function ( val ) { - scope.ttPlacement = val || tourConfig.placement; - }); - - attrs.$observe( 'tourtipNextLabel', function ( val ) { - scope.ttNextLabel = val || tourConfig.nextLabel; - }); - - attrs.$observe( 'tourtipOffset', function ( val ) { - scope.ttOffset = parseInt(val, 10) || tourConfig.offset; - }); - - scope.ttOpen = false; - scope.ttAnimation = tourConfig.animation; - scope.index = parseInt(attrs.tourtipStep, 10); - - var tourtip = $compile( template )( scope ); - tourCtrl.addStep(scope); - - // wrap this in a time out because the tourtip won't compile right away - $timeout( function() { - scope.$watch('ttOpen', function(val) { - if(val) { - show(); - } else { - hide(); - } - }); - }, 500); - - function show() { - var position, - ttWidth, - ttHeight, - ttPosition, - height, - width, - targetElement; - - if ( ! scope.ttContent ) { - return; - } - - if(scope.ttAnimation) - tourtip.fadeIn(); - else { - tourtip.css({ display: 'block' }); - } - - // Append it to the dom - element.after( tourtip ); - - // Try to set target to the first child of our tour directive - if(element.children().eq(0).length>0) { - targetElement = element.children().eq(0); - } else { - targetElement = element; - } - - var updatePosition = function() { - // Get the position of the directive element - position = targetElement.position(); - - ttWidth = tourtip.width(); - ttHeight = tourtip.height(); - - width = targetElement.width(); - height = targetElement.height(); - - // Calculate the tourtip's top and left coordinates to center it - switch ( scope.ttPlacement ) { - case 'right': - ttPosition = { - top: position.top, - left: position.left + width + scope.ttOffset - }; - break; - case 'bottom': - ttPosition = { - top: position.top + height + scope.ttOffset, - left: position.left - }; - break; - case 'left': - ttPosition = { - top: position.top, - left: position.left - ttWidth - scope.ttOffset - }; - break; - default: - ttPosition = { - top: position.top - ttHeight - scope.ttOffset, - left: position.left - }; - break; + require: '^tour', + restrict: 'EA', + scope: true, + link: function(scope, element, attrs, tourCtrl) { + attrs.$observe('tourtip', function(val) { + scope.ttContent = val; + }); + + attrs.$observe('tourtipPlacement', function(val) { + scope.ttPlacement = val || tourConfig.placement; + }); + + attrs.$observe('tourtipNextLabel', function(val) { + scope.ttNextLabel = val || tourConfig.nextLabel; + }); + + attrs.$observe('tourtipOffset', function(val) { + scope.ttOffset = parseInt(val, 10) || tourConfig.offset; + }); + + scope.ttOpen = false; + scope.ttAnimation = tourConfig.animation; + scope.index = parseInt(attrs.tourtipStep, 10); + + var tourtip = $compile(template)(scope); + tourCtrl.addStep(scope); + + // wrap this in a time out because the tourtip won't compile right away + $timeout(function() { + scope.$watch('ttOpen', function(val) { + if (val) { + show(); + } else { + hide(); + } + }); + }, 500); + + function show() { + var position, + ttWidth, + ttHeight, + ttPosition, + height, + width, + targetElement; + + if (!scope.ttContent) { + return; + } + + /*if(scope.ttAnimation) + tourtip.fadeIn(); + else { + tourtip.css({ display: 'block' }); + }*/ + tourtip.css({ + display: 'block' + }); + tourtip.removeClass('ng-hide'); + + // Append it to the dom + element.after(tourtip); + + // Try to set target to the first child of our tour directive + if (element.children().eq(0).length > 0) { + targetElement = element.children().eq(0); + } else { + targetElement = element; + } + + var updatePosition = function() { + // Get the position of the directive element + position = targetElement[0]; + + ttWidth = tourtip[0].offsetWidth; + ttHeight = tourtip[0].offsetHeight; + + width = targetElement[0].offsetWidth; + height = targetElement[0].offsetHeight; + + // Calculate the tourtip's top and left coordinates to center it + switch (scope.ttPlacement) { + case 'right': + ttPosition = { + top: position.offsetTop, + left: position.offsetLeft + width + scope.ttOffset + }; + break; + case 'bottom': + ttPosition = { + top: position.offsetTop + height + scope.ttOffset, + left: position.offsetLeft + }; + break; + case 'left': + ttPosition = { + top: position.offsetTop, + left: position.offsetLeft - ttWidth - scope.ttOffset + }; + break; + default: + ttPosition = { + top: position.offsetTop - ttHeight - scope.ttOffset, + left: position.offsetLeft + }; + break; + } + + ttPosition.top += 'px'; + ttPosition.left += 'px'; + + // Now set the calculated positioning. + tourtip.css(ttPosition); + + // Scroll to the tour tip + + + scrollTo(tourtip, -200, -300, tourConfig.scrollSpeed); + }; + + angular.element($window).bind('resize.' + scope.$id, function() { + updatePosition(); + }); + updatePosition(); } - ttPosition.top += 'px'; - ttPosition.left += 'px'; - - // Now set the calculated positioning. - tourtip.css( ttPosition ); - - // Scroll to the tour tip - scrollTo(tourtip, -200, -300, tourConfig.scrollSpeed); - }; - - angular.element($window).bind('resize.' + scope.$id, function() { - updatePosition(); - }); - updatePosition(); - } + function hide() { + tourtip.addClass('ng-hide'); + angular.element($window).unbind('resize.' + scope.$id); + } - function hide() { - tourtip.detach(); - angular.element($window).unbind('resize.' + scope.$id); + // Make sure tooltip is destroyed and removed. + scope.$on('$destroy', function onDestroyTourtip() { + angular.element($window).unbind('resize.' + scope.$id); + tourtip.remove(); + tourtip = null; + }); } - - // Make sure tooltip is destroyed and removed. - scope.$on('$destroy', function onDestroyTourtip() { - angular.element($window).unbind('resize.' + scope.$id); - tourtip.remove(); - tourtip = null; - }); - } }; - }) +}) - /** - * TourPopup - * the directive that actually has the template for the tip - */ - .directive('tourPopup', function () { +/** + * TourPopup + * the directive that actually has the template for the tip + */ +.directive('tourPopup', function() { return { - replace: true, - templateUrl: 'tour/tour.tpl.html', - scope: true, - restrict: 'EA', - link: function (scope, element, attrs) { - } + replace: true, + templateUrl: 'tour/tour.tpl.html', + scope: true, + restrict: 'EA', + link: function(scope, element, attrs) {} }; - }) +}) - /** - * OrderedList - * Used for keeping steps in order - */ - .factory('orderedList', function () { +/** + * OrderedList + * Used for keeping steps in order + */ +.factory('orderedList', function() { var OrderedList = function() { - this.map = {}; - this._array = []; + this.map = {}; + this._array = []; }; - - OrderedList.prototype.set = function (key, value) { - if (!angular.isNumber(key)) - return; - if (key in this.map) { - this.map[key] = value; - } else { - if (key < this._array.length) { - var insertIndex = key - 1 > 0 ? key - 1 : 0; - this._array.splice(insertIndex, 0, key); + + OrderedList.prototype.set = function(key, value) { + if (!angular.isNumber(key)) + return; + if (key in this.map) { + this.map[key] = value; } else { - this._array.push(key); + if (key < this._array.length) { + var insertIndex = key - 1 > 0 ? key - 1 : 0; + this._array.splice(insertIndex, 0, key); + } else { + this._array.push(key); + } + this.map[key] = value; + this._array.sort(function(a, b) { + return a - b; + }); } + }; + OrderedList.prototype.indexOf = function(value) { + for (var prop in this.map) { + if (this.map.hasOwnProperty(prop)) { + if (this.map[prop] === value) + return Number(prop); + } + } + }; + OrderedList.prototype.push = function(value) { + var key = this._array[this._array.length - 1] + 1 || 0; + this._array.push(key); this.map[key] = value; - this._array.sort(function(a,b){ - return a-b; + this._array.sort(function(a, b) { + return a - b; }); - } }; - OrderedList.prototype.indexOf = function (value) { - for (var prop in this.map) { - if (this.map.hasOwnProperty(prop)) { - if (this.map[prop] === value) - return Number(prop); + OrderedList.prototype.remove = function(key) { + var index = this._array.indexOf(key); + if (index === -1) { + throw new Error('key does not exist'); } - } + this._array.splice(index, 1); + delete this.map[key]; }; - OrderedList.prototype.push = function (value) { - var key = this._array[this._array.length - 1] + 1 || 0; - this._array.push(key); - this.map[key] = value; - this._array.sort(function(a, b) { - return a-b; - }); + OrderedList.prototype.get = function(key) { + return this.map[key]; }; - OrderedList.prototype.remove = function (key) { - var index = this._array.indexOf(key); - if (index === -1) { - throw new Error('key does not exist'); - } - this._array.splice(index, 1); - delete this.map[key]; + OrderedList.prototype.getCount = function() { + return this._array.length; }; - OrderedList.prototype.get = function (key) { - return this.map[key]; - }; - OrderedList.prototype.getCount = function () { - return this._array.length; + OrderedList.prototype.forEach = function(f) { + var key, value; + for (var i = 0; i < this._array.length; i++) { + key = this._array[i]; + value = this.map[key]; + f(value, key); + } }; - OrderedList.prototype.forEach = function (f) { - var key, value; - for (var i = 0; i < this._array.length; i++) { - key = this._array[i]; + OrderedList.prototype.first = function() { + var key, value; + key = this._array[0]; value = this.map[key]; - f(value, key); - } - }; - OrderedList.prototype.first = function () { - var key, value; - key = this._array[0]; - value = this.map[key]; - return value; + return value; }; var orderedListFactory = function() { - return new OrderedList(); + return new OrderedList(); }; - + return orderedListFactory; - }) +}) + +/** + * ScrollTo + * Smoothly scroll to a dom element + */ + +.factory('scrollTo', function($window, $timeout, tourConfig) { + + var smooth_scroll = function(targetX, targetY, duration) { + + targetX = Math.round(targetX); + targetY = Math.round(targetY); + duration = Math.round(duration); + + if (duration < 0) { + return Promise.reject("bad duration"); + } + if (duration === 0) { + window.scrollTo(targetX, targetY); + return Promise.resolve(); + } + + var start_time = Date.now(), + end_time = start_time + duration, + startLeft = window.scrollX, + startTop = window.scrollY, + distanceX = targetX - startLeft, + distanceY = targetY - startTop; + + // based on http://en.wikipedia.org/wiki/Smoothstep + var smooth_step = function(start, end, point) { + if (point <= start) { + return 0; + } + if (point >= end) { + return 1; + } + var x = (point - start) / (end - start); // interpolation + return x * x * (3 - 2 * x); + } + + return new Promise(function(resolve, reject) { + + var scroll_frame = function() { + + var now = Date.now(), + point = smooth_step(start_time, end_time, now), + frameLeft = Math.round(startLeft + (distanceX * point)), + frameTop = Math.round(startTop + (distanceY * point)); + + + window.scrollTo(frameLeft, frameTop) + + // check if we're done! + if (now >= end_time) { + resolve(); + return; + } + + // schedule next frame for execution + $timeout(scroll_frame, 0); + } + + // boostrap the animation process + $timeout(scroll_frame, 0); + }); + } - /** - * ScrollTo - * Smoothly scroll to a dom element - */ - .factory('scrollTo', function() { return function(target, offsetY, offsetX, speed) { - if(target) { - offsetY = offsetY || -100; - offsetX = offsetX || -100; - speed = speed || 500; - $('html,body').stop().animate({scrollTop: target.offset().top + offsetY, scrollLeft: target.offset().left + offsetX}, speed); - } else { - $('html,body').stop().animate({scrollTop: 0}, speed); - } + if (target) { + offsetY = offsetY || -100; + offsetX = offsetX || -100; + speed = speed || 500; + smooth_scroll(target[0].offsetLeft + offsetX, target[0].offsetTop + offsetY, speed); + } else { + smooth_scroll(0, 0, speed); + } }; - }); \ No newline at end of file +}); From 0117d88110aea928231b17df4d893a48b41bfb48 Mon Sep 17 00:00:00 2001 From: britztopher Date: Mon, 14 Sep 2015 14:32:46 -0400 Subject: [PATCH 4/9] upgraded angular, replaced grunt compass with grunt sass and added tooltip fade in --- Gruntfile.js | 156 ++++++++++++---------------- bower.json | 2 +- demo/index.html | 2 +- dist/angular-tour-tpls.js | 102 ++++++++++-------- dist/angular-tour-tpls.min.js | 2 +- dist/angular-tour.css | 188 ++++++++++++++++------------------ dist/angular-tour.css.map | 10 ++ dist/angular-tour.js | 100 ++++++++++-------- dist/angular-tour.min.js | 2 +- package.json | 24 ++--- 10 files changed, 300 insertions(+), 288 deletions(-) create mode 100644 dist/angular-tour.css.map diff --git a/Gruntfile.js b/Gruntfile.js index 3d1b1e5..7bea49f 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -1,6 +1,6 @@ 'use strict'; -module.exports = function (grunt) { +module.exports = function(grunt){ // Load grunt tasks automatically require('load-grunt-tasks')(grunt); @@ -14,6 +14,16 @@ module.exports = function (grunt) { // Project configuration. grunt.initConfig({ + sass: { + options: { + sourceMap: true + }, + dist: { + files: { + './dist/angular-tour.css': './src/tour/**/*.scss' + } + } + }, yeoman: yeomanConfig, pkg: grunt.file.readJSON('package.json'), modules: [],//to be filled in by buildmodules task @@ -23,12 +33,12 @@ module.exports = function (grunt) { tplmodules: 'angular.module("<%= pkg.name %>.tpls", [<%= tplModules %>]);', all: 'angular.module("<%= pkg.name %>", ["<%= pkg.name %>.tpls", <%= srcModules %>]);', banner: '/**\n' + - ' * <%= pkg.description %>\n' + - ' * @version v<%= pkg.version %> - <%= grunt.template.today("yyyy-mm-dd") %>\n' + - ' * @link <%= pkg.homepage %>\n' + - ' * @author <%= pkg.author.name %>\n' + - ' * @license MIT License, http://www.opensource.org/licenses/MIT\n' + - ' */\n\n' + ' * <%= pkg.description %>\n' + + ' * @version v<%= pkg.version %> - <%= grunt.template.today("yyyy-mm-dd") %>\n' + + ' * @link <%= pkg.homepage %>\n' + + ' * @author <%= pkg.author.name %>\n' + + ' * @license MIT License, http://www.opensource.org/licenses/MIT\n' + + ' */\n\n' }, // Watches files for changes and runs tasks based on the changed files @@ -44,9 +54,9 @@ module.exports = function (grunt) { files: ['<%= yeoman.src %>/**/*.spec.js'], tasks: ['karma'] }, - compass: { + sass:{ files: ['<%= yeoman.src %>/**/*.{scss,sass}'], - tasks: ['compass:server', 'autoprefixer'] + tasks: ['sass', 'autoprefixer'] }, gruntfile: { files: ['Gruntfile.js'] @@ -131,26 +141,6 @@ module.exports = function (grunt) { } }, - // Compiles Sass to CSS and generates necessary files if requested - compass: { - options: { - sassDir: '<%= yeoman.src %>', - cssDir: '.tmp/styles', - relativeAssets: false, - assetCacheBuster: false - }, - server: { - options: { - debugInfo: true - } - }, - dist: { - options: { - noLineComments: true - } - } - }, - // Make sure code styles are up to par and there are no obvious mistakes jshint: { options: { @@ -187,7 +177,7 @@ module.exports = function (grunt) { // Replace all 'use strict' statements in the code with a single one at the top banner: '(function(window, document, undefined) {\n\'use strict\';\n<%= meta.modules %>\n', footer: '\n})(window, document);\n', - process: function(src, filepath) { + process: function(src, filepath){ return src.replace(/(^|\n)[ \t]*('use strict'|"use strict");?\s*/g, '$1'); } }, @@ -203,7 +193,7 @@ module.exports = function (grunt) { // Replace all 'use strict' statements in the code with a single one at the top banner: '(function(window, document, undefined) {\n\'use strict\';\n<%= meta.all %>\n<%= meta.tplmodules %>\n', footer: '\n})(window, document);\n', - process: function(src, filepath) { + process: function(src, filepath){ return src.replace(/(^|\n)[ \t]*('use strict'|"use strict");?\s*/g, '$1'); } }, @@ -296,7 +286,7 @@ module.exports = function (grunt) { module: null, // no bundle module for all the html2js templates base: 'src' }, - src: [ 'src/**/*.tpl.html' ], + src: ['src/**/*.tpl.html'], dest: '<%= yeoman.dist %>/<%= pkg.name %>-tpls.js' } }, @@ -321,23 +311,6 @@ module.exports = function (grunt) { src: ['src/**/*.tpl.html'] } }, - - // Run some tasks in parallel to speed up the build process - concurrent: { - server: [ - 'compass:server', - 'copy:styles' - ] - }, - - copy: { - styles: { - expand: true, - src: '<%= yeoman.src %>/**/*.css', - dest: '.tmp/' - } - }, - processhtml: { dist: { files: { @@ -372,91 +345,96 @@ module.exports = function (grunt) { //findModule: Adds a given module to config var foundModules = {}; - function findModule(name) { - if (foundModules[name]) { return; } + + function findModule(name){ + if(foundModules[name]){ + return; + } foundModules[name] = true; - function enquote(str) { + function enquote(str){ return '"' + str + '"'; } - function removeroot(str) { + function removeroot(str){ return str.slice(str.indexOf('/') + 1, str.length); } var module = { name: name, - moduleName: enquote(grunt.config('moduleprefix')+name), - srcFiles: grunt.file.expand(['src/'+name+'/*.js','!src/'+name+'/*.spec.js']), - tplFiles: grunt.file.expand('src/'+name+'/*.tpl.html'), - tplModules: grunt.file.expand('src/'+name+'/*.tpl.html').map(removeroot).map(enquote), + moduleName: enquote(grunt.config('moduleprefix') + name), + srcFiles: grunt.file.expand(['src/' + name + '/*.js', '!src/' + name + '/*.spec.js']), + tplFiles: grunt.file.expand('src/' + name + '/*.tpl.html'), + tplModules: grunt.file.expand('src/' + name + '/*.tpl.html').map(removeroot).map(enquote), dependencies: dependenciesForModule(name) }; module.dependencies.forEach(findModule); grunt.config('modules', grunt.config('modules').concat(module)); } - function dependenciesForModule(name) { + function dependenciesForModule(name){ var deps = []; - grunt.file.expand(['src/'+name+'/*.js','!src/'+name+'/*.spec.js']) - .map(grunt.file.read) - .forEach(function(contents) { - //Strategy: find where module is declared, - //and from there get everything inside the [] and split them by comma - var moduleDeclIndex = contents.indexOf('angular.module('); - var depArrayStart = contents.indexOf('[', moduleDeclIndex); - var depArrayEnd = contents.indexOf(']', depArrayStart); - var dependencies = contents.substring(depArrayStart + 1, depArrayEnd); - dependencies.split(',').forEach(function(dep) { - if (dep.indexOf(grunt.config('moduleprefix')) > -1) { - var depName = dep.trim().replace( grunt.config('moduleprefix'),'').replace(/['"]/g,''); - if (deps.indexOf(depName) < 0) { - deps.push(depName); - //Get dependencies for this new dependency - deps = deps.concat(dependenciesForModule(depName)); + grunt.file.expand(['src/' + name + '/*.js', '!src/' + name + '/*.spec.js']) + .map(grunt.file.read) + .forEach(function(contents){ + //Strategy: find where module is declared, + //and from there get everything inside the [] and split them by comma + var moduleDeclIndex = contents.indexOf('angular.module('); + var depArrayStart = contents.indexOf('[', moduleDeclIndex); + var depArrayEnd = contents.indexOf(']', depArrayStart); + var dependencies = contents.substring(depArrayStart + 1, depArrayEnd); + dependencies.split(',').forEach(function(dep){ + if(dep.indexOf(grunt.config('moduleprefix')) > -1){ + var depName = dep.trim().replace(grunt.config('moduleprefix'), '').replace(/['"]/g, ''); + if(deps.indexOf(depName) < 0){ + deps.push(depName); + //Get dependencies for this new dependency + deps = deps.concat(dependenciesForModule(depName)); + } } - } + }); }); - }); return deps; } - grunt.registerTask('buildmodules', function() { + grunt.registerTask('buildmodules', function(){ var _ = grunt.util._; //Build all modules grunt.file.expand({ filter: 'isDirectory', cwd: '.' - }, 'src/*').forEach(function(dir) { + }, 'src/*').forEach(function(dir){ findModule(dir.split('/')[1]); }); var modules = grunt.config('modules'); grunt.config('srcModules', _.pluck(modules, 'moduleName')); - grunt.config('tplModules', _.pluck(modules, 'tplModules').filter(function(tpls) { return tpls.length > 0;} )); + grunt.config('tplModules', _.pluck(modules, 'tplModules').filter(function(tpls){ + return tpls.length > 0; + })); }); - grunt.registerMultiTask('optionaltasks', 'Run task only if source files exists', function() { + grunt.registerMultiTask('optionaltasks', 'Run task only if source files exists', function(){ var options = this.options({ tasks: [] }); var filesExist = false; - this.files.forEach(function(f) { - var src = f.src.filter(function(filepath) { - if (!grunt.file.exists(filepath)) { + this.files.forEach(function(f){ + var src = f.src.filter(function(filepath){ + if(!grunt.file.exists(filepath)){ return false; - } else { + }else{ filesExist = true; return true; } }); }); - if(filesExist) { + if(filesExist){ console.log('true'); - options.tasks.forEach(function(task) { + options.tasks.forEach(function(task){ grunt.task.run(task); }); } @@ -470,7 +448,7 @@ module.exports = function (grunt) { grunt.registerTask('build', [ 'clean:dist', - 'compass:dist', + 'sass:dist', 'autoprefixer', 'buildmodules', 'optionaltasks:css', @@ -482,10 +460,10 @@ module.exports = function (grunt) { 'processhtml' ]); - grunt.registerTask('serve', function (target) { + grunt.registerTask('serve', function(target){ grunt.task.run([ 'clean:server', - 'concurrent:server', + //'concurrent:server', 'autoprefixer', 'connect:livereload', 'watch' diff --git a/bower.json b/bower.json index 39ef260..1aba0bd 100644 --- a/bower.json +++ b/bower.json @@ -31,7 +31,7 @@ "package.json" ], "dependencies": { - "angular": "~1.2.x" + "angular": "~1.4.x" }, "devDependencies": { "angular-mocks": "~1.x", diff --git a/demo/index.html b/demo/index.html index f0c5f98..cb964ed 100644 --- a/demo/index.html +++ b/demo/index.html @@ -48,7 +48,7 @@ }); - + diff --git a/dist/angular-tour-tpls.js b/dist/angular-tour-tpls.js index 263f590..ae0621f 100644 --- a/dist/angular-tour-tpls.js +++ b/dist/angular-tour-tpls.js @@ -1,11 +1,11 @@ -/** - * An AngularJS directive for showcasing features of your website - * @version v0.1.1 - 2014-03-19 - * @link https://github.com/DaftMonk/angular-tour - * @author Tyler Henkel - * @license MIT License, http://www.opensource.org/licenses/MIT - */ - +/** + * An AngularJS directive for showcasing features of your website + * @version v0.1.1 - 2015-09-14 + * @link https://github.com/DaftMonk/angular-tour + * @author Tyler Henkel + * @license MIT License, http://www.opensource.org/licenses/MIT + */ + (function (window, document, undefined) { 'use strict'; angular.module('angular-tour', [ @@ -16,7 +16,7 @@ angular.module('tour/tour.tpl.html', []).run([ '$templateCache', function ($templateCache) { - $templateCache.put('tour/tour.tpl.html', '
\n' + ' \n' + '
\n' + '

\n' + ' \n' + ' \xd7\n' + '
\n' + '
'); + $templateCache.put('tour/tour.tpl.html', '
\n' + ' \n' + '
\n' + '

\n' + ' \n' + ' ×\n' + '
\n' + '
'); } ]); angular.module('angular-tour.tour', []).constant('tourConfig', { @@ -30,9 +30,11 @@ 'orderedList', function ($scope, orderedList) { var self = this, steps = self.steps = orderedList(); + // we'll pass these in from the directive self.postTourCallback = angular.noop; self.postStepCallback = angular.noop; self.currentStep = 0; + // if currentStep changes, select the new step $scope.$watch(function () { return self.currentStep; }, function (val) { @@ -46,6 +48,7 @@ if (step) { step.ttOpen = true; } + // update currentStep if we manually selected this index if (self.currentStep !== nextIndex) { self.currentStep = nextIndex; } @@ -71,6 +74,7 @@ self.postTourCallback(); }; $scope.openTour = function () { + // open at first step if we've already finished tour var startStep = self.currentStep >= steps.getCount() || self.currentStep < 0 ? 0 : self.currentStep; self.select(startStep); }; @@ -90,6 +94,7 @@ throw 'The directive requires a `step` attribute to bind the current step to.'; } var model = $parse(attrs.step); + // Watch current step view model and update locally scope.$watch(attrs.step, function (newVal) { ctrl.currentStep = newVal; }); @@ -103,6 +108,7 @@ scope.$parent.$eval(attrs.postStep); } }; + // update the current step in the view as well as in our controller scope.setCurrentStep = function (val) { model.assign(scope.$parent, val); ctrl.currentStep = val; @@ -145,6 +151,7 @@ scope.index = parseInt(attrs.tourtipStep, 10); var tourtip = $compile(template)(scope); tourCtrl.addStep(scope); + // wrap this in a time out because the tourtip won't compile right away $timeout(function () { scope.$watch('ttOpen', function (val) { if (val) { @@ -159,52 +166,60 @@ if (!scope.ttContent) { return; } - if (scope.ttAnimation) - tourtip.fadeIn(); - else { - tourtip.css({ display: 'block' }); - } + /*if(scope.ttAnimation) + tourtip.fadeIn(); + else { + tourtip.css({ display: 'block' }); + }*/ + tourtip.css({ display: 'block' }); + tourtip.removeClass('ng-hide'); + // Append it to the dom element.after(tourtip); + // Try to set target to the first child of our tour directive if (element.children().eq(0).length > 0) { targetElement = element.children().eq(0); } else { targetElement = element; } var updatePosition = function () { - position = targetElement.position(); - ttWidth = tourtip.width(); - ttHeight = tourtip.height(); - width = targetElement.width(); - height = targetElement.height(); + // Get the position of the directive element + position = targetElement[0]; + ttWidth = tourtip[0].offsetWidth; + ttHeight = tourtip[0].offsetHeight; + width = targetElement[0].offsetWidth; + height = targetElement[0].offsetHeight; + // Calculate the tourtip's top and left coordinates to center it switch (scope.ttPlacement) { case 'right': ttPosition = { - top: position.top, - left: position.left + width + scope.ttOffset + top: position.offsetTop, + left: position.offsetLeft + width + scope.ttOffset }; break; case 'bottom': ttPosition = { - top: position.top + height + scope.ttOffset, - left: position.left + top: position.offsetTop + height + scope.ttOffset, + left: position.offsetLeft }; break; case 'left': ttPosition = { - top: position.top, - left: position.left - ttWidth - scope.ttOffset + top: position.offsetTop, + left: position.offsetLeft - ttWidth - scope.ttOffset }; break; default: ttPosition = { - top: position.top - ttHeight - scope.ttOffset, - left: position.left + top: position.offsetTop - ttHeight - scope.ttOffset, + left: position.offsetLeft }; break; } ttPosition.top += 'px'; ttPosition.left += 'px'; + // Now set the calculated positioning. tourtip.css(ttPosition); + // Scroll to the tour tip scrollTo(tourtip, -200, -300, tourConfig.scrollSpeed); }; angular.element($window).bind('resize.' + scope.$id, function () { @@ -213,9 +228,10 @@ updatePosition(); } function hide() { - tourtip.detach(); + tourtip.addClass('ng-hide'); angular.element($window).unbind('resize.' + scope.$id); } + // Make sure tooltip is destroyed and removed. scope.$on('$destroy', function onDestroyTourtip() { angular.element($window).unbind('resize.' + scope.$id); tourtip.remove(); @@ -304,19 +320,19 @@ return new OrderedList(); }; return orderedListFactory; - }).factory('scrollTo', function () { - return function (target, offsetY, offsetX, speed) { - if (target) { - offsetY = offsetY || -100; - offsetX = offsetX || -100; - speed = speed || 500; - $('html,body').stop().animate({ - scrollTop: target.offset().top + offsetY, - scrollLeft: target.offset().left + offsetX - }, speed); - } else { - $('html,body').stop().animate({ scrollTop: 0 }, speed); - } - }; - }); + }).factory('scrollTo', [ + '$window', + function ($window) { + return function (target, offsetY, offsetX, speed) { + if (target) { + offsetY = offsetY || -100; + offsetX = offsetX || -100; + speed = speed || 500; + $window.scrollTo(target[0].offsetLeft + offsetX, target[0].offsetTop + offsetY); + } else { + $window.scrollTo(0, 0); + } + }; + } + ]); }(window, document)); \ No newline at end of file diff --git a/dist/angular-tour-tpls.min.js b/dist/angular-tour-tpls.min.js index 8e701a5..b4093bf 100644 --- a/dist/angular-tour-tpls.min.js +++ b/dist/angular-tour-tpls.min.js @@ -1 +1 @@ -!function(){"use strict";angular.module("angular-tour",["angular-tour.tpls","angular-tour.tour"]),angular.module("angular-tour.tpls",["tour/tour.tpl.html"]),angular.module("tour/tour.tpl.html",[]).run(["$templateCache",function(a){a.put("tour/tour.tpl.html",'
\n \n
\n

\n \n ×\n
\n
')}]),angular.module("angular-tour.tour",[]).constant("tourConfig",{placement:"top",animation:!0,nextLabel:"Next",scrollSpeed:500,offset:28}).controller("TourController",["$scope","orderedList",function(a,b){var c=this,d=c.steps=b();c.postTourCallback=angular.noop,c.postStepCallback=angular.noop,c.currentStep=0,a.$watch(function(){return c.currentStep},function(a){c.select(a)}),c.select=function(a){if(angular.isNumber(a)){c.unselectAllSteps();var b=d.get(a);b&&(b.ttOpen=!0),c.currentStep!==a&&(c.currentStep=a),a>=d.getCount()&&c.postTourCallback(),c.postStepCallback()}},c.addStep=function(a){angular.isNumber(a.index)&&!isNaN(a.index)?d.set(a.index,a):d.push(a)},c.unselectAllSteps=function(){d.forEach(function(a){a.ttOpen=!1})},c.cancelTour=function(){c.unselectAllSteps(),c.postTourCallback()},a.openTour=function(){var a=c.currentStep>=d.getCount()||c.currentStep<0?0:c.currentStep;c.select(a)},a.closeTour=function(){c.cancelTour()}}]).directive("tour",["$parse",function(a){return{controller:"TourController",restrict:"EA",scope:!0,link:function(b,c,d,e){if(!angular.isDefined(d.step))throw"The directive requires a `step` attribute to bind the current step to.";var f=a(d.step);b.$watch(d.step,function(a){e.currentStep=a}),e.postTourCallback=function(){angular.isDefined(d.postTour)&&b.$parent.$eval(d.postTour)},e.postStepCallback=function(){angular.isDefined(d.postStep)&&b.$parent.$eval(d.postStep)},b.setCurrentStep=function(a){f.assign(b.$parent,a),e.currentStep=a},b.getCurrentStep=function(){return e.currentStep}}}}]).directive("tourtip",["$window","$compile","$interpolate","$timeout","scrollTo","tourConfig",function(a,b,c,d,e,f){var g=(c.startSymbol(),c.endSymbol(),"
");return{require:"^tour",restrict:"EA",scope:!0,link:function(c,h,i,j){function k(){var b,d,g,i,j,k,l;if(c.ttContent){c.ttAnimation?m.fadeIn():m.css({display:"block"}),h.after(m),l=h.children().eq(0).length>0?h.children().eq(0):h;var n=function(){switch(b=l.position(),d=m.width(),g=m.height(),k=l.width(),j=l.height(),c.ttPlacement){case"right":i={top:b.top,left:b.left+k+c.ttOffset};break;case"bottom":i={top:b.top+j+c.ttOffset,left:b.left};break;case"left":i={top:b.top,left:b.left-d-c.ttOffset};break;default:i={top:b.top-g-c.ttOffset,left:b.left}}i.top+="px",i.left+="px",m.css(i),e(m,-200,-300,f.scrollSpeed)};angular.element(a).bind("resize."+c.$id,function(){n()}),n()}}function l(){m.detach(),angular.element(a).unbind("resize."+c.$id)}i.$observe("tourtip",function(a){c.ttContent=a}),i.$observe("tourtipPlacement",function(a){c.ttPlacement=a||f.placement}),i.$observe("tourtipNextLabel",function(a){c.ttNextLabel=a||f.nextLabel}),i.$observe("tourtipOffset",function(a){c.ttOffset=parseInt(a,10)||f.offset}),c.ttOpen=!1,c.ttAnimation=f.animation,c.index=parseInt(i.tourtipStep,10);var m=b(g)(c);j.addStep(c),d(function(){c.$watch("ttOpen",function(a){a?k():l()})},500),c.$on("$destroy",function(){angular.element(a).unbind("resize."+c.$id),m.remove(),m=null})}}}]).directive("tourPopup",function(){return{replace:!0,templateUrl:"tour/tour.tpl.html",scope:!0,restrict:"EA",link:function(){}}}).factory("orderedList",function(){var a=function(){this.map={},this._array=[]};a.prototype.set=function(a,b){if(angular.isNumber(a))if(a in this.map)this.map[a]=b;else{if(a0?a-1:0;this._array.splice(c,0,a)}else this._array.push(a);this.map[a]=b,this._array.sort(function(a,b){return a-b})}},a.prototype.indexOf=function(a){for(var b in this.map)if(this.map.hasOwnProperty(b)&&this.map[b]===a)return Number(b)},a.prototype.push=function(a){var b=this._array[this._array.length-1]+1||0;this._array.push(b),this.map[b]=a,this._array.sort(function(a,b){return a-b})},a.prototype.remove=function(a){var b=this._array.indexOf(a);if(-1===b)throw new Error("key does not exist");this._array.splice(b,1),delete this.map[a]},a.prototype.get=function(a){return this.map[a]},a.prototype.getCount=function(){return this._array.length},a.prototype.forEach=function(a){for(var b,c,d=0;d\n \n
\n

\n \n ×\n
\n')}]),angular.module("angular-tour.tour",[]).constant("tourConfig",{placement:"top",animation:!0,nextLabel:"Next",scrollSpeed:500,offset:28}).controller("TourController",["$scope","orderedList",function(a,b){var c=this,d=c.steps=b();c.postTourCallback=angular.noop,c.postStepCallback=angular.noop,c.currentStep=0,a.$watch(function(){return c.currentStep},function(a){c.select(a)}),c.select=function(a){if(angular.isNumber(a)){c.unselectAllSteps();var b=d.get(a);b&&(b.ttOpen=!0),c.currentStep!==a&&(c.currentStep=a),a>=d.getCount()&&c.postTourCallback(),c.postStepCallback()}},c.addStep=function(a){angular.isNumber(a.index)&&!isNaN(a.index)?d.set(a.index,a):d.push(a)},c.unselectAllSteps=function(){d.forEach(function(a){a.ttOpen=!1})},c.cancelTour=function(){c.unselectAllSteps(),c.postTourCallback()},a.openTour=function(){var a=c.currentStep>=d.getCount()||c.currentStep<0?0:c.currentStep;c.select(a)},a.closeTour=function(){c.cancelTour()}}]).directive("tour",["$parse",function(a){return{controller:"TourController",restrict:"EA",scope:!0,link:function(b,c,d,e){if(!angular.isDefined(d.step))throw"The directive requires a `step` attribute to bind the current step to.";var f=a(d.step);b.$watch(d.step,function(a){e.currentStep=a}),e.postTourCallback=function(){angular.isDefined(d.postTour)&&b.$parent.$eval(d.postTour)},e.postStepCallback=function(){angular.isDefined(d.postStep)&&b.$parent.$eval(d.postStep)},b.setCurrentStep=function(a){f.assign(b.$parent,a),e.currentStep=a},b.getCurrentStep=function(){return e.currentStep}}}}]).directive("tourtip",["$window","$compile","$interpolate","$timeout","scrollTo","tourConfig",function(a,b,c,d,e,f){var g=(c.startSymbol(),c.endSymbol(),"
");return{require:"^tour",restrict:"EA",scope:!0,link:function(c,h,i,j){function k(){var b,d,g,i,j,k,l;if(c.ttContent){m.css({display:"block"}),m.removeClass("ng-hide"),h.after(m),l=h.children().eq(0).length>0?h.children().eq(0):h;var n=function(){switch(b=l[0],d=m[0].offsetWidth,g=m[0].offsetHeight,k=l[0].offsetWidth,j=l[0].offsetHeight,c.ttPlacement){case"right":i={top:b.offsetTop,left:b.offsetLeft+k+c.ttOffset};break;case"bottom":i={top:b.offsetTop+j+c.ttOffset,left:b.offsetLeft};break;case"left":i={top:b.offsetTop,left:b.offsetLeft-d-c.ttOffset};break;default:i={top:b.offsetTop-g-c.ttOffset,left:b.offsetLeft}}i.top+="px",i.left+="px",m.css(i),e(m,-200,-300,f.scrollSpeed)};angular.element(a).bind("resize."+c.$id,function(){n()}),n()}}function l(){m.addClass("ng-hide"),angular.element(a).unbind("resize."+c.$id)}i.$observe("tourtip",function(a){c.ttContent=a}),i.$observe("tourtipPlacement",function(a){c.ttPlacement=a||f.placement}),i.$observe("tourtipNextLabel",function(a){c.ttNextLabel=a||f.nextLabel}),i.$observe("tourtipOffset",function(a){c.ttOffset=parseInt(a,10)||f.offset}),c.ttOpen=!1,c.ttAnimation=f.animation,c.index=parseInt(i.tourtipStep,10);var m=b(g)(c);j.addStep(c),d(function(){c.$watch("ttOpen",function(a){a?k():l()})},500),c.$on("$destroy",function(){angular.element(a).unbind("resize."+c.$id),m.remove(),m=null})}}}]).directive("tourPopup",function(){return{replace:!0,templateUrl:"tour/tour.tpl.html",scope:!0,restrict:"EA",link:function(a,b,c){}}}).factory("orderedList",function(){var a=function(){this.map={},this._array=[]};a.prototype.set=function(a,b){if(angular.isNumber(a))if(a in this.map)this.map[a]=b;else{if(a0?a-1:0;this._array.splice(c,0,a)}else this._array.push(a);this.map[a]=b,this._array.sort(function(a,b){return a-b})}},a.prototype.indexOf=function(a){for(var b in this.map)if(this.map.hasOwnProperty(b)&&this.map[b]===a)return Number(b)},a.prototype.push=function(a){var b=this._array[this._array.length-1]+1||0;this._array.push(b),this.map[b]=a,this._array.sort(function(a,b){return a-b})},a.prototype.remove=function(a){var b=this._array.indexOf(a);if(-1===b)throw new Error("key does not exist");this._array.splice(b,1),delete this.map[a]},a.prototype.get=function(a){return this.map[a]},a.prototype.getCount=function(){return this._array.length},a.prototype.forEach=function(a){for(var b,c,d=0;d= steps.getCount() || self.currentStep < 0 ? 0 : self.currentStep; self.select(startStep); }; @@ -80,6 +84,7 @@ throw 'The directive requires a `step` attribute to bind the current step to.'; } var model = $parse(attrs.step); + // Watch current step view model and update locally scope.$watch(attrs.step, function (newVal) { ctrl.currentStep = newVal; }); @@ -93,6 +98,7 @@ scope.$parent.$eval(attrs.postStep); } }; + // update the current step in the view as well as in our controller scope.setCurrentStep = function (val) { model.assign(scope.$parent, val); ctrl.currentStep = val; @@ -135,6 +141,7 @@ scope.index = parseInt(attrs.tourtipStep, 10); var tourtip = $compile(template)(scope); tourCtrl.addStep(scope); + // wrap this in a time out because the tourtip won't compile right away $timeout(function () { scope.$watch('ttOpen', function (val) { if (val) { @@ -149,52 +156,60 @@ if (!scope.ttContent) { return; } - if (scope.ttAnimation) - tourtip.fadeIn(); - else { - tourtip.css({ display: 'block' }); - } + /*if(scope.ttAnimation) + tourtip.fadeIn(); + else { + tourtip.css({ display: 'block' }); + }*/ + tourtip.css({ display: 'block' }); + tourtip.removeClass('ng-hide'); + // Append it to the dom element.after(tourtip); + // Try to set target to the first child of our tour directive if (element.children().eq(0).length > 0) { targetElement = element.children().eq(0); } else { targetElement = element; } var updatePosition = function () { - position = targetElement.position(); - ttWidth = tourtip.width(); - ttHeight = tourtip.height(); - width = targetElement.width(); - height = targetElement.height(); + // Get the position of the directive element + position = targetElement[0]; + ttWidth = tourtip[0].offsetWidth; + ttHeight = tourtip[0].offsetHeight; + width = targetElement[0].offsetWidth; + height = targetElement[0].offsetHeight; + // Calculate the tourtip's top and left coordinates to center it switch (scope.ttPlacement) { case 'right': ttPosition = { - top: position.top, - left: position.left + width + scope.ttOffset + top: position.offsetTop, + left: position.offsetLeft + width + scope.ttOffset }; break; case 'bottom': ttPosition = { - top: position.top + height + scope.ttOffset, - left: position.left + top: position.offsetTop + height + scope.ttOffset, + left: position.offsetLeft }; break; case 'left': ttPosition = { - top: position.top, - left: position.left - ttWidth - scope.ttOffset + top: position.offsetTop, + left: position.offsetLeft - ttWidth - scope.ttOffset }; break; default: ttPosition = { - top: position.top - ttHeight - scope.ttOffset, - left: position.left + top: position.offsetTop - ttHeight - scope.ttOffset, + left: position.offsetLeft }; break; } ttPosition.top += 'px'; ttPosition.left += 'px'; + // Now set the calculated positioning. tourtip.css(ttPosition); + // Scroll to the tour tip scrollTo(tourtip, -200, -300, tourConfig.scrollSpeed); }; angular.element($window).bind('resize.' + scope.$id, function () { @@ -203,9 +218,10 @@ updatePosition(); } function hide() { - tourtip.detach(); + tourtip.addClass('ng-hide'); angular.element($window).unbind('resize.' + scope.$id); } + // Make sure tooltip is destroyed and removed. scope.$on('$destroy', function onDestroyTourtip() { angular.element($window).unbind('resize.' + scope.$id); tourtip.remove(); @@ -294,19 +310,19 @@ return new OrderedList(); }; return orderedListFactory; - }).factory('scrollTo', function () { - return function (target, offsetY, offsetX, speed) { - if (target) { - offsetY = offsetY || -100; - offsetX = offsetX || -100; - speed = speed || 500; - $('html,body').stop().animate({ - scrollTop: target.offset().top + offsetY, - scrollLeft: target.offset().left + offsetX - }, speed); - } else { - $('html,body').stop().animate({ scrollTop: 0 }, speed); - } - }; - }); + }).factory('scrollTo', [ + '$window', + function ($window) { + return function (target, offsetY, offsetX, speed) { + if (target) { + offsetY = offsetY || -100; + offsetX = offsetX || -100; + speed = speed || 500; + $window.scrollTo(target[0].offsetLeft + offsetX, target[0].offsetTop + offsetY); + } else { + $window.scrollTo(0, 0); + } + }; + } + ]); }(window, document)); \ No newline at end of file diff --git a/dist/angular-tour.min.js b/dist/angular-tour.min.js index d331211..c42d84f 100644 --- a/dist/angular-tour.min.js +++ b/dist/angular-tour.min.js @@ -1 +1 @@ -!function(){"use strict";angular.module("angular-tour",["angular-tour.tour"]),angular.module("angular-tour.tour",[]).constant("tourConfig",{placement:"top",animation:!0,nextLabel:"Next",scrollSpeed:500,offset:28}).controller("TourController",["$scope","orderedList",function(a,b){var c=this,d=c.steps=b();c.postTourCallback=angular.noop,c.postStepCallback=angular.noop,c.currentStep=0,a.$watch(function(){return c.currentStep},function(a){c.select(a)}),c.select=function(a){if(angular.isNumber(a)){c.unselectAllSteps();var b=d.get(a);b&&(b.ttOpen=!0),c.currentStep!==a&&(c.currentStep=a),a>=d.getCount()&&c.postTourCallback(),c.postStepCallback()}},c.addStep=function(a){angular.isNumber(a.index)&&!isNaN(a.index)?d.set(a.index,a):d.push(a)},c.unselectAllSteps=function(){d.forEach(function(a){a.ttOpen=!1})},c.cancelTour=function(){c.unselectAllSteps(),c.postTourCallback()},a.openTour=function(){var a=c.currentStep>=d.getCount()||c.currentStep<0?0:c.currentStep;c.select(a)},a.closeTour=function(){c.cancelTour()}}]).directive("tour",["$parse",function(a){return{controller:"TourController",restrict:"EA",scope:!0,link:function(b,c,d,e){if(!angular.isDefined(d.step))throw"The directive requires a `step` attribute to bind the current step to.";var f=a(d.step);b.$watch(d.step,function(a){e.currentStep=a}),e.postTourCallback=function(){angular.isDefined(d.postTour)&&b.$parent.$eval(d.postTour)},e.postStepCallback=function(){angular.isDefined(d.postStep)&&b.$parent.$eval(d.postStep)},b.setCurrentStep=function(a){f.assign(b.$parent,a),e.currentStep=a},b.getCurrentStep=function(){return e.currentStep}}}}]).directive("tourtip",["$window","$compile","$interpolate","$timeout","scrollTo","tourConfig",function(a,b,c,d,e,f){var g=(c.startSymbol(),c.endSymbol(),"
");return{require:"^tour",restrict:"EA",scope:!0,link:function(c,h,i,j){function k(){var b,d,g,i,j,k,l;if(c.ttContent){c.ttAnimation?m.fadeIn():m.css({display:"block"}),h.after(m),l=h.children().eq(0).length>0?h.children().eq(0):h;var n=function(){switch(b=l.position(),d=m.width(),g=m.height(),k=l.width(),j=l.height(),c.ttPlacement){case"right":i={top:b.top,left:b.left+k+c.ttOffset};break;case"bottom":i={top:b.top+j+c.ttOffset,left:b.left};break;case"left":i={top:b.top,left:b.left-d-c.ttOffset};break;default:i={top:b.top-g-c.ttOffset,left:b.left}}i.top+="px",i.left+="px",m.css(i),e(m,-200,-300,f.scrollSpeed)};angular.element(a).bind("resize."+c.$id,function(){n()}),n()}}function l(){m.detach(),angular.element(a).unbind("resize."+c.$id)}i.$observe("tourtip",function(a){c.ttContent=a}),i.$observe("tourtipPlacement",function(a){c.ttPlacement=a||f.placement}),i.$observe("tourtipNextLabel",function(a){c.ttNextLabel=a||f.nextLabel}),i.$observe("tourtipOffset",function(a){c.ttOffset=parseInt(a,10)||f.offset}),c.ttOpen=!1,c.ttAnimation=f.animation,c.index=parseInt(i.tourtipStep,10);var m=b(g)(c);j.addStep(c),d(function(){c.$watch("ttOpen",function(a){a?k():l()})},500),c.$on("$destroy",function(){angular.element(a).unbind("resize."+c.$id),m.remove(),m=null})}}}]).directive("tourPopup",function(){return{replace:!0,templateUrl:"tour/tour.tpl.html",scope:!0,restrict:"EA",link:function(){}}}).factory("orderedList",function(){var a=function(){this.map={},this._array=[]};a.prototype.set=function(a,b){if(angular.isNumber(a))if(a in this.map)this.map[a]=b;else{if(a0?a-1:0;this._array.splice(c,0,a)}else this._array.push(a);this.map[a]=b,this._array.sort(function(a,b){return a-b})}},a.prototype.indexOf=function(a){for(var b in this.map)if(this.map.hasOwnProperty(b)&&this.map[b]===a)return Number(b)},a.prototype.push=function(a){var b=this._array[this._array.length-1]+1||0;this._array.push(b),this.map[b]=a,this._array.sort(function(a,b){return a-b})},a.prototype.remove=function(a){var b=this._array.indexOf(a);if(-1===b)throw new Error("key does not exist");this._array.splice(b,1),delete this.map[a]},a.prototype.get=function(a){return this.map[a]},a.prototype.getCount=function(){return this._array.length},a.prototype.forEach=function(a){for(var b,c,d=0;d=d.getCount()&&c.postTourCallback(),c.postStepCallback()}},c.addStep=function(a){angular.isNumber(a.index)&&!isNaN(a.index)?d.set(a.index,a):d.push(a)},c.unselectAllSteps=function(){d.forEach(function(a){a.ttOpen=!1})},c.cancelTour=function(){c.unselectAllSteps(),c.postTourCallback()},a.openTour=function(){var a=c.currentStep>=d.getCount()||c.currentStep<0?0:c.currentStep;c.select(a)},a.closeTour=function(){c.cancelTour()}}]).directive("tour",["$parse",function(a){return{controller:"TourController",restrict:"EA",scope:!0,link:function(b,c,d,e){if(!angular.isDefined(d.step))throw"The directive requires a `step` attribute to bind the current step to.";var f=a(d.step);b.$watch(d.step,function(a){e.currentStep=a}),e.postTourCallback=function(){angular.isDefined(d.postTour)&&b.$parent.$eval(d.postTour)},e.postStepCallback=function(){angular.isDefined(d.postStep)&&b.$parent.$eval(d.postStep)},b.setCurrentStep=function(a){f.assign(b.$parent,a),e.currentStep=a},b.getCurrentStep=function(){return e.currentStep}}}}]).directive("tourtip",["$window","$compile","$interpolate","$timeout","scrollTo","tourConfig",function(a,b,c,d,e,f){var g=(c.startSymbol(),c.endSymbol(),"
");return{require:"^tour",restrict:"EA",scope:!0,link:function(c,h,i,j){function k(){var b,d,g,i,j,k,l;if(c.ttContent){m.css({display:"block"}),m.removeClass("ng-hide"),h.after(m),l=h.children().eq(0).length>0?h.children().eq(0):h;var n=function(){switch(b=l[0],d=m[0].offsetWidth,g=m[0].offsetHeight,k=l[0].offsetWidth,j=l[0].offsetHeight,c.ttPlacement){case"right":i={top:b.offsetTop,left:b.offsetLeft+k+c.ttOffset};break;case"bottom":i={top:b.offsetTop+j+c.ttOffset,left:b.offsetLeft};break;case"left":i={top:b.offsetTop,left:b.offsetLeft-d-c.ttOffset};break;default:i={top:b.offsetTop-g-c.ttOffset,left:b.offsetLeft}}i.top+="px",i.left+="px",m.css(i),e(m,-200,-300,f.scrollSpeed)};angular.element(a).bind("resize."+c.$id,function(){n()}),n()}}function l(){m.addClass("ng-hide"),angular.element(a).unbind("resize."+c.$id)}i.$observe("tourtip",function(a){c.ttContent=a}),i.$observe("tourtipPlacement",function(a){c.ttPlacement=a||f.placement}),i.$observe("tourtipNextLabel",function(a){c.ttNextLabel=a||f.nextLabel}),i.$observe("tourtipOffset",function(a){c.ttOffset=parseInt(a,10)||f.offset}),c.ttOpen=!1,c.ttAnimation=f.animation,c.index=parseInt(i.tourtipStep,10);var m=b(g)(c);j.addStep(c),d(function(){c.$watch("ttOpen",function(a){a?k():l()})},500),c.$on("$destroy",function(){angular.element(a).unbind("resize."+c.$id),m.remove(),m=null})}}}]).directive("tourPopup",function(){return{replace:!0,templateUrl:"tour/tour.tpl.html",scope:!0,restrict:"EA",link:function(a,b,c){}}}).factory("orderedList",function(){var a=function(){this.map={},this._array=[]};a.prototype.set=function(a,b){if(angular.isNumber(a))if(a in this.map)this.map[a]=b;else{if(a0?a-1:0;this._array.splice(c,0,a)}else this._array.push(a);this.map[a]=b,this._array.sort(function(a,b){return a-b})}},a.prototype.indexOf=function(a){for(var b in this.map)if(this.map.hasOwnProperty(b)&&this.map[b]===a)return Number(b)},a.prototype.push=function(a){var b=this._array[this._array.length-1]+1||0;this._array.push(b),this.map[b]=a,this._array.sort(function(a,b){return a-b})},a.prototype.remove=function(a){var b=this._array.indexOf(a);if(-1===b)throw new Error("key does not exist");this._array.splice(b,1),delete this.map[a]},a.prototype.get=function(a){return this.map[a]},a.prototype.getCount=function(){return this._array.length},a.prototype.forEach=function(a){for(var b,c,d=0;d=0.8.0" + "node": ">=0.10.0" }, "scripts": { "test": "grunt test" From 73cdb4a52461eed3309447b4ac2d722302876006 Mon Sep 17 00:00:00 2001 From: Brian Yanosik Date: Wed, 16 Sep 2015 14:49:24 -0500 Subject: [PATCH 5/9] fixed indenting --- bower.json | 3 +- src/tour/tour.js | 574 +++++++++++++++++++++++------------------------ 2 files changed, 286 insertions(+), 291 deletions(-) diff --git a/bower.json b/bower.json index 57043e0..39ef260 100644 --- a/bower.json +++ b/bower.json @@ -31,8 +31,7 @@ "package.json" ], "dependencies": { - "angular": "~1.2.x", - "jquery": "~2.0.3" + "angular": "~1.2.x" }, "devDependencies": { "angular-mocks": "~1.x", diff --git a/src/tour/tour.js b/src/tour/tour.js index 74230ce..ef691bb 100644 --- a/src/tour/tour.js +++ b/src/tour/tour.js @@ -2,23 +2,23 @@ angular.module('angular-tour.tour', []) -/** - * tourConfig - * Default configuration, can be customized by injecting tourConfig into your app and modifying it - */ -.constant('tourConfig', { - placement: 'top', // default placement relative to target. 'top', 'right', 'left', 'bottom' - animation: true, // if tips fade in - nextLabel: 'Next', // default text in the next tip button - scrollSpeed: 500, // page scrolling speed in milliseconds - offset: 28 // how many pixels offset the tip is from the target -}) - -/** - * TourController - * the logic for the tour, which manages all the steps - */ -.controller('TourController', function($scope, $timeout, orderedList) { + /** + * tourConfig + * Default configuration, can be customized by injecting tourConfig into your app and modifying it + */ + .constant('tourConfig', { + placement : 'top', // default placement relative to target. 'top', 'right', 'left', 'bottom' + animation : true, // if tips fade in + nextLabel : 'Next', // default text in the next tip button + scrollSpeed : 500, // page scrolling speed in milliseconds + offset : 28 // how many pixels offset the tip is from the target + }) + + /** + * TourController + * the logic for the tour, which manages all the steps + */ + .controller('TourController', function($scope, orderedList) { var self = this, steps = self.steps = orderedList(); @@ -28,193 +28,191 @@ angular.module('angular-tour.tour', []) self.currentStep = 0; // if currentStep changes, select the new step - $scope.$watch(function() { - return self.currentStep; - }, - function(val) { - self.select(val); - } + $scope.$watch( function() { return self.currentStep; }, + function ( val ) { + self.select(val); + } ); self.select = function(nextIndex) { - if (!angular.isNumber(nextIndex)) return; + if(!angular.isNumber(nextIndex)) return; - self.unselectAllSteps(); - var step = steps.get(nextIndex); - if (step) { - step.ttOpen = true; - } + self.unselectAllSteps(); + var step = steps.get(nextIndex); + if(step) { + step.ttOpen = true; + } - // update currentStep if we manually selected this index - if (self.currentStep !== nextIndex) { - self.currentStep = nextIndex; - } + // update currentStep if we manually selected this index + if(self.currentStep !== nextIndex) { + self.currentStep = nextIndex; + } - if (nextIndex >= steps.getCount()) { - self.postTourCallback(); - } - self.postStepCallback(); + if(nextIndex >= steps.getCount()) { + self.postTourCallback(); + } + self.postStepCallback(); }; self.addStep = function(step) { - if (angular.isNumber(step.index) && !isNaN(step.index)) { - steps.set(step.index, step); - } else { - steps.push(step); - } + if(angular.isNumber(step.index) && !isNaN(step.index)) { + steps.set(step.index, step); + } else { + steps.push(step); + } }; self.unselectAllSteps = function() { - steps.forEach(function(step) { - step.ttOpen = false; - }); + steps.forEach(function (step) { + step.ttOpen = false; + }); }; - self.cancelTour = function() { - self.unselectAllSteps(); - self.postTourCallback(); + self.cancelTour = function () { + self.unselectAllSteps(); + self.postTourCallback(); }; $scope.openTour = function() { - // open at first step if we've already finished tour - var startStep = self.currentStep >= steps.getCount() || self.currentStep < 0 ? 0 : self.currentStep; - self.select(startStep); + // open at first step if we've already finished tour + var startStep = self.currentStep >= steps.getCount() || self.currentStep < 0 ? 0 : self.currentStep; + self.select(startStep); }; $scope.closeTour = function() { - self.cancelTour(); + self.cancelTour(); }; -}) + }) -/** - * Tour - * directive that allows you to control the tour - */ -.directive('tour', function($parse) { + /** + * Tour + * directive that allows you to control the tour + */ + .directive('tour', function ($parse) { return { - controller: 'TourController', - restrict: 'EA', - scope: true, - link: function(scope, element, attrs, ctrl) { - if (!angular.isDefined(attrs.step)) { - throw ('The directive requires a `step` attribute to bind the current step to.'); - } - var model = $parse(attrs.step); - - // Watch current step view model and update locally - scope.$watch(attrs.step, function(newVal) { - ctrl.currentStep = newVal; - }); - - ctrl.postTourCallback = function() { - if (angular.isDefined(attrs.postTour)) { - scope.$parent.$eval(attrs.postTour); - } - }; - - ctrl.postStepCallback = function() { - if (angular.isDefined(attrs.postStep)) { - scope.$parent.$eval(attrs.postStep); - } - }; + controller: 'TourController', + restrict: 'EA', + scope: true, + link: function (scope, element, attrs, ctrl) { + if(!angular.isDefined(attrs.step)) { + throw('The directive requires a `step` attribute to bind the current step to.'); + } + var model = $parse(attrs.step); - // update the current step in the view as well as in our controller - scope.setCurrentStep = function(val) { - model.assign(scope.$parent, val); - ctrl.currentStep = val; - }; + // Watch current step view model and update locally + scope.$watch(attrs.step, function(newVal){ + ctrl.currentStep = newVal; + }); - scope.getCurrentStep = function() { - return ctrl.currentStep; - }; - } + ctrl.postTourCallback = function() { + if(angular.isDefined(attrs.postTour)) { + scope.$parent.$eval(attrs.postTour); + } + }; + + ctrl.postStepCallback = function() { + if(angular.isDefined(attrs.postStep)) { + scope.$parent.$eval(attrs.postStep); + } + }; + + // update the current step in the view as well as in our controller + scope.setCurrentStep = function(val) { + model.assign(scope.$parent, val); + ctrl.currentStep = val; + }; + + scope.getCurrentStep = function() { + return ctrl.currentStep; + }; + } }; -}) + }) -/** - * Tourtip - * tourtip manages the state of the tour-popup directive - */ -.directive('tourtip', function($window, $compile, $interpolate, $timeout, scrollTo, tourConfig) { + /** + * Tourtip + * tourtip manages the state of the tour-popup directive + */ + .directive('tourtip', function ($window, $compile, $interpolate, $timeout, scrollTo, tourConfig) { var startSym = $interpolate.startSymbol(), endSym = $interpolate.endSymbol(); var template = '
'; return { - require: '^tour', - restrict: 'EA', - scope: true, - link: function(scope, element, attrs, tourCtrl) { - attrs.$observe('tourtip', function(val) { - scope.ttContent = val; - }); - - attrs.$observe('tourtipPlacement', function(val) { - scope.ttPlacement = val || tourConfig.placement; - }); - - attrs.$observe('tourtipNextLabel', function(val) { - scope.ttNextLabel = val || tourConfig.nextLabel; - }); - - attrs.$observe('tourtipOffset', function(val) { - scope.ttOffset = parseInt(val, 10) || tourConfig.offset; - }); - - scope.ttOpen = false; - scope.ttAnimation = tourConfig.animation; - scope.index = parseInt(attrs.tourtipStep, 10); - - var tourtip = $compile(template)(scope); - tourCtrl.addStep(scope); - - // wrap this in a time out because the tourtip won't compile right away - $timeout(function() { - scope.$watch('ttOpen', function(val) { - if (val) { - show(); - } else { - hide(); - } - }); - }, 500); - - function show() { - var position, - ttWidth, - ttHeight, - ttPosition, - height, - width, - targetElement; - - if (!scope.ttContent) { - return; - } + require: '^tour', + restrict: 'EA', + scope: true, + link: function (scope, element, attrs, tourCtrl) { + attrs.$observe( 'tourtip', function ( val ) { + scope.ttContent = val; + }); + + attrs.$observe( 'tourtipPlacement', function ( val ) { + scope.ttPlacement = val || tourConfig.placement; + }); + + attrs.$observe( 'tourtipNextLabel', function ( val ) { + scope.ttNextLabel = val || tourConfig.nextLabel; + }); + + attrs.$observe( 'tourtipOffset', function ( val ) { + scope.ttOffset = parseInt(val, 10) || tourConfig.offset; + }); + + scope.ttOpen = false; + scope.ttAnimation = tourConfig.animation; + scope.index = parseInt(attrs.tourtipStep, 10); + + var tourtip = $compile( template )( scope ); + tourCtrl.addStep(scope); + + // wrap this in a time out because the tourtip won't compile right away + $timeout( function() { + scope.$watch('ttOpen', function(val) { + if(val) { + show(); + } else { + hide(); + } + }); + }, 500); + + function show() { + var position, + ttWidth, + ttHeight, + ttPosition, + height, + width, + targetElement; + + if ( ! scope.ttContent ) { + return; + } /*if(scope.ttAnimation) - tourtip.fadeIn(); - else { - tourtip.css({ display: 'block' }); + tourtip.fadeIn(); + else { + tourtip.css({ display: 'block' }); }*/ tourtip.css({ display: 'block' }); tourtip.removeClass('ng-hide'); - // Append it to the dom - element.after(tourtip); + // Append it to the dom + element.after( tourtip ); - // Try to set target to the first child of our tour directive - if (element.children().eq(0).length > 0) { - targetElement = element.children().eq(0); - } else { - targetElement = element; - } + // Try to set target to the first child of our tour directive + if(element.children().eq(0).length>0) { + targetElement = element.children().eq(0); + } else { + targetElement = element; + } - var updatePosition = function() { - // Get the position of the directive element + var updatePosition = function() { + // Get the position of the directive element position = targetElement[0]; ttWidth = tourtip[0].offsetWidth; @@ -223,166 +221,164 @@ angular.module('angular-tour.tour', []) width = targetElement[0].offsetWidth; height = targetElement[0].offsetHeight; - // Calculate the tourtip's top and left coordinates to center it - switch (scope.ttPlacement) { - case 'right': - ttPosition = { + // Calculate the tourtip's top and left coordinates to center it + switch ( scope.ttPlacement ) { + case 'right': + ttPosition = { top: position.offsetTop, left: position.offsetLeft + width + scope.ttOffset - }; - break; - case 'bottom': - ttPosition = { + }; + break; + case 'bottom': + ttPosition = { top: position.offsetTop + height + scope.ttOffset, left: position.offsetLeft - }; - break; - case 'left': - ttPosition = { + }; + break; + case 'left': + ttPosition = { top: position.offsetTop, left: position.offsetLeft - ttWidth - scope.ttOffset - }; - break; - default: - ttPosition = { + }; + break; + default: + ttPosition = { top: position.offsetTop - ttHeight - scope.ttOffset, left: position.offsetLeft - }; - break; - } - - ttPosition.top += 'px'; - ttPosition.left += 'px'; - - // Now set the calculated positioning. - tourtip.css(ttPosition); + }; + break; + } - // Scroll to the tour tip + ttPosition.top += 'px'; + ttPosition.left += 'px'; + // Now set the calculated positioning. + tourtip.css( ttPosition ); - scrollTo(tourtip, -200, -300, tourConfig.scrollSpeed); - }; + // Scroll to the tour tip + scrollTo(tourtip, -200, -300, tourConfig.scrollSpeed); + }; - angular.element($window).bind('resize.' + scope.$id, function() { - updatePosition(); - }); - updatePosition(); - } + angular.element($window).bind('resize.' + scope.$id, function() { + updatePosition(); + }); + updatePosition(); + } - function hide() { + function hide() { tourtip.addClass('ng-hide'); - angular.element($window).unbind('resize.' + scope.$id); - } - - // Make sure tooltip is destroyed and removed. - scope.$on('$destroy', function onDestroyTourtip() { - angular.element($window).unbind('resize.' + scope.$id); - tourtip.remove(); - tourtip = null; - }); + angular.element($window).unbind('resize.' + scope.$id); } + + // Make sure tooltip is destroyed and removed. + scope.$on('$destroy', function onDestroyTourtip() { + angular.element($window).unbind('resize.' + scope.$id); + tourtip.remove(); + tourtip = null; + }); + } }; -}) + }) -/** - * TourPopup - * the directive that actually has the template for the tip - */ -.directive('tourPopup', function() { + /** + * TourPopup + * the directive that actually has the template for the tip + */ + .directive('tourPopup', function () { return { - replace: true, - templateUrl: 'tour/tour.tpl.html', - scope: true, - restrict: 'EA', - link: function(scope, element, attrs) {} + replace: true, + templateUrl: 'tour/tour.tpl.html', + scope: true, + restrict: 'EA', + link: function (scope, element, attrs) { + } }; -}) + }) -/** - * OrderedList - * Used for keeping steps in order - */ -.factory('orderedList', function() { + /** + * OrderedList + * Used for keeping steps in order + */ + .factory('orderedList', function () { var OrderedList = function() { - this.map = {}; - this._array = []; + this.map = {}; + this._array = []; }; - - OrderedList.prototype.set = function(key, value) { - if (!angular.isNumber(key)) - return; - if (key in this.map) { - this.map[key] = value; + + OrderedList.prototype.set = function (key, value) { + if (!angular.isNumber(key)) + return; + if (key in this.map) { + this.map[key] = value; + } else { + if (key < this._array.length) { + var insertIndex = key - 1 > 0 ? key - 1 : 0; + this._array.splice(insertIndex, 0, key); } else { - if (key < this._array.length) { - var insertIndex = key - 1 > 0 ? key - 1 : 0; - this._array.splice(insertIndex, 0, key); - } else { - this._array.push(key); - } - this.map[key] = value; - this._array.sort(function(a, b) { - return a - b; - }); + this._array.push(key); } - }; - OrderedList.prototype.indexOf = function(value) { - for (var prop in this.map) { - if (this.map.hasOwnProperty(prop)) { - if (this.map[prop] === value) - return Number(prop); - } - } - }; - OrderedList.prototype.push = function(value) { - var key = this._array[this._array.length - 1] + 1 || 0; - this._array.push(key); this.map[key] = value; - this._array.sort(function(a, b) { - return a - b; + this._array.sort(function(a,b){ + return a-b; }); + } }; - OrderedList.prototype.remove = function(key) { - var index = this._array.indexOf(key); - if (index === -1) { - throw new Error('key does not exist'); + OrderedList.prototype.indexOf = function (value) { + for (var prop in this.map) { + if (this.map.hasOwnProperty(prop)) { + if (this.map[prop] === value) + return Number(prop); } - this._array.splice(index, 1); - delete this.map[key]; + } }; - OrderedList.prototype.get = function(key) { - return this.map[key]; + OrderedList.prototype.push = function (value) { + var key = this._array[this._array.length - 1] + 1 || 0; + this._array.push(key); + this.map[key] = value; + this._array.sort(function(a, b) { + return a-b; + }); }; - OrderedList.prototype.getCount = function() { - return this._array.length; + OrderedList.prototype.remove = function (key) { + var index = this._array.indexOf(key); + if (index === -1) { + throw new Error('key does not exist'); + } + this._array.splice(index, 1); + delete this.map[key]; }; - OrderedList.prototype.forEach = function(f) { - var key, value; - for (var i = 0; i < this._array.length; i++) { - key = this._array[i]; - value = this.map[key]; - f(value, key); - } + OrderedList.prototype.get = function (key) { + return this.map[key]; + }; + OrderedList.prototype.getCount = function () { + return this._array.length; }; - OrderedList.prototype.first = function() { - var key, value; - key = this._array[0]; + OrderedList.prototype.forEach = function (f) { + var key, value; + for (var i = 0; i < this._array.length; i++) { + key = this._array[i]; value = this.map[key]; - return value; + f(value, key); + } + }; + OrderedList.prototype.first = function () { + var key, value; + key = this._array[0]; + value = this.map[key]; + return value; }; var orderedListFactory = function() { - return new OrderedList(); + return new OrderedList(); }; - + return orderedListFactory; -}) - -/** - * ScrollTo - * Smoothly scroll to a dom element - */ + }) + /** + * ScrollTo + * Smoothly scroll to a dom element + */ .factory('scrollTo', function($window, $timeout, tourConfig) { var smooth_scroll = function(targetX, targetY, duration) { @@ -446,13 +442,13 @@ angular.module('angular-tour.tour', []) } return function(target, offsetY, offsetX, speed) { - if (target) { - offsetY = offsetY || -100; - offsetX = offsetX || -100; - speed = speed || 500; + if(target) { + offsetY = offsetY || -100; + offsetX = offsetX || -100; + speed = speed || 500; smooth_scroll(target[0].offsetLeft + offsetX, target[0].offsetTop + offsetY, speed); - } else { + } else { smooth_scroll(0, 0, speed); - } + } }; -}); + }); From 82e18e7e74e9f4baf8d4077ff163bd18f38a3b46 Mon Sep 17 00:00:00 2001 From: Brian Yanosik Date: Wed, 16 Sep 2015 14:52:06 -0500 Subject: [PATCH 6/9] fixed some more indenting --- src/tour/tour.js | 111 +++++++++++++++++++++-------------------------- 1 file changed, 49 insertions(+), 62 deletions(-) diff --git a/src/tour/tour.js b/src/tour/tour.js index ef691bb..11c84ec 100644 --- a/src/tour/tour.js +++ b/src/tour/tour.js @@ -190,16 +190,10 @@ angular.module('angular-tour.tour', []) if ( ! scope.ttContent ) { return; } - - /*if(scope.ttAnimation) - tourtip.fadeIn(); - else { - tourtip.css({ display: 'block' }); - }*/ - tourtip.css({ - display: 'block' - }); - tourtip.removeClass('ng-hide'); + tourtip.css({ + display: 'block' + }); + tourtip.removeClass('ng-hide'); // Append it to the dom element.after( tourtip ); @@ -213,38 +207,38 @@ angular.module('angular-tour.tour', []) var updatePosition = function() { // Get the position of the directive element - position = targetElement[0]; + position = targetElement[0]; - ttWidth = tourtip[0].offsetWidth; - ttHeight = tourtip[0].offsetHeight; + ttWidth = tourtip[0].offsetWidth; + ttHeight = tourtip[0].offsetHeight; - width = targetElement[0].offsetWidth; - height = targetElement[0].offsetHeight; + width = targetElement[0].offsetWidth; + height = targetElement[0].offsetHeight; // Calculate the tourtip's top and left coordinates to center it switch ( scope.ttPlacement ) { case 'right': ttPosition = { - top: position.offsetTop, - left: position.offsetLeft + width + scope.ttOffset + top: position.offsetTop, + left: position.offsetLeft + width + scope.ttOffset }; break; case 'bottom': ttPosition = { - top: position.offsetTop + height + scope.ttOffset, - left: position.offsetLeft + top: position.offsetTop + height + scope.ttOffset, + left: position.offsetLeft }; break; case 'left': ttPosition = { - top: position.offsetTop, - left: position.offsetLeft - ttWidth - scope.ttOffset + top: position.offsetTop, + left: position.offsetLeft - ttWidth - scope.ttOffset }; break; default: ttPosition = { - top: position.offsetTop - ttHeight - scope.ttOffset, - left: position.offsetLeft + top: position.offsetTop - ttHeight - scope.ttOffset, + left: position.offsetLeft }; break; } @@ -304,7 +298,7 @@ angular.module('angular-tour.tour', []) this.map = {}; this._array = []; }; - + OrderedList.prototype.set = function (key, value) { if (!angular.isNumber(key)) return; @@ -371,7 +365,7 @@ angular.module('angular-tour.tour', []) var orderedListFactory = function() { return new OrderedList(); }; - + return orderedListFactory; }) @@ -388,56 +382,49 @@ angular.module('angular-tour.tour', []) duration = Math.round(duration); if (duration < 0) { - return Promise.reject("bad duration"); + return Promise.reject("bad duration"); } if (duration === 0) { - window.scrollTo(targetX, targetY); - return Promise.resolve(); + window.scrollTo(targetX, targetY); + return Promise.resolve(); } var start_time = Date.now(), - end_time = start_time + duration, - startLeft = window.scrollX, - startTop = window.scrollY, - distanceX = targetX - startLeft, - distanceY = targetY - startTop; + end_time = start_time + duration, + startLeft = window.scrollX, + startTop = window.scrollY, + distanceX = targetX - startLeft, + distanceY = targetY - startTop; // based on http://en.wikipedia.org/wiki/Smoothstep var smooth_step = function(start, end, point) { - if (point <= start) { - return 0; - } - if (point >= end) { - return 1; - } - var x = (point - start) / (end - start); // interpolation - return x * x * (3 - 2 * x); + if (point <= start) { + return 0; + } + if (point >= end) { + return 1; + } + var x = (point - start) / (end - start); // interpolation + return x * x * (3 - 2 * x); } return new Promise(function(resolve, reject) { - - var scroll_frame = function() { - - var now = Date.now(), - point = smooth_step(start_time, end_time, now), - frameLeft = Math.round(startLeft + (distanceX * point)), - frameTop = Math.round(startTop + (distanceY * point)); - - - window.scrollTo(frameLeft, frameTop) - - // check if we're done! - if (now >= end_time) { - resolve(); - return; - } - - // schedule next frame for execution - $timeout(scroll_frame, 0); + var scroll_frame = function() { + var now = Date.now(), + point = smooth_step(start_time, end_time, now), + frameLeft = Math.round(startLeft + (distanceX * point)), + frameTop = Math.round(startTop + (distanceY * point)); + window.scrollTo(frameLeft, frameTop) + // check if we're done! + if (now >= end_time) { + resolve(); + return; } - - // boostrap the animation process + // schedule next frame for execution $timeout(scroll_frame, 0); + } + // boostrap the animation process + $timeout(scroll_frame, 0); }); } From 722cbd8a560f3a312f1c600c440ee30d13a8fd79 Mon Sep 17 00:00:00 2001 From: Brian Yanosik Date: Wed, 16 Sep 2015 14:54:40 -0500 Subject: [PATCH 7/9] additional tweaks --- src/tour/tour.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/tour/tour.js b/src/tour/tour.js index 11c84ec..fda6687 100644 --- a/src/tour/tour.js +++ b/src/tour/tour.js @@ -190,10 +190,10 @@ angular.module('angular-tour.tour', []) if ( ! scope.ttContent ) { return; } - tourtip.css({ - display: 'block' - }); - tourtip.removeClass('ng-hide'); + tourtip.css({ + display: 'block' + }); + tourtip.removeClass('ng-hide'); // Append it to the dom element.after( tourtip ); @@ -207,13 +207,13 @@ angular.module('angular-tour.tour', []) var updatePosition = function() { // Get the position of the directive element - position = targetElement[0]; + position = targetElement[0]; - ttWidth = tourtip[0].offsetWidth; - ttHeight = tourtip[0].offsetHeight; + ttWidth = tourtip[0].offsetWidth; + ttHeight = tourtip[0].offsetHeight; - width = targetElement[0].offsetWidth; - height = targetElement[0].offsetHeight; + width = targetElement[0].offsetWidth; + height = targetElement[0].offsetHeight; // Calculate the tourtip's top and left coordinates to center it switch ( scope.ttPlacement ) { @@ -260,7 +260,7 @@ angular.module('angular-tour.tour', []) } function hide() { - tourtip.addClass('ng-hide'); + tourtip.addClass('ng-hide'); angular.element($window).unbind('resize.' + scope.$id); } @@ -373,7 +373,7 @@ angular.module('angular-tour.tour', []) * ScrollTo * Smoothly scroll to a dom element */ -.factory('scrollTo', function($window, $timeout, tourConfig) { + .factory('scrollTo', function($window, $timeout, tourConfig) { var smooth_scroll = function(targetX, targetY, duration) { From a15de8bd803b617574627b07ff653ed72fef582c Mon Sep 17 00:00:00 2001 From: Brian Yanosik Date: Wed, 16 Sep 2015 14:56:16 -0500 Subject: [PATCH 8/9] final tweaks --- src/tour/tour.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/tour/tour.js b/src/tour/tour.js index fda6687..bbb2dba 100644 --- a/src/tour/tour.js +++ b/src/tour/tour.js @@ -190,6 +190,7 @@ angular.module('angular-tour.tour', []) if ( ! scope.ttContent ) { return; } + tourtip.css({ display: 'block' }); @@ -433,9 +434,9 @@ angular.module('angular-tour.tour', []) offsetY = offsetY || -100; offsetX = offsetX || -100; speed = speed || 500; - smooth_scroll(target[0].offsetLeft + offsetX, target[0].offsetTop + offsetY, speed); + smooth_scroll(target[0].offsetLeft + offsetX, target[0].offsetTop + offsetY, speed); } else { - smooth_scroll(0, 0, speed); + smooth_scroll(0, 0, speed); } }; }); From c1de35d12ee2113f83ebeca5563702c6aec1c06f Mon Sep 17 00:00:00 2001 From: Brian Yanosik Date: Wed, 16 Sep 2015 15:02:53 -0500 Subject: [PATCH 9/9] removed jquery reference --- demo/index.html | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/demo/index.html b/demo/index.html index 523fde8..0b04805 100644 --- a/demo/index.html +++ b/demo/index.html @@ -18,9 +18,7 @@ - - - +