Get the basic tutorial working completely, including reacting to server-side events

This commit is contained in:
Joseph Schorr 2014-02-06 20:58:26 -05:00
parent b7afc83204
commit fa1bf94af1
20 changed files with 431 additions and 99 deletions

View file

@ -32,21 +32,20 @@ angular.module("angular-tour", [])
'inline': '=inline',
},
controller: function($rootScope, $scope, $element, $location, $interval, AngularTour) {
var createNewScope = function() {
var tourScope = {
'_replaceData': function(s) {
if (typeof s != 'string') {
return s;
}
for (var key in tourScope) {
if (key[0] == '_') { continue; }
if (tourScope.hasOwnProperty(key)) {
s = s.replace('{{' + key + '}}', tourScope[key]);
}
}
var createNewScope = function(initialScope) {
var tourScope = jQuery.extend({}, initialScope || {});
tourScope['_replaceData'] = function(s) {
if (typeof s != 'string') {
return s;
}
for (var key in tourScope) {
if (key[0] == '_') { continue; }
if (tourScope.hasOwnProperty(key)) {
s = s.replace('{{' + key + '}}', tourScope[key]);
}
}
return s;
};
return tourScope;
@ -55,7 +54,7 @@ angular.module("angular-tour", [])
$scope.stepIndex = 0;
$scope.step = null;
$scope.interval = null;
$scope.tourScope = createNewScope();
$scope.tourScope = null;
var getElement = function() {
if (typeof $scope.step['element'] == 'function') {
@ -65,14 +64,35 @@ angular.module("angular-tour", [])
return $($scope.tourScope._replaceData($scope.step['element']));
};
var checkSignal = function() {
return $scope.step['signal'] && $scope.step['signal']($scope.tourScope);
};
var teardownSignal = function() {
if (!$scope.step) { return; }
var signal = $scope.step['signal'];
if (signal && signal.$teardown) {
signal.$teardown($scope.tourScope);
}
};
var setupSignal = function() {
if (!$scope.step) { return; }
var signal = $scope.step['signal'];
if (signal && signal.$setup) {
signal.$setup($scope.tourScope);
}
};
var checkSignalTimer = function() {
if (!$scope.step) {
if (!$scope.step || !$scope.tourScope) {
stopSignalTimer();
return;
}
var signal = $scope.step['signal'];
if (signal($scope.tourScope)) {
if (checkSignal()) {
$scope.next();
}
};
@ -116,6 +136,7 @@ angular.module("angular-tour", [])
$scope.setStepIndex = function(stepIndex) {
// Close existing spotlight and signal timer.
teardownSignal();
closeDomHighlight();
stopSignalTimer();
@ -129,7 +150,8 @@ angular.module("angular-tour", [])
$scope.step = $scope.tour.steps[stepIndex];
// If the signal is already true, then skip this step entirely.
if ($scope.step['signal'] && $scope.step['signal']($scope.tourScope)) {
setupSignal();
if (checkSignal()) {
$scope.setStepIndex(stepIndex + 1);
return;
}
@ -138,10 +160,11 @@ angular.module("angular-tour", [])
$scope.hasNextStep = stepIndex < $scope.tour.steps.length - 1;
// Need the timeout here to ensure the click event does not
// hide the spotlight.
// hide the spotlight, and it has to be longer than the hide
// spotlight animation timing.
setTimeout(function() {
updateDomHighlight();
}, 1);
}, 500);
// Start listening for signals to move the tour forward.
if ($scope.step.signal) {
@ -162,9 +185,15 @@ angular.module("angular-tour", [])
$scope.$watch('tour', function(tour) {
stopSignalTimer();
if (tour) {
// Set the tour scope.
if (tour.tourScope) {
$scope.tourScope = tour.tourScope;
} else {
$scope.tourScope = $scope.tour.tourScope = createNewScope(tour.initialScope);
}
// Set the initial step.
$scope.setStepIndex(tour.initialStep || 0);
$scope.tourScope = tour.tourScope || createNewScope();
$scope.tour.tourScope = $scope.tourScope;
}
});
@ -181,6 +210,9 @@ angular.module("angular-tour", [])
// Unbind the listener.
unbind();
// Teardown any existing signal listener.
teardownSignal();
// If there is an active tour, transition it over to the overlay.
if ($scope.tour && $scope.step && $scope.step['overlayable']) {
AngularTour.start($scope.tour, $scope.stepIndex, $scope.tourScope);
@ -212,5 +244,30 @@ angular.module("angular-tour", [])
};
};
// Signal: When a server-side event matches the predicate.
signals.serverEvent = function(url, matcher) {
var checker = function(tourScope) {
return checker.$message && matcher(checker.$message, tourScope);
};
checker.$message = null;
checker.$setup = function(tourScope) {
var fullUrl = tourScope._replaceData(url);
checker.$source = new EventSource(fullUrl);
checker.$source.onmessage = function(e) {
checker.$message = JSON.parse(e.data);
};
};
checker.$teardown = function() {
if (checker.$source) {
checker.$source.close();
}
};
return checker;
};
return signals;
}]);