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.
Files changed (160) hide show
  1. checksums.yaml +7 -0
  2. data/.bowerrc +3 -0
  3. data/.csslintrc +37 -0
  4. data/.editorconfig +27 -0
  5. data/.gitattributes +1 -0
  6. data/.gitignore +23 -0
  7. data/BUILDING.md +4 -0
  8. data/CHANGELOG.md +47 -0
  9. data/Gulpfile.js +404 -0
  10. data/LICENSE +191 -0
  11. data/README.md +342 -0
  12. data/VERSION +1 -0
  13. data/bower.json +61 -0
  14. data/distr/dependencies/jazz.min.js +8 -0
  15. data/distr/dependencies/jquery.min.js +5 -0
  16. data/distr/dependencies/pagedown.min.js +1 -0
  17. data/distr/fonts/open-sans-family/opensans-bold.eot +0 -0
  18. data/distr/fonts/open-sans-family/opensans-bold.svg +1825 -0
  19. data/distr/fonts/open-sans-family/opensans-bold.ttf +0 -0
  20. data/distr/fonts/open-sans-family/opensans-bold.woff +0 -0
  21. data/distr/fonts/open-sans-family/opensans-bolditalic.eot +0 -0
  22. data/distr/fonts/open-sans-family/opensans-bolditalic.svg +1825 -0
  23. data/distr/fonts/open-sans-family/opensans-bolditalic.ttf +0 -0
  24. data/distr/fonts/open-sans-family/opensans-bolditalic.woff +0 -0
  25. data/distr/fonts/open-sans-family/opensans-extrabold.eot +0 -0
  26. data/distr/fonts/open-sans-family/opensans-extrabold.svg +1825 -0
  27. data/distr/fonts/open-sans-family/opensans-extrabold.ttf +0 -0
  28. data/distr/fonts/open-sans-family/opensans-extrabold.woff +0 -0
  29. data/distr/fonts/open-sans-family/opensans-extrabolditalic.eot +0 -0
  30. data/distr/fonts/open-sans-family/opensans-extrabolditalic.svg +1825 -0
  31. data/distr/fonts/open-sans-family/opensans-extrabolditalic.ttf +0 -0
  32. data/distr/fonts/open-sans-family/opensans-extrabolditalic.woff +0 -0
  33. data/distr/fonts/open-sans-family/opensans-italic.eot +0 -0
  34. data/distr/fonts/open-sans-family/opensans-italic.svg +1825 -0
  35. data/distr/fonts/open-sans-family/opensans-italic.ttf +0 -0
  36. data/distr/fonts/open-sans-family/opensans-italic.woff +0 -0
  37. data/distr/fonts/open-sans-family/opensans-light.eot +0 -0
  38. data/distr/fonts/open-sans-family/opensans-light.svg +1825 -0
  39. data/distr/fonts/open-sans-family/opensans-light.ttf +0 -0
  40. data/distr/fonts/open-sans-family/opensans-light.woff +0 -0
  41. data/distr/fonts/open-sans-family/opensans-lightitalic.eot +0 -0
  42. data/distr/fonts/open-sans-family/opensans-lightitalic.svg +1825 -0
  43. data/distr/fonts/open-sans-family/opensans-lightitalic.ttf +0 -0
  44. data/distr/fonts/open-sans-family/opensans-lightitalic.woff +0 -0
  45. data/distr/fonts/open-sans-family/opensans-regular.eot +0 -0
  46. data/distr/fonts/open-sans-family/opensans-regular.svg +1825 -0
  47. data/distr/fonts/open-sans-family/opensans-regular.ttf +0 -0
  48. data/distr/fonts/open-sans-family/opensans-regular.woff +0 -0
  49. data/distr/fonts/open-sans-family/opensans-semibold.eot +0 -0
  50. data/distr/fonts/open-sans-family/opensans-semibold.svg +1825 -0
  51. data/distr/fonts/open-sans-family/opensans-semibold.ttf +0 -0
  52. data/distr/fonts/open-sans-family/opensans-semibold.woff +0 -0
  53. data/distr/fonts/open-sans-family/opensans-semibolditalic.eot +0 -0
  54. data/distr/fonts/open-sans-family/opensans-semibolditalic.svg +1825 -0
  55. data/distr/fonts/open-sans-family/opensans-semibolditalic.ttf +0 -0
  56. data/distr/fonts/open-sans-family/opensans-semibolditalic.woff +0 -0
  57. data/distr/fonts/sideshow-fontface.min.css +1 -0
  58. data/distr/fonts/sideshow-icons/sideshow-icons.eot +0 -0
  59. data/distr/fonts/sideshow-icons/sideshow-icons.svg +16 -0
  60. data/distr/fonts/sideshow-icons/sideshow-icons.ttf +0 -0
  61. data/distr/fonts/sideshow-icons/sideshow-icons.woff +0 -0
  62. data/distr/sideshow.js +2510 -0
  63. data/distr/sideshow.min.js +10 -0
  64. data/distr/stylesheets/sideshow.min.css +1 -0
  65. data/docs/api.js +29 -0
  66. data/docs/assets/css/external-small.png +0 -0
  67. data/docs/assets/css/logo.png +0 -0
  68. data/docs/assets/css/main.css +783 -0
  69. data/docs/assets/favicon.png +0 -0
  70. data/docs/assets/img/spinner.gif +0 -0
  71. data/docs/assets/index.html +10 -0
  72. data/docs/assets/js/api-filter.js +52 -0
  73. data/docs/assets/js/api-list.js +251 -0
  74. data/docs/assets/js/api-search.js +98 -0
  75. data/docs/assets/js/apidocs.js +370 -0
  76. data/docs/assets/js/yui-prettify.js +17 -0
  77. data/docs/assets/vendor/prettify/CHANGES.html +130 -0
  78. data/docs/assets/vendor/prettify/COPYING +202 -0
  79. data/docs/assets/vendor/prettify/README.html +203 -0
  80. data/docs/assets/vendor/prettify/prettify-min.css +1 -0
  81. data/docs/assets/vendor/prettify/prettify-min.js +1 -0
  82. data/docs/classes/Arrow.html +541 -0
  83. data/docs/classes/Arrows.html +805 -0
  84. data/docs/classes/ControlVariables.html +1005 -0
  85. data/docs/classes/DetailsPanel.html +672 -0
  86. data/docs/classes/FadableItem.html +613 -0
  87. data/docs/classes/HidableItem.html +495 -0
  88. data/docs/classes/Mask.CloseButton.html +706 -0
  89. data/docs/classes/Mask.CompositeMask.html +721 -0
  90. data/docs/classes/Mask.CornerPart.html +613 -0
  91. data/docs/classes/Mask.Part.html +395 -0
  92. data/docs/classes/Mask.Polling.html +809 -0
  93. data/docs/classes/Mask.Subject.html +199 -0
  94. data/docs/classes/Mask.SubjectMask.html +417 -0
  95. data/docs/classes/Mask.WizardMenu.html +1401 -0
  96. data/docs/classes/SS.html +267 -0
  97. data/docs/classes/SSException.html +203 -0
  98. data/docs/classes/Screen.html +363 -0
  99. data/docs/classes/StepDescription.html +1025 -0
  100. data/docs/classes/StepDescriptionNextButton.html +746 -0
  101. data/docs/classes/VisualItem.html +339 -0
  102. data/docs/classes/Wizard.html +967 -0
  103. data/docs/files/c +0 -0
  104. data/docs/index.html +162 -0
  105. data/example.html +81 -0
  106. data/examples/images/clemenza.jpg +0 -0
  107. data/examples/images/doc_brown.png +0 -0
  108. data/examples/images/forkme.png +0 -0
  109. data/examples/images/fortes-logo.png +0 -0
  110. data/examples/images/sideshow-logo.png +0 -0
  111. data/examples/images/sideshow-logo.svg +155 -0
  112. data/examples/scripts/sideshow.config.js +2 -0
  113. data/examples/scripts/tutorials/introducing_sideshow.js +259 -0
  114. data/examples/stylesheets/example.min.css +1 -0
  115. data/examples/stylesheets/styl/example.styl +272 -0
  116. data/gulp/config.js +0 -0
  117. data/gulp/extensions/gulp-html-extend.js +151 -0
  118. data/gulp/tasks/.gitkeep +0 -0
  119. data/icons/iconfont.zip +0 -0
  120. data/package.json +56 -0
  121. data/sideshow.gemspec +20 -0
  122. data/sideshow.nuspec +72 -0
  123. data/sideshow.sublime-project +22 -0
  124. data/src/copyright_info.js +8 -0
  125. data/src/general/config.js +42 -0
  126. data/src/general/dictionary.js +42 -0
  127. data/src/general/exception.js +15 -0
  128. data/src/general/global_object.js +287 -0
  129. data/src/general/polling.js +151 -0
  130. data/src/general/screen.js +39 -0
  131. data/src/general/utility_functions.js +88 -0
  132. data/src/general/variables.js +42 -0
  133. data/src/interface_itens/fadable_item.js +55 -0
  134. data/src/interface_itens/hidable_item.js +32 -0
  135. data/src/interface_itens/visual_item.js +42 -0
  136. data/src/main.js +52 -0
  137. data/src/mask/composite_mask.js +193 -0
  138. data/src/mask/composite_mask_corner_part.js +105 -0
  139. data/src/mask/composite_mask_part.js +51 -0
  140. data/src/mask/mask.js +6 -0
  141. data/src/mask/subject_mask.js +34 -0
  142. data/src/step/arrow.js +88 -0
  143. data/src/step/arrows.js +155 -0
  144. data/src/step/step_description.js +165 -0
  145. data/src/step/step_description_next_button.js +55 -0
  146. data/src/step/step_details_panel.js +87 -0
  147. data/src/step/subject.js +100 -0
  148. data/src/wizard/wizard.js +395 -0
  149. data/src/wizard/wizard_control_variables.js +95 -0
  150. data/src/wizard/wizard_menu.js +101 -0
  151. data/stylesheets/_animations.styl +87 -0
  152. data/stylesheets/_font-face.styl +135 -0
  153. data/stylesheets/_icons.styl +27 -0
  154. data/stylesheets/_layout.styl +362 -0
  155. data/stylesheets/_mixins.styl +52 -0
  156. data/stylesheets/_variables.styl +35 -0
  157. data/stylesheets/sideshow-fontface.styl +4 -0
  158. data/stylesheets/sideshow.styl +7 -0
  159. data/yuidoc.json +15 -0
  160. 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
+
@@ -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
+ };