sideshow 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.bowerrc +3 -0
- data/.csslintrc +37 -0
- data/.editorconfig +27 -0
- data/.gitattributes +1 -0
- data/.gitignore +23 -0
- data/BUILDING.md +4 -0
- data/CHANGELOG.md +47 -0
- data/Gulpfile.js +404 -0
- data/LICENSE +191 -0
- data/README.md +342 -0
- data/VERSION +1 -0
- data/bower.json +61 -0
- data/distr/dependencies/jazz.min.js +8 -0
- data/distr/dependencies/jquery.min.js +5 -0
- data/distr/dependencies/pagedown.min.js +1 -0
- data/distr/fonts/open-sans-family/opensans-bold.eot +0 -0
- data/distr/fonts/open-sans-family/opensans-bold.svg +1825 -0
- data/distr/fonts/open-sans-family/opensans-bold.ttf +0 -0
- data/distr/fonts/open-sans-family/opensans-bold.woff +0 -0
- data/distr/fonts/open-sans-family/opensans-bolditalic.eot +0 -0
- data/distr/fonts/open-sans-family/opensans-bolditalic.svg +1825 -0
- data/distr/fonts/open-sans-family/opensans-bolditalic.ttf +0 -0
- data/distr/fonts/open-sans-family/opensans-bolditalic.woff +0 -0
- data/distr/fonts/open-sans-family/opensans-extrabold.eot +0 -0
- data/distr/fonts/open-sans-family/opensans-extrabold.svg +1825 -0
- data/distr/fonts/open-sans-family/opensans-extrabold.ttf +0 -0
- data/distr/fonts/open-sans-family/opensans-extrabold.woff +0 -0
- data/distr/fonts/open-sans-family/opensans-extrabolditalic.eot +0 -0
- data/distr/fonts/open-sans-family/opensans-extrabolditalic.svg +1825 -0
- data/distr/fonts/open-sans-family/opensans-extrabolditalic.ttf +0 -0
- data/distr/fonts/open-sans-family/opensans-extrabolditalic.woff +0 -0
- data/distr/fonts/open-sans-family/opensans-italic.eot +0 -0
- data/distr/fonts/open-sans-family/opensans-italic.svg +1825 -0
- data/distr/fonts/open-sans-family/opensans-italic.ttf +0 -0
- data/distr/fonts/open-sans-family/opensans-italic.woff +0 -0
- data/distr/fonts/open-sans-family/opensans-light.eot +0 -0
- data/distr/fonts/open-sans-family/opensans-light.svg +1825 -0
- data/distr/fonts/open-sans-family/opensans-light.ttf +0 -0
- data/distr/fonts/open-sans-family/opensans-light.woff +0 -0
- data/distr/fonts/open-sans-family/opensans-lightitalic.eot +0 -0
- data/distr/fonts/open-sans-family/opensans-lightitalic.svg +1825 -0
- data/distr/fonts/open-sans-family/opensans-lightitalic.ttf +0 -0
- data/distr/fonts/open-sans-family/opensans-lightitalic.woff +0 -0
- data/distr/fonts/open-sans-family/opensans-regular.eot +0 -0
- data/distr/fonts/open-sans-family/opensans-regular.svg +1825 -0
- data/distr/fonts/open-sans-family/opensans-regular.ttf +0 -0
- data/distr/fonts/open-sans-family/opensans-regular.woff +0 -0
- data/distr/fonts/open-sans-family/opensans-semibold.eot +0 -0
- data/distr/fonts/open-sans-family/opensans-semibold.svg +1825 -0
- data/distr/fonts/open-sans-family/opensans-semibold.ttf +0 -0
- data/distr/fonts/open-sans-family/opensans-semibold.woff +0 -0
- data/distr/fonts/open-sans-family/opensans-semibolditalic.eot +0 -0
- data/distr/fonts/open-sans-family/opensans-semibolditalic.svg +1825 -0
- data/distr/fonts/open-sans-family/opensans-semibolditalic.ttf +0 -0
- data/distr/fonts/open-sans-family/opensans-semibolditalic.woff +0 -0
- data/distr/fonts/sideshow-fontface.min.css +1 -0
- data/distr/fonts/sideshow-icons/sideshow-icons.eot +0 -0
- data/distr/fonts/sideshow-icons/sideshow-icons.svg +16 -0
- data/distr/fonts/sideshow-icons/sideshow-icons.ttf +0 -0
- data/distr/fonts/sideshow-icons/sideshow-icons.woff +0 -0
- data/distr/sideshow.js +2510 -0
- data/distr/sideshow.min.js +10 -0
- data/distr/stylesheets/sideshow.min.css +1 -0
- data/docs/api.js +29 -0
- data/docs/assets/css/external-small.png +0 -0
- data/docs/assets/css/logo.png +0 -0
- data/docs/assets/css/main.css +783 -0
- data/docs/assets/favicon.png +0 -0
- data/docs/assets/img/spinner.gif +0 -0
- data/docs/assets/index.html +10 -0
- data/docs/assets/js/api-filter.js +52 -0
- data/docs/assets/js/api-list.js +251 -0
- data/docs/assets/js/api-search.js +98 -0
- data/docs/assets/js/apidocs.js +370 -0
- data/docs/assets/js/yui-prettify.js +17 -0
- data/docs/assets/vendor/prettify/CHANGES.html +130 -0
- data/docs/assets/vendor/prettify/COPYING +202 -0
- data/docs/assets/vendor/prettify/README.html +203 -0
- data/docs/assets/vendor/prettify/prettify-min.css +1 -0
- data/docs/assets/vendor/prettify/prettify-min.js +1 -0
- data/docs/classes/Arrow.html +541 -0
- data/docs/classes/Arrows.html +805 -0
- data/docs/classes/ControlVariables.html +1005 -0
- data/docs/classes/DetailsPanel.html +672 -0
- data/docs/classes/FadableItem.html +613 -0
- data/docs/classes/HidableItem.html +495 -0
- data/docs/classes/Mask.CloseButton.html +706 -0
- data/docs/classes/Mask.CompositeMask.html +721 -0
- data/docs/classes/Mask.CornerPart.html +613 -0
- data/docs/classes/Mask.Part.html +395 -0
- data/docs/classes/Mask.Polling.html +809 -0
- data/docs/classes/Mask.Subject.html +199 -0
- data/docs/classes/Mask.SubjectMask.html +417 -0
- data/docs/classes/Mask.WizardMenu.html +1401 -0
- data/docs/classes/SS.html +267 -0
- data/docs/classes/SSException.html +203 -0
- data/docs/classes/Screen.html +363 -0
- data/docs/classes/StepDescription.html +1025 -0
- data/docs/classes/StepDescriptionNextButton.html +746 -0
- data/docs/classes/VisualItem.html +339 -0
- data/docs/classes/Wizard.html +967 -0
- data/docs/files/c +0 -0
- data/docs/index.html +162 -0
- data/example.html +81 -0
- data/examples/images/clemenza.jpg +0 -0
- data/examples/images/doc_brown.png +0 -0
- data/examples/images/forkme.png +0 -0
- data/examples/images/fortes-logo.png +0 -0
- data/examples/images/sideshow-logo.png +0 -0
- data/examples/images/sideshow-logo.svg +155 -0
- data/examples/scripts/sideshow.config.js +2 -0
- data/examples/scripts/tutorials/introducing_sideshow.js +259 -0
- data/examples/stylesheets/example.min.css +1 -0
- data/examples/stylesheets/styl/example.styl +272 -0
- data/gulp/config.js +0 -0
- data/gulp/extensions/gulp-html-extend.js +151 -0
- data/gulp/tasks/.gitkeep +0 -0
- data/icons/iconfont.zip +0 -0
- data/package.json +56 -0
- data/sideshow.gemspec +20 -0
- data/sideshow.nuspec +72 -0
- data/sideshow.sublime-project +22 -0
- data/src/copyright_info.js +8 -0
- data/src/general/config.js +42 -0
- data/src/general/dictionary.js +42 -0
- data/src/general/exception.js +15 -0
- data/src/general/global_object.js +287 -0
- data/src/general/polling.js +151 -0
- data/src/general/screen.js +39 -0
- data/src/general/utility_functions.js +88 -0
- data/src/general/variables.js +42 -0
- data/src/interface_itens/fadable_item.js +55 -0
- data/src/interface_itens/hidable_item.js +32 -0
- data/src/interface_itens/visual_item.js +42 -0
- data/src/main.js +52 -0
- data/src/mask/composite_mask.js +193 -0
- data/src/mask/composite_mask_corner_part.js +105 -0
- data/src/mask/composite_mask_part.js +51 -0
- data/src/mask/mask.js +6 -0
- data/src/mask/subject_mask.js +34 -0
- data/src/step/arrow.js +88 -0
- data/src/step/arrows.js +155 -0
- data/src/step/step_description.js +165 -0
- data/src/step/step_description_next_button.js +55 -0
- data/src/step/step_details_panel.js +87 -0
- data/src/step/subject.js +100 -0
- data/src/wizard/wizard.js +395 -0
- data/src/wizard/wizard_control_variables.js +95 -0
- data/src/wizard/wizard_menu.js +101 -0
- data/stylesheets/_animations.styl +87 -0
- data/stylesheets/_font-face.styl +135 -0
- data/stylesheets/_icons.styl +27 -0
- data/stylesheets/_layout.styl +362 -0
- data/stylesheets/_mixins.styl +52 -0
- data/stylesheets/_variables.styl +35 -0
- data/stylesheets/sideshow-fontface.styl +4 -0
- data/stylesheets/sideshow.styl +7 -0
- data/yuidoc.json +15 -0
- metadata +246 -0
@@ -0,0 +1,87 @@
|
|
1
|
+
/**
|
2
|
+
The panel that holds step description, is positionated over the biggest remaining space among the four parts of a composite mask
|
3
|
+
|
4
|
+
@class DetailsPanel
|
5
|
+
@@singleton
|
6
|
+
@extends FadableItem
|
7
|
+
**/
|
8
|
+
var DetailsPanel = jazz.Class().extending(FadableItem).singleton;
|
9
|
+
|
10
|
+
/**
|
11
|
+
An object holding dimension information for the Details Panel
|
12
|
+
|
13
|
+
@@field dimension
|
14
|
+
@type Object
|
15
|
+
**/
|
16
|
+
DetailsPanel.field("dimension", {});
|
17
|
+
|
18
|
+
/**
|
19
|
+
An object holding positioning information for the Details Panel
|
20
|
+
|
21
|
+
@@field position
|
22
|
+
@type Object
|
23
|
+
**/
|
24
|
+
DetailsPanel.field("position", {});
|
25
|
+
|
26
|
+
/**
|
27
|
+
Renders the Details Panel
|
28
|
+
|
29
|
+
@method render
|
30
|
+
**/
|
31
|
+
DetailsPanel.method("render", function() {
|
32
|
+
this.$el = $("<div>")
|
33
|
+
.addClass("sideshow-details-panel")
|
34
|
+
.addClass("sideshow-hidden");
|
35
|
+
this.callSuper("render");
|
36
|
+
});
|
37
|
+
|
38
|
+
/**
|
39
|
+
Positionates the panel automatically, calculating the biggest available area and putting the panel over there
|
40
|
+
|
41
|
+
@method positionate
|
42
|
+
**/
|
43
|
+
DetailsPanel.method("positionate", function() {
|
44
|
+
var parts = Mask.CompositeMask.singleInstance.parts;
|
45
|
+
|
46
|
+
//Considering the four parts surrounding the current subject, gets the biggest one
|
47
|
+
var sortedSides = [
|
48
|
+
[parts.top, "height"],
|
49
|
+
[parts.right, "width"],
|
50
|
+
[parts.bottom, "height"],
|
51
|
+
[parts.left, "width"]
|
52
|
+
].sort(function(a, b) {
|
53
|
+
return a[0].dimension[a[1]] - b[0].dimension[b[1]];
|
54
|
+
});
|
55
|
+
|
56
|
+
var biggestSide = sortedSides.slice(-1)[0];
|
57
|
+
|
58
|
+
for(var i = 2; i > 0; i--){
|
59
|
+
var side = sortedSides[i];
|
60
|
+
var dimension = side[0].dimension;
|
61
|
+
if(dimension.width > 250 && dimension.height > 250){
|
62
|
+
if((dimension.width + dimension.height) > ((biggestSide[0].dimension.width + biggestSide[0].dimension.height) * 2))
|
63
|
+
biggestSide = side;
|
64
|
+
}
|
65
|
+
}
|
66
|
+
|
67
|
+
if (biggestSide[1] == "width") {
|
68
|
+
this.$el
|
69
|
+
.css("left", biggestSide[0].position.x).css("top", 0)
|
70
|
+
.css("height", Screen.dimension.height).css("width", biggestSide[0].dimension.width);
|
71
|
+
} else {
|
72
|
+
this.$el
|
73
|
+
.css("left", 0).css("top", biggestSide[0].position.y)
|
74
|
+
.css("height", biggestSide[0].dimension.height).css("width", Screen.dimension.width);
|
75
|
+
}
|
76
|
+
|
77
|
+
this.dimension = {
|
78
|
+
width: parsePxValue(this.$el.css("width")),
|
79
|
+
height: parsePxValue(this.$el.css("height"))
|
80
|
+
};
|
81
|
+
|
82
|
+
this.position = {
|
83
|
+
x: parsePxValue(this.$el.css("left")),
|
84
|
+
y: parsePxValue(this.$el.css("top"))
|
85
|
+
};
|
86
|
+
});
|
87
|
+
|
data/src/step/subject.js
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
/**
|
2
|
+
The current subject (the object being shown by the current wizard)
|
3
|
+
|
4
|
+
@class Subject
|
5
|
+
@static
|
6
|
+
**/
|
7
|
+
var Subject = {};
|
8
|
+
|
9
|
+
/**
|
10
|
+
The current subject jQuery wrapped DOM element
|
11
|
+
|
12
|
+
@@field obj
|
13
|
+
@static
|
14
|
+
@type Object
|
15
|
+
**/
|
16
|
+
Subject.obj = null;
|
17
|
+
|
18
|
+
/**
|
19
|
+
The current subject dimension information
|
20
|
+
|
21
|
+
@@field position
|
22
|
+
@static
|
23
|
+
@type Object
|
24
|
+
**/
|
25
|
+
Subject.dimension = {};
|
26
|
+
|
27
|
+
/**
|
28
|
+
The current subject positioning information
|
29
|
+
|
30
|
+
@@field position
|
31
|
+
@static
|
32
|
+
@type Object
|
33
|
+
**/
|
34
|
+
Subject.position = {};
|
35
|
+
|
36
|
+
/**
|
37
|
+
The current subject border radius information
|
38
|
+
|
39
|
+
@@field borderRadius
|
40
|
+
@static
|
41
|
+
@type Object
|
42
|
+
**/
|
43
|
+
Subject.borderRadius = {};
|
44
|
+
|
45
|
+
/**
|
46
|
+
Checks if the object has changed since the last checking
|
47
|
+
|
48
|
+
@method hasChanged
|
49
|
+
@return boolean
|
50
|
+
**/
|
51
|
+
Subject.hasChanged = function() {
|
52
|
+
if (!this.obj) return false;
|
53
|
+
|
54
|
+
return (this.obj.offset().left - $window.scrollLeft() !== this.position.x) ||
|
55
|
+
(this.obj.offset().top - $window.scrollTop() !== this.position.y) ||
|
56
|
+
(this.obj.outerWidth() !== this.dimension.width) ||
|
57
|
+
(this.obj.outerHeight() !== this.dimension.height) ||
|
58
|
+
(parsePxValue(this.obj.css("border-top-left-radius")) !== this.borderRadius.leftTop) ||
|
59
|
+
(parsePxValue(this.obj.css("border-top-right-radius")) !== this.borderRadius.rightTop) ||
|
60
|
+
(parsePxValue(this.obj.css("border-bottom-left-radius")) !== this.borderRadius.leftBottom) ||
|
61
|
+
(parsePxValue(this.obj.css("border-bottom-right-radius")) !== this.borderRadius.rightBottom) ||
|
62
|
+
Screen.hasChanged();
|
63
|
+
};
|
64
|
+
|
65
|
+
/**
|
66
|
+
Updates the information about the suject
|
67
|
+
|
68
|
+
@method updateInfo
|
69
|
+
@param {Object} config Dimension, positioning and border radius information
|
70
|
+
**/
|
71
|
+
Subject.updateInfo = function(config) {
|
72
|
+
if (config === undefined) {
|
73
|
+
this.position.x = this.obj.offset().left - $window.scrollLeft();
|
74
|
+
this.position.y = this.obj.offset().top - $window.scrollTop();
|
75
|
+
this.dimension.width = this.obj.outerWidth();
|
76
|
+
this.dimension.height = this.obj.outerHeight();
|
77
|
+
this.borderRadius.leftTop = parsePxValue(this.obj.css("border-top-left-radius"));
|
78
|
+
this.borderRadius.rightTop = parsePxValue(this.obj.css("border-top-right-radius"));
|
79
|
+
this.borderRadius.leftBottom = parsePxValue(this.obj.css("border-bottom-left-radius"));
|
80
|
+
this.borderRadius.rightBottom = parsePxValue(this.obj.css("border-bottom-right-radius"));
|
81
|
+
} else {
|
82
|
+
this.position.x = config.position.x;
|
83
|
+
this.position.y = config.position.y;
|
84
|
+
this.dimension.width = config.dimension.width;
|
85
|
+
this.dimension.height = config.dimension.height;
|
86
|
+
this.borderRadius.leftTop = config.borderRadius.leftTop;
|
87
|
+
this.borderRadius.rightTop = config.borderRadius.rightTop;
|
88
|
+
this.borderRadius.leftBottom = config.borderRadius.leftBottom;
|
89
|
+
this.borderRadius.rightBottom = config.borderRadius.rightBottom;
|
90
|
+
}
|
91
|
+
|
92
|
+
Screen.updateInfo();
|
93
|
+
};
|
94
|
+
|
95
|
+
Subject.isSubjectVisible = function(position, dimension){
|
96
|
+
if((position.y + dimension.height) > $window.height() || position.y < 0){
|
97
|
+
return false;
|
98
|
+
}
|
99
|
+
return true;
|
100
|
+
};
|
@@ -0,0 +1,395 @@
|
|
1
|
+
/**
|
2
|
+
Represents a tutorial
|
3
|
+
|
4
|
+
@class Wizard
|
5
|
+
@@initializer
|
6
|
+
@param {Object} wizardConfig The wizard configuration object
|
7
|
+
**/
|
8
|
+
var Wizard = jazz.Class(function(wizardConfig) {
|
9
|
+
this.name = wizardConfig.name;
|
10
|
+
this.title = wizardConfig.title;
|
11
|
+
this.description = wizardConfig.description;
|
12
|
+
this.estimatedTime = wizardConfig.estimatedTime;
|
13
|
+
this.affects = wizardConfig.affects;
|
14
|
+
this.preparation = wizardConfig.preparation;
|
15
|
+
this.listeners = wizardConfig.listeners;
|
16
|
+
this.showStepPosition = wizardConfig.showStepPosition;
|
17
|
+
this.relatedWizards = wizardConfig.relatedWizards;
|
18
|
+
});
|
19
|
+
|
20
|
+
/**
|
21
|
+
A function to prepare the environment for running a wizard (e.g. redirecting to some screen)
|
22
|
+
|
23
|
+
@@field preparation
|
24
|
+
@type Function
|
25
|
+
**/
|
26
|
+
Wizard.field("preparation");
|
27
|
+
|
28
|
+
/**
|
29
|
+
An object with listeners to this wizard (e.g. beforeWizardStarts, afterWizardEnds)
|
30
|
+
|
31
|
+
@@field listeners
|
32
|
+
@type Object
|
33
|
+
**/
|
34
|
+
Wizard.field("listeners");
|
35
|
+
|
36
|
+
/**
|
37
|
+
A configuration flag that defines if the step position (e.g. 2/10, 3/15, 12/12) will be shown
|
38
|
+
|
39
|
+
@@field showStepPosition
|
40
|
+
@type boolean
|
41
|
+
**/
|
42
|
+
Wizard.field("showStepPosition");
|
43
|
+
|
44
|
+
/**
|
45
|
+
An array with related wizards names. These wizards are listed after the ending of the current wizard.
|
46
|
+
|
47
|
+
@@field relatedWizards
|
48
|
+
@type Array
|
49
|
+
**/
|
50
|
+
Wizard.field("relatedWizards");
|
51
|
+
|
52
|
+
/**
|
53
|
+
The wizard unique name (used internally as an identifier)
|
54
|
+
|
55
|
+
@@field name
|
56
|
+
@type String
|
57
|
+
**/
|
58
|
+
Wizard.field("name");
|
59
|
+
|
60
|
+
/**
|
61
|
+
The wizard title (will be shown in the list of available wizards)
|
62
|
+
|
63
|
+
@@field title
|
64
|
+
@type String
|
65
|
+
**/
|
66
|
+
Wizard.field("title");
|
67
|
+
|
68
|
+
/**
|
69
|
+
The wizard description (will be shown in the list of available wizards)
|
70
|
+
|
71
|
+
@@field description
|
72
|
+
@type String
|
73
|
+
**/
|
74
|
+
Wizard.field("description");
|
75
|
+
|
76
|
+
/**
|
77
|
+
The wizard estimated completion time (will be shown in the list of available wizards)
|
78
|
+
|
79
|
+
@@field estimatedTime
|
80
|
+
@type String
|
81
|
+
**/
|
82
|
+
Wizard.field("estimatedTime");
|
83
|
+
|
84
|
+
/**
|
85
|
+
A collection of rules to infer whether a wizard should be available in a specific screen
|
86
|
+
|
87
|
+
@@field affects
|
88
|
+
@type Array
|
89
|
+
**/
|
90
|
+
Wizard.field("affects");
|
91
|
+
|
92
|
+
/**
|
93
|
+
The sequence of steps for this wizard
|
94
|
+
|
95
|
+
@@field storyline
|
96
|
+
@private
|
97
|
+
@type Object
|
98
|
+
**/
|
99
|
+
Wizard.field("_storyline");
|
100
|
+
|
101
|
+
/**
|
102
|
+
Points to the current step object in a playing wizard
|
103
|
+
|
104
|
+
@@field currentStep
|
105
|
+
@type Object
|
106
|
+
**/
|
107
|
+
Wizard.field("currentStep");
|
108
|
+
|
109
|
+
/**
|
110
|
+
Sets the storyline for the wizard
|
111
|
+
|
112
|
+
@method storyLine
|
113
|
+
**/
|
114
|
+
Wizard.method("storyLine", function(storyline) {
|
115
|
+
this._storyline = storyline;
|
116
|
+
});
|
117
|
+
|
118
|
+
/**
|
119
|
+
Runs the wizard
|
120
|
+
|
121
|
+
@method play
|
122
|
+
**/
|
123
|
+
Wizard.method("play", function() {
|
124
|
+
var wiz = this;
|
125
|
+
|
126
|
+
Polling.enqueue("check_composite_mask_subject_changes", function() {
|
127
|
+
Mask.CompositeMask.singleInstance.pollForSubjectChanges();
|
128
|
+
});
|
129
|
+
|
130
|
+
Polling.enqueue("check_arrow_changes", function() {
|
131
|
+
Arrows.pollForArrowsChanges(true);
|
132
|
+
});
|
133
|
+
|
134
|
+
//Checks if the wizard has a storyline
|
135
|
+
if (!this._storyline) throw new SSException("201", "A wizard needs to have a storyline.");
|
136
|
+
var steps = this._storyline.steps;
|
137
|
+
|
138
|
+
//Checks if the storyline has at least one step
|
139
|
+
if (steps.length === 0) throw new SSException("202", "A storyline must have at least one step.");
|
140
|
+
|
141
|
+
DetailsPanel.singleInstance.render();
|
142
|
+
|
143
|
+
StepDescription.singleInstance.render();
|
144
|
+
|
145
|
+
var listeners = this.listeners;
|
146
|
+
if (listeners && listeners.beforeWizardStarts) listeners.beforeWizardStarts();
|
147
|
+
|
148
|
+
flags.changingStep = true;
|
149
|
+
this.showStep(steps[0], function() {
|
150
|
+
//Releases the polling for checking any changes in the current subject
|
151
|
+
//flags.lockMaskUpdate = false;
|
152
|
+
|
153
|
+
//Register the function that checks the completing of a step in the polling queue
|
154
|
+
Polling.enqueue("check_completed_step", function() {
|
155
|
+
wiz.pollForCheckCompletedStep();
|
156
|
+
});
|
157
|
+
});
|
158
|
+
|
159
|
+
Mask.CompositeMask.singleInstance.fadeIn();
|
160
|
+
});
|
161
|
+
|
162
|
+
/**
|
163
|
+
Shows a specific step
|
164
|
+
|
165
|
+
@method showStep
|
166
|
+
@param {Object} step The step to be shown
|
167
|
+
@param {Function} callback A callback function to be called
|
168
|
+
**/
|
169
|
+
Wizard.method("showStep", function(step, callback) {
|
170
|
+
var wizard = this;
|
171
|
+
flags.skippingStep = false;
|
172
|
+
|
173
|
+
Arrows.clear();
|
174
|
+
|
175
|
+
if (this.currentStep && this.currentStep.listeners && this.currentStep.listeners.afterStep)
|
176
|
+
this.currentStep.listeners.afterStep();
|
177
|
+
|
178
|
+
function skipStep(wiz) {
|
179
|
+
flags.skippingStep = true;
|
180
|
+
wizard.next();
|
181
|
+
}
|
182
|
+
|
183
|
+
if (step && step.listeners && step.listeners.beforeStep)
|
184
|
+
step.listeners.beforeStep();
|
185
|
+
|
186
|
+
//The shown step is, of course, the current
|
187
|
+
this.currentStep = step;
|
188
|
+
|
189
|
+
//If the step has a skipIf evaluator and it evaluates to true, we'll skip to the next step!
|
190
|
+
if (step.skipIf && step.skipIf())
|
191
|
+
skipStep(this);
|
192
|
+
|
193
|
+
if (flags.changingStep && !flags.skippingStep) {
|
194
|
+
//Sets the current subject and updates its dimension and position
|
195
|
+
if (step.subject)
|
196
|
+
SS.setSubject(step.subject);
|
197
|
+
else
|
198
|
+
SS.setEmptySubject();
|
199
|
+
//Updates the mask
|
200
|
+
Mask.CompositeMask.singleInstance.update(Subject.position, Subject.dimension, Subject.borderRadius);
|
201
|
+
|
202
|
+
var sm = Mask.SubjectMask.singleInstance;
|
203
|
+
sm.fadeOut(function() {
|
204
|
+
if (step.lockSubject) sm.show(true);
|
205
|
+
});
|
206
|
+
//The details panel (that wraps the step description and arrow) is shown
|
207
|
+
DetailsPanel.singleInstance.show();
|
208
|
+
//Repositionate the details panel depending on the remaining space in the screen
|
209
|
+
DetailsPanel.singleInstance.positionate();
|
210
|
+
//Sets the description properties (text, title and step position)
|
211
|
+
var description = StepDescription.singleInstance;
|
212
|
+
var text = step.text;
|
213
|
+
text = text instanceof Function ? SS.heredoc(text) : text;
|
214
|
+
if (step.format == "markdown") {
|
215
|
+
description.setHTML(new markdown.Converter().makeHtml(text));
|
216
|
+
} else
|
217
|
+
description.setText(text);
|
218
|
+
|
219
|
+
description.setTitle(step.title);
|
220
|
+
description.setStepPosition((this.getStepPosition() + 1) + "/" + this._storyline.steps.length);
|
221
|
+
//If this step doesn't have its own passing conditions/evaluators, or the flag "showNextButton" is true, then, the button is visible
|
222
|
+
if (step.showNextButton || step.autoContinue === false || !(step.completingConditions && step.completingConditions.length > 0)) {
|
223
|
+
var nextStep = this._storyline.steps[this.getStepPosition() + 1];
|
224
|
+
if (nextStep) {
|
225
|
+
description.nextButton.setText(getString(strings.next) + ": " + this._storyline.steps[this.getStepPosition() + 1].title);
|
226
|
+
} else {
|
227
|
+
description.nextButton.setText(getString(strings.finishWizard));
|
228
|
+
}
|
229
|
+
description.nextButton.show();
|
230
|
+
|
231
|
+
if (step.autoContinue === false) description.nextButton.disable();
|
232
|
+
} else {
|
233
|
+
description.nextButton.hide();
|
234
|
+
}
|
235
|
+
|
236
|
+
if (step.targets && step.targets.length > 0) {
|
237
|
+
Arrows.setTargets(step.targets);
|
238
|
+
Arrows.render();
|
239
|
+
Arrows.positionate();
|
240
|
+
Arrows.fadeIn();
|
241
|
+
}
|
242
|
+
|
243
|
+
//Step Description is shown, but is transparent yet (since we need to know its dimension to positionate it properly)
|
244
|
+
description.show(true);
|
245
|
+
if(!Mask.CompositeMask.singleInstance.scrollIfNecessary(Subject.position, Subject.dimension)){
|
246
|
+
description.positionate();
|
247
|
+
//Do a simple fade in for the description box
|
248
|
+
description.fadeIn();
|
249
|
+
}
|
250
|
+
|
251
|
+
|
252
|
+
//If a callback is passed, call it
|
253
|
+
if (callback) callback();
|
254
|
+
flags.changingStep = false;
|
255
|
+
}
|
256
|
+
});
|
257
|
+
|
258
|
+
/**
|
259
|
+
Shows the next step of the wizard
|
260
|
+
|
261
|
+
@method next
|
262
|
+
@param {Function} callback A callback function to be called
|
263
|
+
**/
|
264
|
+
Wizard.method("next", function(callback, nextStep) {
|
265
|
+
if (!flags.changingStep || flags.skippingStep) {
|
266
|
+
flags.changingStep = true;
|
267
|
+
var currentStep = this.currentStep;
|
268
|
+
nextStep = nextStep || this._storyline.steps[this.getStepPosition(this.currentStep) + 1];
|
269
|
+
var self = this;
|
270
|
+
|
271
|
+
this.hideStep(function() {
|
272
|
+
if (nextStep) self.showStep(nextStep, function() {
|
273
|
+
if (callback) callback();
|
274
|
+
});
|
275
|
+
else {
|
276
|
+
if (currentStep && currentStep.listeners && currentStep.listeners.afterStep)
|
277
|
+
currentStep.listeners.afterStep();
|
278
|
+
|
279
|
+
var completedWizard = currentWizard;
|
280
|
+
currentWizard = null;
|
281
|
+
var listeners = self.listeners;
|
282
|
+
if (listeners && listeners.afterWizardEnds) listeners.afterWizardEnds();
|
283
|
+
|
284
|
+
if (!SS.showRelatedWizardsList(completedWizard)) SS.close();
|
285
|
+
}
|
286
|
+
});
|
287
|
+
}
|
288
|
+
});
|
289
|
+
|
290
|
+
/**
|
291
|
+
Hides the step
|
292
|
+
|
293
|
+
@method hideStep
|
294
|
+
@param {Function} callback A callback function to be called in the ending of the hiding process
|
295
|
+
**/
|
296
|
+
Wizard.method("hideStep", function(callback) {
|
297
|
+
StepDescription.singleInstance.fadeOut(function() {
|
298
|
+
DetailsPanel.singleInstance.hide();
|
299
|
+
});
|
300
|
+
Arrows.fadeOut();
|
301
|
+
Mask.SubjectMask.singleInstance.update(Subject.position, Subject.dimension, Subject.borderRadius);
|
302
|
+
Mask.SubjectMask.singleInstance.fadeIn(callback);
|
303
|
+
});
|
304
|
+
|
305
|
+
/**
|
306
|
+
Returns the position of the step passed as argument or (by default) the current step
|
307
|
+
|
308
|
+
@method getStepPosition
|
309
|
+
@param {Object} step The step object to get position
|
310
|
+
**/
|
311
|
+
Wizard.method("getStepPosition", function(step) {
|
312
|
+
return this._storyline.steps.indexOf(step || this.currentStep);
|
313
|
+
});
|
314
|
+
|
315
|
+
/**
|
316
|
+
Checks if a wizard should be shown in the current context (running each evaluator defined for this wizard)
|
317
|
+
|
318
|
+
@method isEligible
|
319
|
+
@return {boolean} A boolean indicating if this wizard should be available in the current context
|
320
|
+
**/
|
321
|
+
Wizard.method("isEligible", function() {
|
322
|
+
var l = global.location;
|
323
|
+
|
324
|
+
function isEqual(a, b, caseSensitive) {
|
325
|
+
return (caseSensitive) ? a === b : a.toLowerCase() === b.toLowerCase();
|
326
|
+
}
|
327
|
+
|
328
|
+
for (var c = 0; c < this.affects.length; c++) {
|
329
|
+
var condition = this.affects[c];
|
330
|
+
if (condition instanceof Function) {
|
331
|
+
if (condition()) return true;
|
332
|
+
} else if (condition instanceof Object) {
|
333
|
+
if ("route" in condition) {
|
334
|
+
var route = l.pathname + l.search + l.hash;
|
335
|
+
if (isEqual(route, condition.route, condition.caseSensitive)) return true;
|
336
|
+
}
|
337
|
+
|
338
|
+
if ("hash" in condition) {
|
339
|
+
if (isEqual(location.hash, condition.hash, condition.caseSensitive)) return true;
|
340
|
+
}
|
341
|
+
|
342
|
+
if ("url" in condition) {
|
343
|
+
if (isEqual(location.href, condition.url, condition.caseSensitive)) return true;
|
344
|
+
}
|
345
|
+
}
|
346
|
+
}
|
347
|
+
return false;
|
348
|
+
});
|
349
|
+
|
350
|
+
/**
|
351
|
+
Checks if the current user already watched this wizard
|
352
|
+
|
353
|
+
@method isAlreadyWatched
|
354
|
+
@return {boolean} A boolean indicating if the user watched this wizard
|
355
|
+
@@todo Implement this method...
|
356
|
+
**/
|
357
|
+
Wizard.method("isAlreadyWatched", function() {
|
358
|
+
//ToDo
|
359
|
+
return false;
|
360
|
+
});
|
361
|
+
|
362
|
+
/**
|
363
|
+
A Polling function to check if the current step is completed
|
364
|
+
|
365
|
+
@method pollForCheckCompletedStep
|
366
|
+
**/
|
367
|
+
Wizard.method("pollForCheckCompletedStep", function() {
|
368
|
+
var conditions = this.currentStep.completingConditions;
|
369
|
+
if (conditions && conditions.length > 0 && !flags.skippingStep) {
|
370
|
+
var completed = true;
|
371
|
+
for (var fn = 0; fn < conditions.length; fn++) {
|
372
|
+
var completingCondition = conditions[fn];
|
373
|
+
if (!completingCondition()) completed = false;
|
374
|
+
}
|
375
|
+
|
376
|
+
if (completed) {
|
377
|
+
if (this.currentStep.autoContinue === false) StepDescription.singleInstance.nextButton.enable();
|
378
|
+
else currentWizard.next();
|
379
|
+
}
|
380
|
+
}
|
381
|
+
});
|
382
|
+
|
383
|
+
|
384
|
+
Wizard.method("prepareAndPlay", function(){
|
385
|
+
currentWizard = this;
|
386
|
+
|
387
|
+
if (!this.isEligible()) {
|
388
|
+
if (this.preparation)
|
389
|
+
this.preparation(function() {
|
390
|
+
currentWizard.play();
|
391
|
+
});
|
392
|
+
else
|
393
|
+
throw new SSException("203", "This wizard is not eligible neither has a preparation function.");
|
394
|
+
} else this.play();
|
395
|
+
});
|
@@ -0,0 +1,95 @@
|
|
1
|
+
/**
|
2
|
+
Stores the variables used in step evaluators
|
3
|
+
|
4
|
+
@class ControlVariables
|
5
|
+
@static
|
6
|
+
**/
|
7
|
+
SS.ControlVariables = {};
|
8
|
+
|
9
|
+
/**
|
10
|
+
Sets a variable value
|
11
|
+
|
12
|
+
@method set
|
13
|
+
@param {String} name The variable name
|
14
|
+
@param {String} value The variable value
|
15
|
+
@return {String} A formatted key=value pair representing the defined variable
|
16
|
+
**/
|
17
|
+
SS.ControlVariables.set = function(name, value) {
|
18
|
+
var variable = {};
|
19
|
+
if (this.isDefined(name)) {
|
20
|
+
variable = this.getNameValuePair(name);
|
21
|
+
} else controlVariables.push(variable);
|
22
|
+
|
23
|
+
variable.name = name;
|
24
|
+
variable.value = value;
|
25
|
+
return name + "=" + value;
|
26
|
+
};
|
27
|
+
|
28
|
+
/**
|
29
|
+
Sets a variable if not defined yet
|
30
|
+
|
31
|
+
@method setIfUndefined
|
32
|
+
@param {String} name The variable name
|
33
|
+
@param {String} value The variable value
|
34
|
+
@return {String} A formatted key=value pair representing the defined variable
|
35
|
+
**/
|
36
|
+
SS.ControlVariables.setIfUndefined = function(name, value) {
|
37
|
+
if (!this.isDefined(name)) return this.set(name, value);
|
38
|
+
};
|
39
|
+
|
40
|
+
/**
|
41
|
+
Checks if some variable is already defined
|
42
|
+
|
43
|
+
@method isDefined
|
44
|
+
@param {String} name The variable name
|
45
|
+
@return {boolean} A boolean indicating if the variable is already defined
|
46
|
+
**/
|
47
|
+
SS.ControlVariables.isDefined = function(name) {
|
48
|
+
return this.getNameValuePair(name) !== undefined;
|
49
|
+
};
|
50
|
+
|
51
|
+
/**
|
52
|
+
Gets a variable value
|
53
|
+
|
54
|
+
@method get
|
55
|
+
@param {String} name The variable name
|
56
|
+
@return {any} The variable value
|
57
|
+
**/
|
58
|
+
SS.ControlVariables.get = function(name) {
|
59
|
+
var pair = this.getNameValuePair(name);
|
60
|
+
return pair ? pair.value : undefined;
|
61
|
+
};
|
62
|
+
|
63
|
+
/**
|
64
|
+
Gets a pair with name and value
|
65
|
+
|
66
|
+
@method getNameValuePair
|
67
|
+
@param {String} name The variable name
|
68
|
+
@return {Object} A pair with the variable name and value
|
69
|
+
**/
|
70
|
+
SS.ControlVariables.getNameValuePair = function(name) {
|
71
|
+
for (var i = 0; i < controlVariables.length; i++) {
|
72
|
+
var variable = controlVariables[i];
|
73
|
+
if (variable.name === name) return variable;
|
74
|
+
}
|
75
|
+
};
|
76
|
+
|
77
|
+
/**
|
78
|
+
Remove some variable from the control variables collection
|
79
|
+
|
80
|
+
@method remove
|
81
|
+
@param {String} name The variable name
|
82
|
+
@return {Object} A pair with the removed variable name and value
|
83
|
+
**/
|
84
|
+
SS.ControlVariables.remove = function(name) {
|
85
|
+
return controlVariables.splice(controlVariables.indexOf(this.getNameValuePair(name)), 1);
|
86
|
+
};
|
87
|
+
|
88
|
+
/**
|
89
|
+
Clear the control variables collection
|
90
|
+
|
91
|
+
@method clear
|
92
|
+
**/
|
93
|
+
SS.ControlVariables.clear = function() {
|
94
|
+
controlVariables = [];
|
95
|
+
};
|