Start on tour infrastructure. Note that this code works but is NOT STYLED and has a FAKE TEMP TOUR in it
This commit is contained in:
parent
37507b7d7d
commit
a049fc57c6
10 changed files with 411 additions and 130 deletions
|
@ -103,8 +103,8 @@ function getMarkedDown(string) {
|
|||
}
|
||||
|
||||
// Start the application code itself.
|
||||
quayApp = angular.module('quay', ['ngRoute', 'chieffancypants.loadingBar', 'restangular', 'angularMoment', 'angulartics', /*'angulartics.google.analytics',*/ 'angulartics.mixpanel', '$strap.directives', 'ngCookies', 'ngSanitize', 'angular-md5'], function($provide, cfpLoadingBarProvider) {
|
||||
cfpLoadingBarProvider.includeSpinner = false;
|
||||
quayApp = angular.module('quay', ['ngRoute', 'chieffancypants.loadingBar', 'angular-tour', 'restangular', 'angularMoment', 'angulartics', /*'angulartics.google.analytics',*/ 'angulartics.mixpanel', '$strap.directives', 'ngCookies', 'ngSanitize', 'angular-md5'], function($provide, cfpLoadingBarProvider) {
|
||||
cfpLoadingBarProvider.includeSpinner = false;
|
||||
|
||||
$provide.factory('UtilService', ['$sanitize', function($sanitize) {
|
||||
var utilService = {};
|
||||
|
@ -2510,6 +2510,7 @@ quayApp.directive('ngBlur', function() {
|
|||
};
|
||||
});
|
||||
|
||||
|
||||
quayApp.run(['$location', '$rootScope', 'Restangular', 'UserService', 'PlanService', '$http', '$timeout',
|
||||
function($location, $rootScope, Restangular, UserService, PlanService, $http, $timeout) {
|
||||
|
||||
|
|
|
@ -42,7 +42,36 @@ function PlansCtrl($scope, $location, UserService, PlanService) {
|
|||
};
|
||||
}
|
||||
|
||||
function GuideCtrl($scope) {
|
||||
function GuideCtrl($scope, AngularTour, AngularTourSignals) {
|
||||
$scope.startTour = function() {
|
||||
AngularTour.start({
|
||||
'title': 'My Test Tour',
|
||||
'steps': [
|
||||
{
|
||||
'title': 'Welcome to the tour!',
|
||||
'content': 'Some cool content'
|
||||
},
|
||||
{
|
||||
'title': 'A step tied to a DOM element',
|
||||
'content': 'This is the best DOM element!',
|
||||
'element': '#test-element'
|
||||
},
|
||||
{
|
||||
'content': 'Waiting for the page to change',
|
||||
'signal': AngularTourSignals.matchesLocation('/repository/')
|
||||
},
|
||||
{
|
||||
'content': 'Waiting for the page to load',
|
||||
'signal': AngularTourSignals.elementAvaliable('*[data-repo="public/publicrepo"]')
|
||||
},
|
||||
{
|
||||
'content': 'Now click on the public repository',
|
||||
'signal': AngularTourSignals.matchesLocation('/repository/public/publicrepo'),
|
||||
'element': '*[data-repo="public/publicrepo"]'
|
||||
}
|
||||
]
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
function SecurityCtrl($scope) {
|
||||
|
|
147
static/js/tour.js
Normal file
147
static/js/tour.js
Normal file
|
@ -0,0 +1,147 @@
|
|||
angular.module("angular-tour", [])
|
||||
.provider('AngularTour', function() {
|
||||
this.$get = ['$document', '$rootScope', '$compile', function($document, $rootScope, $compile) {
|
||||
function _start(tour) {
|
||||
$rootScope.angular_tour_current = tour;
|
||||
}
|
||||
|
||||
function _stop() {
|
||||
$rootScope.angular_tour_current = null;
|
||||
}
|
||||
|
||||
return {
|
||||
start: _start,
|
||||
stop: _stop
|
||||
};
|
||||
|
||||
}];
|
||||
})
|
||||
|
||||
.directive('angularTourOverlay', function() {
|
||||
var directiveDefinitionObject = {
|
||||
priority: 0,
|
||||
templateUrl: '/static/directives/angular-tour-overlay.html',
|
||||
replace: false,
|
||||
transclude: false,
|
||||
restrict: 'C',
|
||||
scope: {
|
||||
'tour': '=tour'
|
||||
},
|
||||
controller: function($scope, $element, $interval) {
|
||||
$scope.stepIndex = 0;
|
||||
$scope.step = null;
|
||||
$scope.interval = null;
|
||||
|
||||
var checkSignalTimer = function() {
|
||||
if (!$scope.step) {
|
||||
stopSignalTimer();
|
||||
return;
|
||||
}
|
||||
|
||||
var signal = $scope.step.signal;
|
||||
if (signal()) {
|
||||
$scope.next();
|
||||
}
|
||||
};
|
||||
|
||||
var stopSignalTimer = function() {
|
||||
if (!$scope.interval) { return; }
|
||||
|
||||
$interval.cancel($scope.interval);
|
||||
$scope.interval = null;
|
||||
};
|
||||
|
||||
var startSignalTimer = function() {
|
||||
$scope.interval = $interval(checkSignalTimer, 500);
|
||||
};
|
||||
|
||||
var closeDomHighlight = function() {
|
||||
if (!$scope.step) { return; }
|
||||
|
||||
var element = $($scope.step.element);
|
||||
element.spotlight('close');
|
||||
};
|
||||
|
||||
var updateDomHighlight = function() {
|
||||
var element = $($scope.step.element);
|
||||
if (!element.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
element.spotlight({
|
||||
opacity: .5,
|
||||
speed: 400,
|
||||
color: '#333',
|
||||
animate: true,
|
||||
easing: 'linear',
|
||||
exitEvent: 'mouseenter',
|
||||
exitEventAppliesToElement: true,
|
||||
paddingX: 1,
|
||||
paddingY: 1
|
||||
});
|
||||
};
|
||||
|
||||
$scope.setStepIndex = function(stepIndex) {
|
||||
// Close existing spotlight and signal timer.
|
||||
closeDomHighlight();
|
||||
stopSignalTimer();
|
||||
|
||||
// Check if there is a next step.
|
||||
if (!$scope.tour || stepIndex >= $scope.tour.steps.length) {
|
||||
$scope.step = null;
|
||||
$scope.hasNextStep = false;
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.step = $scope.tour.steps[stepIndex];
|
||||
$scope.stepIndex = stepIndex;
|
||||
$scope.hasNextStep = stepIndex < $scope.tour.steps.length - 1;
|
||||
|
||||
// Need the timeout here to ensure the click event does not
|
||||
// hide the spotlight.
|
||||
setTimeout(function() {
|
||||
updateDomHighlight();
|
||||
}, 1);
|
||||
|
||||
// Start listening for signals to move the tour forward.
|
||||
if ($scope.step.signal) {
|
||||
startSignalTimer();
|
||||
}
|
||||
};
|
||||
|
||||
$scope.stop = function() {
|
||||
$scope.tour = null;
|
||||
};
|
||||
|
||||
$scope.next = function() {
|
||||
$scope.setStepIndex($scope.stepIndex + 1);
|
||||
};
|
||||
|
||||
$scope.$watch('tour', function(tour) {
|
||||
stopSignalTimer();
|
||||
$scope.setStepIndex(0);
|
||||
});
|
||||
}
|
||||
};
|
||||
return directiveDefinitionObject;
|
||||
})
|
||||
|
||||
.factory('AngularTourSignals', ['$location', function($location) {
|
||||
var signals = {};
|
||||
|
||||
// Signal: When the page location matches the given path.
|
||||
signals.matchesLocation = function(locationPath) {
|
||||
return function() {
|
||||
return $location.path() == locationPath;
|
||||
};
|
||||
};
|
||||
|
||||
// Signal: When an element is found in the page's DOM.
|
||||
signals.elementAvaliable = function(elementPath) {
|
||||
return function() {
|
||||
return $(elementPath).length > 0;
|
||||
};
|
||||
};
|
||||
|
||||
return signals;
|
||||
}]);
|
Reference in a new issue