/[suikacvs]/test/suikawebwww/style/ui/wizard.js.u8
Suika

Contents of /test/suikawebwww/style/ui/wizard.js.u8

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.4 - (hide annotations) (download)
Tue Jan 6 07:05:50 2009 UTC (17 years, 7 months ago) by wakaba
Branch: MAIN
CVS Tags: HEAD
Changes since 1.3: +20 -3 lines
Relicensed under the terms that are compatibile with Perl's license

1 wakaba 1.1 function WizardView (c) {
2 wakaba 1.3 if (c) {
3     this.container = c;
4     this.events = [];
5     this.currentPage = -1;
6     this._init ();
7     }
8 wakaba 1.1 } // WizardView
9    
10     WizardView.prototype.enable = function () {
11 wakaba 1.3 this.deleteClass (this.container, 'wizardview-disabled');
12     this.addClass (this.container, 'wizardview-enabled');
13 wakaba 1.1
14     var ev = new WizardView.Event ('enabled');
15     this.dispatchEvent (ev);
16     }; // enable
17    
18     WizardView.prototype.disable = function () {
19 wakaba 1.3 this.deleteClass (this.container, 'wizardview-enabled');
20     this.addClass (this.container, 'wizardview-disabled');
21 wakaba 1.1
22     var ev = new WizardView.Event ('disabled');
23     this.dispatchEvent (ev);
24     }; // disable
25    
26     WizardView.prototype.getDisabled = function () {
27 wakaba 1.3 return !this.hasClass (this.container, 'wizardview-enabled');
28 wakaba 1.1 }; // getDisabled
29    
30     WizardView.prototype._init = function () {
31     this._updateOutlineInfo ();
32     this._initPanel ();
33 wakaba 1.3 this.addClass (this.container, 'wizardview');
34 wakaba 1.1 this.showFirstPage ();
35     }; // _init
36    
37     WizardView.prototype._initPanel = function () {
38     var outline = this._createOutlineBox ();
39 wakaba 1.2 this.outlineBox = outline;
40 wakaba 1.1 this._insertOutlineBox (outline);
41    
42     var controller = this._createController ();
43     this._insertController (controller);
44     }; // _initPanel
45    
46 wakaba 1.3 WizardView.prototype.updateOutline = function () {
47     this._updateOutlineInfo ();
48     var newOutline = this._createOutlineBox ();
49     var oldOutline = this.outlineBox;
50     this.outlineBox = newOutline;
51     this._insertOutlineBox (newOutline, oldOutline);
52     }; // updateOutline
53    
54 wakaba 1.1 WizardView.prototype._updateOutlineInfo = function () {
55     this.pages = [];
56     this.__updateOutlineInfo (this.container, []);
57     }; // _updateOutlineInfo
58    
59     WizardView.prototype.__updateOutlineInfo = function (el, chain) {
60     var hasPage;
61     var elC = el.childNodes;
62     var elCL = elC.length;
63     for (var i = 0; i < elCL; i++) {
64     var child = elC[i];
65     if (child.nodeType == 1) {
66     if (this.isWizardContainerOrPage (child)) {
67     var newChain = chain.slice (0, chain.length);
68     newChain.push (child);
69     if (this.__updateOutlineInfo (child, newChain)) {
70     hasPage = true;
71     } else {
72     this.pages.push (newChain);
73     hasPage = true;
74     }
75     } else if (this.isTitle (child)) {
76     if (chain.length) {
77     chain[chain.length - 1].wizardTitle = this.getTitleText (child);
78     }
79     } else {
80     if (this.__updateOutlineInfo (child, chain)) {
81     hasPage = true;
82     }
83     }
84     }
85     }
86     return hasPage;
87     }; // _updateOutlineInfo
88    
89 wakaba 1.3 WizardView.prototype.addEventListener = function (eventType, handler, phase) {
90 wakaba 1.1 if (!this.events[eventType]) this.events[eventType] = [];
91     this.events[eventType].push (handler);
92     }; // addEventListener
93    
94     WizardView.prototype.dispatchEvent = function (ev) {
95     var eventType = ev.type;
96     if (!this.events[eventType]) return true;
97 wakaba 1.3 ev.target = this;
98     ev.currentTarget = this;
99 wakaba 1.1 var handlers = this.events[eventType];
100     for (var i = 0; i < handlers.length; i++) {
101     handlers[i] (ev);
102     }
103     return !ev.defaultPrevented;
104     }; // dispatchEvent
105    
106     WizardView.prototype.createButton = function () {
107     var el;
108    
109     try {
110     el = document.createElement ('button');
111 wakaba 1.3 el.setAttribute ('type', 'button');
112 wakaba 1.1 } catch (e) {
113     el = document.createElement ('<button type=button>');
114     }
115    
116     return el;
117     }; // createButton
118    
119 wakaba 1.3 WizardView.prototype.createSubmitButton = function () {
120     var el;
121    
122     try {
123     el = document.createElement ('button');
124     el.setAttribute('type', 'submit');
125     } catch (e) {
126     el = document.createElement ('<button type=submit>');
127     }
128    
129     return el;
130     }; // createSubmitButton
131    
132 wakaba 1.1 WizardView.prototype.getTextContent = function (el) {
133     var r = '';
134     var elC = el.childNodes;
135     var elCL = elC.length;
136     for (var i = 0; i < elCL; i++) {
137     var child = elC[i];
138     if (child.nodeType == 3 || child.nodeType == 4) {
139     r += child.data;
140     } else if (child.nodeType == 1) {
141     r += this.getTextContent (child);
142     }
143     }
144     return r;
145     }; // getTextContent
146    
147     WizardView.prototype.normalizeClassName = function (c) {
148     if (document.compatMode == 'BackCompat') {
149     return c.toLowerCase ();
150     } else {
151     return c;
152     }
153     }; // c
154    
155     WizardView.prototype.addClass = function (el, className) {
156     el.className += ' ' + className;
157     }; // addClass
158    
159     WizardView.prototype.deleteClass = function (el, className) {
160     var c = this.normalizeClassName (el.className).split (/\s+/);
161     className = this.normalizeClassName (className);
162     var C = [];
163     for (var i = 0; i < c.length; i++) {
164     if (c[i] != className) {
165     C.push (c[i]);
166     }
167     }
168     el.className = C.join (' ');
169     }; // deleteClass
170    
171     WizardView.prototype.hasClass = function (el, className) {
172     var c = this.normalizeClassName (el.className).split (/\s+/);
173     className = this.normalizeClassName (className);
174     for (var i = 0; i < c.length; i++) {
175     if (c[i] == className) {
176     return true;
177     }
178     }
179     return false;
180     }; // hasClass
181    
182 wakaba 1.3 WizardView.prototype.isActivePage = function (n) {
183     var page = this.pages[n];
184     for (var i = 0; i < page.length; i++) {
185     if (page[i].getAttribute ('hidden')) {
186     return false;
187     }
188     }
189     return true;
190     }; // isActivePage
191    
192 wakaba 1.1 WizardView.prototype.getNextPageOf = function (n) {
193 wakaba 1.3 A: while (++n < this.pages.length && n >= 0) {
194     if (this.isActivePage(n)) {
195     return n;
196 wakaba 1.1 }
197     }
198     return null;
199     }; // getNextPageOf
200    
201     WizardView.prototype.getPreviousPageOf = function (n) {
202 wakaba 1.3 A: while (--n >= 0 && n < this.pages.length) {
203     if (this.isActivePage(n)) {
204     return n;
205 wakaba 1.1 }
206     }
207     return null;
208     }; // getPreviousPageOf
209    
210 wakaba 1.3 WizardView.prototype.showActivePage = function (n) {
211     if (this.isActivePage (n)) {
212     return this.showPage (n);
213     } else {
214     return this.showPage (this.getNextPageOf (n) || this.getPreviousPageOf (n));
215     }
216     }; // showActivePage
217    
218 wakaba 1.1 WizardView.prototype.showPage = function (n) {
219     if (n == null) return;
220     if (n < 0 || n >= this.pages.length) return;
221     for (var i = 0; i < this.pages.length; i++) {
222     var page = this.pages[i];
223     for (var j = 0; j < page.length; j++) {
224     this.deleteClass (page[j], 'wizardview-active');
225     this.addClass (page[j], 'wizardview-inactive');
226     }
227     }
228     var page = this.pages[n];
229     for (var j = 0; j < page.length; j++) {
230     this.deleteClass (page[j], 'wizardview-inactive');
231     this.addClass (page[j], 'wizardview-active');
232     }
233    
234     this.currentPage = n;
235     this._markCurrentPageInOutlineBox (n);
236    
237     var ev = new WizardView.Event ('previouspagedisablednesschange');
238     ev.disabled = this.getPreviousPageOf (n) == null;
239     this.dispatchEvent (ev);
240    
241     var ev = new WizardView.Event ('nextpagedisablednesschange');
242     ev.disabled = this.getNextPageOf (n) == null;
243     this.dispatchEvent (ev);
244    
245     var ev = new WizardView.Event ('showpage');
246     ev,pageNumber = n;
247     this.dispatchEvent (ev);
248     }; // showPage
249    
250     WizardView.prototype.showFirstPage = function () {
251     this.showPage (this.getNextPageOf (-1));
252     }; // showFirstPage
253    
254     WizardView.prototype.showPreviousPage = function () {
255     this.showPage (this.getPreviousPageOf (this.currentPage));
256     }; // showPreviousPage
257    
258     WizardView.prototype.showNextPage = function () {
259     this.showPage (this.getNextPageOf (this.currentPage));
260     }; // showNextPage
261    
262 wakaba 1.3 /* TODO: Hyperlink support (e.g. onhashchange) */
263    
264     WizardView.prototype.showElement = function (el) {
265     while (!this.isWizardContainerOrPage (el)) {
266     el = el.parentNode;
267     }
268     if (!el) return;
269    
270     var pages = this.pages;
271     for (var i = 0; i < pages.length; i++) {
272     var page = pages[i];
273     if (page[page.length - 1] == el) {
274     return this.showPage (i);
275     }
276     }
277     }; // showElement
278    
279    
280 wakaba 1.1
281     WizardView.Event = function (eventType) {
282     this.type = eventType;
283     }; // Event
284    
285     WizardView.Event.prototype.preventDefault = function () {
286     this.defaultPrevented = true;
287     }; // preventDefault
288    
289    
290    
291     /* You might want to override methods below for customizing how wizard
292     pages are organized and to control page flow. */
293 wakaba 1.2
294     WizardView.prototype._createOutlineBox = function () {
295     var list = document.createElement ('ol');
296     for (var i = 0; i < this.pages.length; i++) {
297     var page = this.pages[i];
298     var li = document.createElement ('li');
299     li.innerHTML = 'Page ' + (i + 1);
300     if (page[page.length - 1].wizardTitle) {
301     li.firstChild.data = page[page.length - 1].wizardTitle;
302     }
303     list.appendChild (li);
304     }
305     return list;
306     }; // _createOutlineBox
307    
308     WizardView.prototype._markCurrentPageInOutlineBox = function (n) {
309     var list = this.outlineBox;
310     for (var i = 0; i < list.childNodes.length; i++) {
311     var li = list.childNodes[i];
312     if (i == n) {
313     this.addClass (li, 'wizard-selected-page');
314     } else {
315     this.deleteClass (li, 'wizard-selected-page');
316     }
317     }
318     }; // _markCurrentPageInOutlineBox
319 wakaba 1.1
320 wakaba 1.3 WizardView.prototype._insertOutlineBox = function (newOutline, oldOutline) {
321     if (oldOutline) {
322     this.container.replaceChild (newOutline, oldOutline);
323     } else {
324     this.container.appendChild (newOutline);
325     }
326 wakaba 1.1 }; // _insertOutlineBox
327    
328     WizardView.prototype._createController = function () {
329     var self = this;
330    
331     var controller = document.createElement ('nav');
332    
333     var prevButton = this.createButton ();
334     prevButton.innerHTML = 'Back';
335     prevButton.onclick = function () { self.showPreviousPage () };
336     this.addEventListener ('previouspagedisablednesschange', function (e) {
337     prevButton.disabled = e.disabled;
338     });
339     controller.appendChild (prevButton);
340    
341     var nextButton = this.createButton ();
342     nextButton.innerHTML = 'Next';
343     nextButton.onclick = function () { self.showNextPage () };
344     this.addEventListener ('nextpagedisablednesschange', function (e) {
345     nextButton.disabled = e.disabled;
346     });
347     controller.appendChild (nextButton);
348    
349     var finButton = this.createButton ();
350     finButton.innerHTML = 'Finish';
351     finButton.onclick = function () { self.finish () };
352     this.addEventListener ('finishdisablednesschange', function (e) {
353     finButton.disabled = e.disabled;
354     });
355     controller.appendChild (finButton);
356    
357     var cancelButton = this.createButton ();
358     cancelButton.innerHTML = 'Cancel';
359     cancelButton.onclick = function () { self.cancel () };
360     this.addEventListener ('canceldisablednesschange', function (e) {
361     cancelButton.disabled = e.disabled;
362     });
363     controller.appendChild (cancelButton);
364    
365     return controller;
366     }; // _createController
367    
368     WizardView.prototype._insertController = function (controller) {
369     this.container.appendChild (controller);
370     }; // _insertController
371    
372     WizardView.prototype.finish = function () {
373    
374     }; // finish
375    
376     WizardView.prototype.cancel = function () {
377    
378     }; // cancel
379    
380     WizardView.prototype.isWizardContainerOrPage = function (el) {
381     var tagName = el.tagName.toLowerCase ();
382     if (tagName == 'section' ||
383     (tagName == 'div' && this.hasClass (el, 'section'))) {
384     return true;
385     } else {
386     return false;
387     }
388     }; // isWizardContainerOrPage
389    
390     WizardView.prototype.isTitle = function (el) {
391     if (el.tagName.match (/^[Hh][1-6]$/)) {
392     return true;
393     } else {
394     return false;
395     }
396     }; // isTitle
397    
398     WizardView.prototype.getTitleText = function (el) {
399     return el.title.length ? el.title : this.getTextContent (el);
400     }; // getTitleText
401    
402     if (window.WizardViewOnLoad) window.WizardViewOnLoad ();
403    
404     /*
405    
406     Usage:
407    
408     <script src="http://suika.fam.cx/www/style/ui/wizard.js" charset=utf-8></script>
409     <script>
410     window.onload = function () {
411     var w = new WizardView (container);
412     w.enable ();
413     };
414     </script>
415 wakaba 1.3
416     Note: Don't try to use this script with a large container element.
417     This script scans all descendant nodes in the container element to
418     find wizard container, page, and title elements upon the
419     initializatioon and rewrites class="" attribute of all page elements
420     whenever the current page changes.
421 wakaba 1.1
422     */
423    
424     /* ***** BEGIN LICENSE BLOCK *****
425 wakaba 1.4 * Copyright 2008 Wakaba <[email protected]>. All rights reserved.
426     *
427     * This program is free software; you can redistribute it and/or
428     * modify it under the same terms as Perl itself.
429     *
430     * Alternatively, the contents of this file may be used
431     * under the following terms (the "MPL/GPL/LGPL"),
432     * in which case the provisions of the MPL/GPL/LGPL are applicable instead
433     * of those above. If you wish to allow use of your version of this file only
434     * under the terms of the MPL/GPL/LGPL, and not to allow others to
435     * use your version of this file under the terms of the Perl, indicate your
436     * decision by deleting the provisions above and replace them with the notice
437     * and other provisions required by the MPL/GPL/LGPL. If you do not delete
438     * the provisions above, a recipient may use your version of this file under
439     * the terms of any one of the Perl or the MPL/GPL/LGPL.
440     *
441     * "MPL/GPL/LGPL":
442     *
443 wakaba 1.1 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
444     *
445     * The contents of this file are subject to the Mozilla Public License Version
446     * 1.1 (the "License"); you may not use this file except in compliance with
447     * the License. You may obtain a copy of the License at
448     * <http://www.mozilla.org/MPL/>
449     *
450     * Software distributed under the License is distributed on an "AS IS" basis,
451     * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
452     * for the specific language governing rights and limitations under the
453     * License.
454     *
455     * The Original Code is WizardView code.
456     *
457 wakaba 1.4 * The Initial Developer of the Original Code is Wakaba.
458 wakaba 1.1 * Portions created by the Initial Developer are Copyright (C) 2008
459     * the Initial Developer. All Rights Reserved.
460     *
461     * Contributor(s):
462     * Wakaba <[email protected]>
463     *
464     * Alternatively, the contents of this file may be used under the terms of
465     * either the GNU General Public License Version 2 or later (the "GPL"), or
466     * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
467     * in which case the provisions of the GPL or the LGPL are applicable instead
468     * of those above. If you wish to allow use of your version of this file only
469     * under the terms of either the GPL or the LGPL, and not to allow others to
470     * use your version of this file under the terms of the MPL, indicate your
471     * decision by deleting the provisions above and replace them with the notice
472 wakaba 1.4 * and other provisions required by the LGPL or the GPL. If you do not delete
473 wakaba 1.1 * the provisions above, a recipient may use your version of this file under
474     * the terms of any one of the MPL, the GPL or the LGPL.
475     *
476     * ***** END LICENSE BLOCK ***** */

[email protected]
ViewVC Help
Powered by ViewVC 1.1.24