/[suikacvs]/test/suikawebwww/www/js/jste/tutorial.js
Suika

Contents of /test/suikawebwww/www/js/jste/tutorial.js

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.4 - (hide annotations) (download) (as text)
Tue Jan 20 13:57:02 2009 UTC (17 years, 5 months ago) by wakaba
Branch: MAIN
Changes since 1.3: +12 -0 lines
File MIME type: application/javascript
Implemented VML version of border and pointer

1 wakaba 1.1
2     if (typeof (JSTE) === "undefined") var JSTE = {};
3    
4     JSTE.WATNS = 'http://suika.fam.cx/ns/wat';
5     JSTE.SpaceChars = /[\x09\x0A\x0C\x0D\x20]+/;
6    
7     JSTE.Class = function (constructor, prototype) {
8     return JSTE.Subclass (constructor, JSTE.EventTarget, prototype);
9     }; // Class
10    
11     JSTE.Class.addClassMethods = function (classObject, methods) {
12     new JSTE.Hash (methods).forEach (function (n, v) {
13     if (!classObject[n]) {
14     classObject[n] = v;
15     }
16     });
17     }; // addClassMethods
18    
19     JSTE.Subclass = function (constructor, superclass, prototype) {
20     constructor.prototype = new superclass;
21     for (var n in prototype) {
22     constructor.prototype[n] = prototype[n];
23     }
24     constructor.prototype.constructor = constructor;
25     constructor.prototype._super = superclass;
26     return constructor;
27     }; // Subclass
28    
29     JSTE.EventTarget = new JSTE.Subclass (function () {
30    
31     }, function () {}, {
32     addEventListener: function (eventType, handler, useCapture) {
33     if (useCapture) return;
34     if (!this.eventListeners) this.eventListeners = {};
35     if (!this.eventListeners[eventType]) {
36     this.eventListeners[eventType] = new JSTE.List;
37     }
38     this.eventListeners[eventType].push (handler);
39     }, // addEventListener
40     removeEventListener: function (eventType, handler, useCapture) {
41     if (useCapture) return;
42     if (!this.eventListeners) return;
43     if (!this.eventListeners[eventType]) return;
44     this.eventListeners[eventType].remove (handler);
45     }, // removeEventListener
46     dispatchEvent: function (e) {
47     if (!this.eventListeners) return;
48     var handlers = this.eventListeners[e.type];
49     if (!handlers) return;
50     e.currentTarget = this;
51     e.target = this;
52     var preventDefault;
53     handlers.forEach (function (handler) {
54     if (handler.apply (this, [e])) {
55     preventDefault = true;
56     }
57     });
58     return preventDefault || e.isDefaultPrevented ();
59     } // dispatchEvent
60     }); // EventTarget
61    
62     JSTE.Event = new JSTE.Class (function (eventType, canBubble, cancelable) {
63     this.type = eventType;
64     this.bubbles = canBubble;
65     this.cancelable = cancelable;
66     }, {
67     preventDefault: function () {
68     this.defaultPrevented = true;
69     }, // preventDefault
70     isDefaultPrevented: function () {
71     return this.defaultPrevented;
72     } // isDefaultPrevented
73     });
74    
75     JSTE.Observer = new JSTE.Class (function (eventType, target, onevent) {
76     this.eventType = eventType;
77     if (target.addEventListener) {
78     this.target = target;
79     this.code = onevent;
80     target.addEventListener (eventType, this.code, false);
81     } else if (target.attachEvent) {
82     this.code = function () {
83     onevent (event);
84     };
85     this.target = target;
86     target.attachEvent ("on" + eventType, this.code);
87     }
88     }, {
89     stop: function () {
90     if (this.target.removeEventListener) {
91     this.target.removeEventListener (this.eventType, this.code, false);
92     } else if (this.detachEvent) {
93     this.target.detachEvent ("on" + this.eventType, this.code);
94     }
95     } // stop
96     }); // Observer
97    
98     JSTE.List = new JSTE.Class (function (arrayLike) {
99     this.list = arrayLike || [];
100     }, {
101     getLast: function () {
102     if (this.list.length) {
103     return this.list[this.list.length - 1];
104     } else {
105     return null;
106     }
107     }, // getLast
108    
109     forEach: function (code) {
110     var length = this.list.length;
111     for (var i = 0; i < length; i++) {
112     var r = code (this.list[i]);
113     if (r && r.stop) return r.returnValue;
114     }
115     return null;
116     }, // forEach
117 wakaba 1.4
118     numberToInteger: function () {
119     var newList = [];
120     this.forEach (function (item) {
121     if (typeof item === "number") {
122     newList.push (Math.floor (item));
123     } else {
124     newList.push (item);
125     }
126     });
127     return new this.constructor (newList);
128     }, // numberToInteger
129 wakaba 1.1
130     clone: function () {
131     var newList = [];
132     this.forEach (function (item) {
133     newList.push (item);
134     });
135     return new this.constructor (newList);
136     }, // clone
137    
138     grep: function (code) {
139     var newList = [];
140     this.forEach (function (item) {
141     if (code (item)) {
142     newList.push (item);
143     }
144     });
145     return new this.constructor (newList);
146     }, // grep
147     onlyNonNull: function () {
148     return this.grep (function (item) {
149     return item != null; /* Intentionally "!=" */
150     });
151     }, // onlyNonNull
152    
153     getFirstMatch: function (code) {
154     return this.forEach (function (item) {
155     if (code (item)) {
156     return new JSTE.List.Return (item);
157     }
158     });
159     }, // getFirstMatch
160    
161     switchByElementType: function () {
162     var cases = new JSTE.List (arguments);
163     this.forEach (function (n) {
164     cases.forEach (function (c) {
165     if (c.namespaceURI == n.namespaceURI) {
166     return new JSTE.List.Return (c.execute (n));
167     }
168     });
169     });
170     }, // switchByElementType
171    
172     push: function (item) {
173     this.list.push (item);
174     }, // push
175     pushCloneOfLast: function () {
176     this.list.push (this.getLast ().clone ());
177     }, // pushCloneOfLast
178     append: function (list) {
179     var self = this;
180     list.forEach (function (n) {
181     self.list.push (n);
182     });
183     }, // append
184    
185     pop: function () {
186     return this.list.pop ();
187     }, // pop
188     remove: function (removedItem) {
189     var length = this.list.length;
190     for (var i = length - 1; i >= 0; --i) {
191     var item = this.list[i];
192     if (item == removedItem) { // Intentionally "=="
193     this.list.splice (i, 1);
194     }
195     }
196     }, // remove
197     clear: function () {
198     this.list.splice (0, this.list.length);
199     } // clear
200    
201     }); // List
202    
203     JSTE.List.Return = new JSTE.Class (function (rv) {
204     this.stop = true;
205     this.returnValue = rv;
206     }, {
207    
208     }); // Return
209    
210     JSTE.List.SpaceSeparated = function (v) {
211     return new JSTE.List ((v || '').split (JSTE.SpaceChars)).grep (function (v) {
212     return v.length;
213     });
214     }; // SpaceSeparated
215    
216     JSTE.List.SwitchByLocalName = new JSTE.Class (function (ns, cases, ow) {
217     this.namespaceURI = ns;
218     this.cases = cases;
219     this.otherwise = ow || function (n) { };
220     }, {
221     execute: function (n) {
222     for (var ln in this.cases) {
223     if (JSTE.Element.matchLocalName (n, ln)) {
224     return this.cases[ln] (n);
225     }
226     }
227     return this.otherwise (n);
228     }
229     });
230    
231     JSTE.Hash = new JSTE.Class (function (hash) {
232     this.hash = hash || {};
233     }, {
234     forEach: function (code) {
235     for (var n in this.hash) {
236     var r = code (n, this.hash[n]);
237     if (r && r.stop) break;
238     }
239     }, // forEach
240     clone: function (code) {
241     var newHash = {};
242     this.forEach (function (n, v) {
243     newHash[n] = v;
244     });
245     return new this.constructor (newHash);
246     }, // clone
247    
248     getNamedItem: function (n) {
249     return this.hash[n];
250     }, // getNamedItem
251     setNamedItem: function (n, v) {
252     return this.hash[n] = v;
253     } // setNamedItem
254     });
255    
256     if (!JSTE.Node) JSTE.Node = {};
257    
258     JSTE.Class.addClassMethods (JSTE.Node, {
259     querySelector: function (node, selectors) {
260     if (node.querySelector) {
261     var el;
262     try {
263     el = node.querySelector (selectors);
264     } catch (e) {
265     el = null;
266     }
267     return el;
268     } else if (window.uu && uu.css) {
269     if (selectors != "") {
270     /* NOTE: uu.css return all elements for "" or ",xxx" */
271     return uu.css (selectors, node)[0];
272     } else {
273     return null;
274     }
275     } else if (window.Ten && Ten.DOM && Ten.DOM.getElementsBySelector) {
276     return Ten.DOM.getElementsBySelector (selectors)[0];
277     } else {
278     return null;
279     }
280     }, // querySelector
281     querySelectorAll: function (node, selectors) {
282     if (node.querySelectorAll) {
283     var nl;
284     try {
285     nl = node.querySelectorAll (selectors);
286     } catch (e) {
287     nl = null;
288     }
289     return new JSTE.List (nl);
290     } else if (window.uu && uu.css) {
291     if (selectors != "") {
292     /* NOTE: uu.css return all elements for "" or ",xxx" */
293     return new JSTE.List (uu.css (selectors, node));
294     } else {
295     return new JSTE.List;
296     }
297     } else if (window.Ten && Ten.DOM && Ten.DOM.getElementsBySelector) {
298     return new JSTE.List (Ten.DOM.getElementsBySelector (selectors));
299     } else {
300     return new JSTE.List;
301     }
302     } // querySelectorAll
303     });
304    
305     if (!JSTE.Element) JSTE.Element = {};
306    
307     JSTE.Class.addClassMethods (JSTE.Element, {
308     getLocalName: function (el) {
309     var localName = el.localName;
310     if (!localName) {
311     localName = el.nodeName;
312     if (el.prefix) {
313     localName = localName.substring (el.prefix.length + 1);
314     }
315     }
316     return localName;
317     }, // getLocalName
318    
319     match: function (el, ns, ln) {
320     if (el.nodeType !== 1) return false;
321     if (el.namespaceURI !== ns) return false;
322     return JSTE.Element.matchLocalName (el, ln);
323     }, // match
324     matchLocalName: function (el, ln) {
325     var localName = JSTE.Element.getLocalName (el);
326     if (ln instanceof RegExp) {
327     if (!localName.match (ln)) return false;
328     } else {
329     if (localName !== ln) return false;
330     }
331     return true;
332     }, // matchLocalName
333    
334     getChildElement: function (el, ns, ln) {
335     return new JSTE.List (el.childNodes).getFirstMatch (function (item) {
336     return JSTE.Element.match (item, ns, ln);
337     });
338     }, // getChildElement
339     getChildElements: function (el, ns, ln) {
340     return new JSTE.List (el.childNodes).grep (function (item) {
341     return JSTE.Element.match (item, ns, ln);
342     });
343     }, // getChildElements
344    
345     appendText: function (el, s) {
346     return el.appendChild (el.ownerDocument.createTextNode (s));
347     }, // appendText
348    
349     createTemplate: function (doc, node) {
350     var df = doc.createDocumentFragment ();
351     new JSTE.List (node.childNodes).forEach (function (n) {
352     if (n.nodeType == 1) {
353     var c = doc.createElement (JSTE.Element.getLocalName (n));
354     new JSTE.List (c.attributes).forEach (function (n) {
355     c.setAttribute (n.name, n.value);
356     });
357     c.appendChild (JSTE.Element.createTemplate (doc, n));
358     df.appendChild (c);
359     } else if (n.nodeType == 3 || n.nodeType == 4) {
360     df.appendChild (doc.createTextNode (n.data));
361     }
362     });
363     return df;
364     }, // createTemplate
365    
366     hasAttribute: function (el, localName) {
367     if (el.hasAttribute) {
368     return el.hasAttribute (localName);
369     } else {
370     return el.getAttribute (localName) != null;
371     }
372     }, // hasAttribute
373    
374     getClassNames: function (el) {
375     return new JSTE.List (el.className.split (JSTE.SpaceChars));
376     }, // getClassNames
377     addClassName: function (el, newClassName) {
378     el.className = el.className + ' ' + newClassName;
379     }, // deleteClassName
380     deleteClassName: function (el, oldClassName) {
381     var classNames = el.className.split (JSTE.SpaceChars);
382     var newClasses = [];
383     for (var n in classNames) {
384     if (classNames[n] != oldClassName) {
385     newClasses.push (classNames[n]);
386     }
387     }
388     el.className = newClasses.join (' ');
389     }, // deleteClassName
390     replaceClassName: function (el, oldClassName, newClassName) {
391     var classNames = el.className.split (JSTE.SpaceChars);
392     var newClasses = [newClassName];
393     for (var n in classNames) {
394     if (classNames[n] != oldClassName) {
395     newClasses.push (classNames[n]);
396     }
397     }
398     el.className = newClasses.join (' ');
399     }, // replaceClassName
400    
401     getIds: function (el) {
402     return new JSTE.List (el.id != "" ? [el.id] : []);
403     } // getIds
404    
405     }); // JSTE.Element
406    
407     /* Events: load, close, shown, hidden */
408     JSTE.Message = new JSTE.Class (function (doc, template, commandTarget) {
409     if (!doc) return;
410     this._targetDocument = doc;
411     this._template = template || doc.createDocumentFragment ();
412     this._commandTarget = commandTarget;
413     this.hidden = true;
414     this.select = "";
415    
416     var e = new JSTE.Event ('load');
417     this.dispatchEvent (e);
418     }, {
419     render: function () {
420     var self = this;
421     var doc = this._targetDocument;
422    
423     var msgContainer = doc.createElement ('section');
424     msgContainer.appendChild (this._template);
425    
426     var buttonContainer = doc.createElement ('menu');
427    
428     var backButton = new JSTE.Message.Button
429     ("Back", this._commandTarget, "back");
430     buttonContainer.appendChild (backButton.element);
431    
432     var nextButton = new JSTE.Message.Button
433     ("Next", this._commandTarget, "next");
434     buttonContainer.appendChild (nextButton.element);
435    
436     this._outermostElement = this._render (msgContainer, buttonContainer);
437    
438     this.show ();
439     }, // render
440     _render: function (msgContainer, buttonContainer) {
441     var doc = this._targetDocument;
442    
443     var container = doc.createElement ('article');
444     var style = doc.createElement ('style');
445     style.innerHTML = this.select + ' { outline: red 2px solid }';
446     container.appendChild (style);
447    
448     container.appendChild (msgContainer);
449     container.appendChild (buttonContainer);
450     doc.documentElement.appendChild (container);
451    
452     return container;
453     }, // _render
454     remove: function () {
455     this.hide ();
456    
457     this._remove ();
458    
459     if (this._outermostElement && this._outermostElement.parentNode) {
460     this._outermostElement.parentNode.removeChild (this._outermostElement);
461     }
462    
463     var e = new JSTE.Event ("close");
464     this.dispatchEvent (e);
465     }, // remove
466     _remove: function () {
467    
468     }, // remove
469    
470     show: function () {
471     if (!this.hidden) return;
472     this.hidden = false;
473     if (this._outermostElement) {
474     JSTE.Element.replaceClassName
475     (this._outermostElement, "jste-hidden", "jste-shown");
476     }
477    
478     var e = new JSTE.Event ("shown");
479     this.dispatchEvent (e);
480     }, // show
481     hide: function () {
482     if (this.hidden) return;
483     this.hidden = true;
484     if (this._outermostElement) {
485     JSTE.Element.replaceClassName
486     (this._outermostElement, "jste-shown", "jste-hidden");
487     }
488    
489     var e = new JSTE.Event ("hidden");
490     this.dispatchEvent (e);
491     }, // hide
492    
493     setTimeout: function () {
494     /* TODO: ... */
495    
496     }
497    
498     }); // Message
499    
500     JSTE.Message.Button =
501     new JSTE.Class (function (labelText, commandTarget, commandName, commandArgs) {
502     labelText = labelText != null ? labelText : "";
503     var className;
504     if (commandTarget && commandTarget instanceof Function) {
505     this._command = commandTarget;
506     } else if (commandTarget) {
507     this._command = function () {
508     return commandTarget.executeCommand.apply
509     (commandTarget, [commandName, commandArgs]);
510     };
511     className = 'jste-command-' + commandName;
512     } else {
513     this._command = function () { };
514     }
515    
516     try {
517     this.element = document.createElement ('button');
518     this.element.setAttribute ('type', 'button');
519     } catch (e) {
520     this.element = document.createElement ('<button type=button>');
521     }
522     JSTE.Element.appendText (this.element, labelText);
523     if (className) this.element.className = className;
524    
525     var self = this;
526     new JSTE.Observer ("click", this.element, function (e) {
527     self._command.apply (self, [e]);
528     });
529     }, {
530    
531     }); // Button
532    
533     JSTE.Course = new JSTE.Class (function (doc) {
534     this._targetDocument = doc;
535    
536     this._entryPointsByURL = {};
537     this._entryPointsById = {};
538     this._entryPointsByClassName = {};
539    
540     this._stepsState = new JSTE.List ([new JSTE.Hash]);
541     this._steps = new JSTE.Hash;
542    
543     var nullState = new JSTE.Step;
544     nullState.uid = "";
545     this._steps.setNamedItem (nullState.uid, nullState);
546     this._initialStepUid = nullState.uid;
547     }, {
548     _processStepsContent: function (el) {
549     var self = this;
550     new JSTE.List (el.childNodes).switchByElementType (
551     new JSTE.List.SwitchByLocalName (JSTE.WATNS, {
552     steps: function (n) { self._processStepsElement (n) },
553     step: function (n) { self._processStepElement (n) },
554     jump: function (n) { self._processJumpElement (n) },
555     entry: function (n) { self._processEntryElement (n) }
556     })
557     );
558     }, // _processStepsContent
559     _processStepsElement: function (e) {
560     this._stepsState.pushCloneOfLast ();
561     this._stepsState.getLast ().prevStep = null;
562     this._processStepsContent (e);
563     this._stepsState.pop ();
564     }, // _processStepsElement
565    
566     _processEntryElement: function (e) {
567     if (JSTE.Element.hasAttribute (e, 'url')) {
568     this.setEntryPointByURL
569     (e.getAttribute ('url'), e.getAttribute ('step'));
570     } else if (JSTE.Element.hasAttribute (e, 'root-id')) {
571     this.setEntryPointById
572     (e.getAttribute ('root-id'), e.getAttribute ('step'));
573     } else if (JSTE.Element.hasAttribute (e, 'root-class')) {
574     this.setEntryPointByClassName
575     (e.getAttribute ('root-class'), e.getAttribute ('step'));
576     }
577     }, // _processEntryElement
578     setEntryPointByURL: function (url, stepName) {
579     this._entryPointsByURL[url] = stepName || '';
580     }, // setEntryPointByURL
581     setEntryPointById: function (id, stepName) {
582     this._entryPointsById[id] = stepName || '';
583     }, // setEntryPointById
584     setEntryPointByClassName: function (className, stepName) {
585     this._entryPointsByClassName[className] = stepName || '';
586     }, // setEntryPointByClassName
587     findEntryPoint: function (doc) {
588     var self = this;
589     var td = this._targetDocument;
590     var stepName;
591    
592     var url = doc.URL;
593     if (url) {
594     stepName = self._entryPointsByURL[url];
595     if (stepName) return 'id-' + stepName;
596     }
597    
598     var docEl = td.documentElement;
599     if (docEl) {
600     var docElId = JSTE.Element.getIds (docEl).forEach (function (i) {
601     stepName = self._entryPointsById[i];
602     if (stepName) return new JSTE.List.Return (stepName);
603     });
604     if (stepName) return 'id-' + stepName;
605    
606     stepName = JSTE.Element.getClassNames (docEl).forEach (function (c) {
607     stepName = self._entryPointsByClassName[c];
608     if (stepName) return new JSTE.List.Return (stepName);
609     });
610     if (stepName) return 'id-' + stepName;
611     }
612    
613     var bodyEl = td.body;
614     if (bodyEl) {
615     var bodyElId = JSTE.Element.getIds (bodyEl).forEach (function (i) {
616     stepName = self._entryPointsById[i];
617     if (stepName) return new JSTE.List.Return (stepName);
618     });
619     if (stepName) return 'id-' + stepName;
620    
621     stepName = JSTE.Element.getClassNames (bodyEl).forEach (function (c) {
622     stepName = self._entryPointsByClassName[c];
623     if (stepName) return new JSTE.List.Return (stepName);
624     });
625     if (stepName) return 'id-' + stepName;
626     }
627    
628     return this._initialStepUid;
629     }, // findEntryPoint
630    
631     _processStepElement: function (e) {
632     var step = new JSTE.Step (e.getAttribute ('id'));
633     step.setPreviousStep (this._stepsState.getLast ().prevStep);
634     step.select = e.getAttribute ('select') || "";
635     step.nextEvents.append
636     (JSTE.List.SpaceSeparated (e.getAttribute ('next-event')));
637     var msgEl = JSTE.Element.getChildElement (e, JSTE.WATNS, 'message');
638     if (msgEl) {
639     var msg = JSTE.Element.createTemplate (this._targetDocument, msgEl);
640     step.setMessageTemplate (msg);
641     }
642     var nextEls = JSTE.Element.getChildElements (e, JSTE.WATNS, 'next-step');
643     if (nextEls.length) {
644     nextEls.forEach (function (nextEl) {
645     step.addNextStep
646     (nextEl.getAttribute ('if'), nextEl.getAttribute ('step'));
647     });
648     this._stepsState.getLast ().prevStep = null;
649     } else {
650     this._stepsState.getLast ().prevStep = step;
651     }
652     /* TODO: @save */
653    
654     this._steps.setNamedItem (step.uid, step);
655     if (!this._initialStepUid) {
656     this._initialStepUid = step.uid;
657     }
658     }, // _processStepElement
659    
660     _processJumpElement: function (e) {
661    
662     }, // _processJumpElement
663    
664     getStep: function (uid) {
665     return this._steps.getNamedItem (uid);
666     } // getStep
667     }); // Course
668    
669     JSTE.Course.createFromDocument = function (doc, targetDoc) {
670     var course = new JSTE.Course (targetDoc);
671     var docEl = doc.documentElement;
672     if (!docEl) return course;
673     if (!JSTE.Element.match (docEl, JSTE.WATNS, 'course')) return course;
674     course._processStepsContent (docEl);
675     return course;
676     }; // createFromDocument
677    
678     JSTE.Step = new JSTE.Class (function (id) {
679     if (id != null && id != '') {
680     this.uid = 'id-' + id;
681     } else {
682     this.uid = 'rand-' + Math.random ();
683     }
684     this._nextSteps = new JSTE.List;
685     this.nextEvents = new JSTE.List;
686     this.select = "";
687     }, {
688     setMessageTemplate: function (msg) {
689     this._messageTemplate = msg;
690     }, // setMessageTemplate
691     hasMessage: function () {
692     return this._messageTemplate ? true : false;
693     }, // hasMessage
694     createMessage: function (msg, doc, commandTarget) {
695     var msg;
696     if (this._messageTemplate) {
697     var clone = JSTE.Element.createTemplate (doc, this._messageTemplate);
698     msg = new msg (doc, clone, commandTarget);
699     } else {
700     msg = new msg (doc, null, commandTarget);
701     }
702     msg.select = this.select;
703     return msg;
704     }, // createMessage
705    
706     addNextStep: function (condition, stepId) {
707     this._nextSteps.push ([condition, stepId]);
708     }, // addNextStep
709     setPreviousStep: function (prevStep) {
710     if (!prevStep) return;
711     if (prevStep._defaultNextStepUid) return;
712     prevStep._defaultNextStepUid = this.uid;
713     }, // setPreviousStep
714    
715     getNextStepUid: function (doc) {
716     var m = this._nextSteps.getFirstMatch (function (item) {
717     var condition = item[0];
718     if (condition) {
719     return JSTE.Node.querySelector (doc, condition) != null;
720     } else {
721     return true;
722     }
723     });
724     if (m) {
725     return 'id-' + m[1];
726     } else if (this._defaultNextStepUid) {
727     return this._defaultNextStepUid;
728     } else {
729     return null;
730     }
731     } // getNextStepUid
732    
733     }); // Step
734    
735 wakaba 1.3 /* Events: load, error, cssomready */
736 wakaba 1.1 JSTE.Tutorial = new JSTE.Class (function (doc, course, args) {
737     this._course = course;
738     this._targetDocument = doc;
739     this._messageClass = JSTE.Message;
740     if (args) {
741     if (args.messageClass) this._messageClass = args.messageClass;
742     }
743    
744     this._currentMessages = new JSTE.List;
745     this._currentObservers = new JSTE.List;
746     this._prevStepUids = new JSTE.List;
747    
748     var stepUid = this._course.findEntryPoint (document);
749     this._currentStep = this._getStepOrError (stepUid);
750     if (this._currentStep) {
751     var e = new JSTE.Event ('load');
752     this.dispatchEvent (e);
753    
754 wakaba 1.3 var self = this;
755     new JSTE.Observer ('cssomready', this, function () {
756     self._renderCurrentStep ();
757     });
758     this._dispatchCSSOMReadyEvent ();
759 wakaba 1.1 return this;
760     } else {
761     return {};
762     }
763     }, {
764     _getStepOrError: function (stepUid) {
765     var step = this._course.getStep (stepUid);
766     if (step) {
767     return step;
768     } else {
769     var e = new JSTE.Event ('error');
770     e.errorMessage = 'Step not found';
771     e.errorArguments = [this._currentStepUid];
772     this.dispatchEvent (e);
773     return null;
774     }
775     }, // _getStepOrError
776    
777     _renderCurrentStep: function () {
778     var self = this;
779     var step = this._currentStep;
780    
781     /* Message */
782     var msg = step.createMessage
783     (this._messageClass, this._targetDocument, this);
784     msg.render ();
785     this._currentMessages.push (msg);
786    
787     /* Next-events */
788     var selectedNodes = JSTE.Node.querySelectorAll
789     (this._targetDocument, step.select);
790     var handler = function () {
791     self.executeCommand ("next");
792     };
793     selectedNodes.forEach (function (node) {
794     step.nextEvents.forEach (function (eventType) {
795     self._currentObservers.push
796     (new JSTE.Observer (eventType, node, handler));
797     });
798     });
799     }, // _renderCurrentStep
800     clearMessages: function () {
801     this._currentMessages.forEach (function (msg) {
802     msg.remove ();
803     });
804     this._currentMessages.clear ();
805    
806     this._currentObservers.forEach (function (ob) {
807     ob.stop ();
808     });
809     this._currentObservers.clear ();
810     }, // clearMessages
811    
812     executeCommand: function (commandName, commandArgs) {
813     if (this[commandName]) {
814     return this[commandName].apply (this, commandArgs || []);
815     } else {
816     var e = new JSTE.Event ('error');
817     e.errorMessage = 'Command not found';
818     e.errorArguments = [commandName];
819     return null;
820     }
821     }, // executeCommand
822    
823     startTutorial: function () {
824     this.resetVisited ();
825    
826     }, // startTutorial
827     continueTutorial: function () {
828    
829     }, // continueTutorial
830    
831     saveVisited: function () {
832    
833     }, // saveVisited
834     resetVisited: function () {
835    
836     }, // resetVisited
837    
838     back: function () {
839     var prevStepUid = this._prevStepUids.pop ();
840     var prevStep = this._getStepOrError (prevStepUid);
841     if (prevStep) {
842     this.clearMessages ();
843     this._currentStep = prevStep;
844     this._renderCurrentStep ();
845     }
846     }, // back
847     next: function () {
848     var nextStepUid = this._currentStep.getNextStepUid (this._targetDocument);
849     var nextStep = this._getStepOrError (nextStepUid);
850     if (nextStep) {
851     this._prevStepUids.push (this._currentStep.uid);
852     this.clearMessages ();
853     this._currentStep = nextStep;
854     this._renderCurrentStep ();
855     }
856 wakaba 1.3 }, // next
857    
858     // <http://twitter.com/waka/status/1129513097>
859     _dispatchCSSOMReadyEvent: function () {
860     var self = this;
861     var e = new JSTE.Event ('cssomready');
862     if (window.opera && document.readyState != 'complete') {
863     new JSTE.Observer ('readystatechange', document, function () {
864     if (document.readyState == 'complete') {
865     self.dispatchEvent (e);
866     }
867     });
868     } else {
869     this.dispatchEvent (e);
870     }
871     } // dispatchCSSOMReadyEvent
872    
873 wakaba 1.1 }); // Tutorial
874 wakaba 1.2
875     /* ***** BEGIN LICENSE BLOCK *****
876     * Copyright 2008-2009 Wakaba <[email protected]>. All rights reserved.
877     *
878     * This program is free software; you can redistribute it and/or
879     * modify it under the same terms as Perl itself.
880     *
881     * Alternatively, the contents of this file may be used
882     * under the following terms (the "MPL/GPL/LGPL"),
883     * in which case the provisions of the MPL/GPL/LGPL are applicable instead
884     * of those above. If you wish to allow use of your version of this file only
885     * under the terms of the MPL/GPL/LGPL, and not to allow others to
886     * use your version of this file under the terms of the Perl, indicate your
887     * decision by deleting the provisions above and replace them with the notice
888     * and other provisions required by the MPL/GPL/LGPL. If you do not delete
889     * the provisions above, a recipient may use your version of this file under
890     * the terms of any one of the Perl or the MPL/GPL/LGPL.
891     *
892     * "MPL/GPL/LGPL":
893     *
894     * Version: MPL 1.1/GPL 2.0/LGPL 2.1
895     *
896     * The contents of this file are subject to the Mozilla Public License Version
897     * 1.1 (the "License"); you may not use this file except in compliance with
898     * the License. You may obtain a copy of the License at
899     * <http://www.mozilla.org/MPL/>
900     *
901     * Software distributed under the License is distributed on an "AS IS" basis,
902     * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
903     * for the specific language governing rights and limitations under the
904     * License.
905     *
906     * The Original Code is JSTE code.
907     *
908     * The Initial Developer of the Original Code is Wakaba.
909     * Portions created by the Initial Developer are Copyright (C) 2008
910     * the Initial Developer. All Rights Reserved.
911     *
912     * Contributor(s):
913     * Wakaba <[email protected]>
914     *
915     * Alternatively, the contents of this file may be used under the terms of
916     * either the GNU General Public License Version 2 or later (the "GPL"), or
917     * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
918     * in which case the provisions of the GPL or the LGPL are applicable instead
919     * of those above. If you wish to allow use of your version of this file only
920     * under the terms of either the GPL or the LGPL, and not to allow others to
921     * use your version of this file under the terms of the MPL, indicate your
922     * decision by deleting the provisions above and replace them with the notice
923     * and other provisions required by the LGPL or the GPL. If you do not delete
924     * the provisions above, a recipient may use your version of this file under
925     * the terms of any one of the MPL, the GPL or the LGPL.
926     *
927     * ***** END LICENSE BLOCK ***** */

[email protected]
ViewVC Help
Powered by ViewVC 1.1.24