/[takahashi]/takahashi.xul
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /takahashi.xul

Parent Directory Parent Directory | Revision Log Revision Log


Revision 12 - (hide annotations)
Sat Jun 10 15:31:05 2006 UTC (13 years, 2 months ago) by dpavlin
File size: 62945 byte(s)
fix inserting elements at end of textarea
1 dpavlin 1 <?xml version="1.0" encoding="UTF-8"?>
2     <!--
3     高橋メソッドなプレゼンツール in XUL リターンズ
4     made by Piro
5     http://piro.sakura.ne.jp/
6    
7     based on
8     高橋メソッドなプレゼン作成ツール ver.2 made by mala
9     http://la.ma.la/blog/diary_200504080545.htm
10     もんたメソッドなプレゼン作成ツール made by mala
11     http://la.ma.la/blog/diary_200505310749.htm
12     -->
13    
14     <!-- ***** BEGIN LICENSE BLOCK *****
15     - Version: MPL 1.1
16     -
17     - The contents of this file are subject to the Mozilla Public License Version
18     - 1.1 (the "License"); you may not use this file except in compliance with
19     - the License. You may obtain a copy of the License at
20     - http://www.mozilla.org/MPL/
21     -
22     - Software distributed under the License is distributed on an "AS IS" basis,
23     - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
24     - for the specific language governing rights and limitations under the
25     - License.
26     -
27     - The Original Code is the Takahashi-Method-based Presentation Tool
28     - in XUL/Returns.
29     -
30     - The Initial Developer of the Original Code is SHIMODA Hiroshi.
31     - Portions created by the Initial Developer are Copyright (C) 2005-2006
32     - the Initial Developer. All Rights Reserved.
33     -
34     - Contributor(s): SHIMODA Hiroshi <piro@p.club.ne.jp>
35     - dynamis <dynamis@mozilla-japan.org>
36     - matobaa <matobaa@lily.freemail.ne.jp>
37     -
38     - ***** END LICENSE BLOCK ***** -->
39    
40    
41     <?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
42     <?xml-stylesheet href="takahashi.css" type="text/css"?>
43    
44     <page xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
45     id="presentation"
46     xmlns:html="http:/www.w3.org/1999/xhtml"
47     orient="vertical"
48     onkeypress="Presentation.onKeyPress(event);">
49    
50    
51     <html:textarea id="builtinCode" style="visibility: collapse">
52     TITLE::高橋メソッドなプレゼンツール in XUL リターンズ
53     高橋メソッド
54     in XUL
55     [[EM:RETURNS]]
56     ----
57     HEADER::高橋メソッドなプレゼンツール in XUL リターンズ
58     CHAPTER::操作説明
59     操作
60     ----
61     HEADER::操作
62     基本的に
63     高橋メソッド
64     in XUL
65     と同じ
66     ----
67     ALIGN::left
68     Enterか
69     Page Downか
70     左クリック
71     で[次のページ]
72     ----
73     ALIGN::right
74     →でも
75     ↓でも
76     次のページ
77     ----
78     ALIGN::center
79     キーボード操作時は
80     次のページへ進む操作で
81     ラベルをめくれます
82     (めくっていない
83     ラベルがなければ
84     そのまま次のページへ)
85     ----
86     一度めくったラベルは
87     状態を保持するので
88     ----
89     ALIGN::right
90     前のページに戻して
91     「奥さん、いいですか!
92     ここですよここ!」
93     ができる
94     ----
95     Back Spaceか
96     Page Upか
97     右クリック
98     で[前のページ]
99     ----
100     ←でも
101     ↑でも
102     前のページ
103     ----
104     ALIGN::right
105     Homeで
106     最初の
107     ページ
108     ----
109     ALIGN::left
110     Endで
111     最後の
112     ページ
113     ----
114     Ctrl-R
115     で[リロード]
116     ----
117     Ctrl-Eで
118     [編集]モード
119     突入
120     ----
121     HEADER::
122     CHAPTER::編集機能
123     編集
124     ----
125     HEADER::編集
126     編集モード時は
127     Ctrl-Nで新しい
128     ページの追加
129     ----
130     HEADER::機能
131     部分
132     強調
133     ----
134     テキストを部分的に
135     [[EM:強調]]できる
136     [[PRE:
137     [[EM:強調テキスト]&#173;]
138     [[EM:強調テキスト:EM]&#173;]
139     ]]
140     ----
141     整形済み
142     テキスト
143     [[PRE:
144     [[PRE:整形済み]&#173;]
145     [[PRE:整形済み:PRE]&#173;]
146     ]]
147     ----
148     行内に[[PRE:preformatted text]]を
149     書ける(けどあんまり意味ない)
150     ----
151     複数行にまたがる整形済みテキスト
152     [[PRE:&lt;html&gt;
153     &lt;head&gt;
154     &lt;title&gt;サンプル&lt;/title&gt;
155     &lt;/head&gt;
156     &lt;body&gt;
157     &lt;p&gt;サンプル&lt;/p&gt;
158     &lt;/body&gt;
159     &lt;/html&gt;:PRE]]
160     ソースコードの例示などに使える
161     ----
162     リンク
163     [[PRE:
164     [[URI]&#173;]
165     [[ラベル|URI]&#173;]
166     ]]
167     ----
168     [[リンクも埋め込める|http://piro.sakura.ne.jp/]]
169     ラベル無しリンクも可能↓
170     [[http://piro.sakura.ne.jp/]]
171     ----
172     [[image src="takahashi.png" width="300" height="168"]]
173     ----
174     画像
175     ----
176     [[PRE:
177     [[IMAGE src="*" width="*" height="*"]&#173;]
178     [[IMG src="*" width="*" height="*"]&#173;]
179     ]]
180     ----
181     インライン[[image src="takahashi.png" width="300" height="168"]]で
182     [[image src="takahashi.png" width="300" height="168"]]
183     いくつでも
184     埋め込める
185     ----
186     リンクや
187     画像のパスの
188     相対指定は
189     ----
190     データファイルの
191     あるディレクトリ
192     もしくは
193     本体のある
194     ディレクトリを
195     基準として解釈
196     ----
197     カスタム
198     スタイル
199     ----
200     自分だけのカスタム
201     指定も可能
202     [[PRE:
203     [[#クラス名:文字列]&#173;]
204     ]]
205     このように↓解釈
206     [[PRE:
207     &lt;description
208     class="クラス名"
209     value="文字列"/&gt;
210     ]]
211     ----
212     複数行にまたがる
213     指定も可能
214     [[PRE:
215     [[#クラス名:
216     1行目
217     2行目
218     ]&#173;]
219     ]]
220     このように↓解釈
221     [[PRE:
222     &lt;vbox class="クラス名 block"&gt;
223     &lt;description value="1行目"/&gt;
224     &lt;description value="2行目"/&gt;
225     &lt;/vbox&gt;
226     ]]
227     ----
228     takahashi.css
229     に自分で好きな
230     スタイル指定を
231     追加しよう!
232     ----
233     [[装飾記号|http://homepage2.nifty.com/k_maeda/code/uni/uni44.html]]などの
234     [[Unicodeの記号文字|http://homepage2.nifty.com/k_maeda/code/unicode.html]]
235     と組み合わせると
236     色々できるかも?
237     ----
238     HEADER::ヘッダ
239     FOOTER::フッタ
240     ヘッダとフッタも
241     自由に指定できる
242     [[PRE:
243     &#173;HEADER::ヘッダ
244     &#173;FOOTER::フッタ
245     ]]
246     ----
247     HEADER::
248     FOOTER::
249     テキストの水平配置
250     (ページ単位)
251     [[PRE:
252     &#173;ALIGN::left
253     &#173;ALIGN::right
254     &#173;ALIGN::center
255     ]]
256     ----
257     テキストの水平配置
258     (以後のページすべて)
259     [[PRE:
260     &#173;GLOBAL-ALIGN::left
261     &#173;GLOBAL-ALIGN::right
262     &#173;GLOBAL-ALIGN::center
263     ]]
264     ----
265     HEADER::機能
266     FOOTER::
267     CHAPTER::起動パラメータ
268     起動
269     パラ
270     メータ
271     ----
272     ?page=[数値]
273     ----
274     表示ページを
275     指定して起動
276     ----
277     ?data=[パス]
278     ----
279     外部データ
280     ファイルを
281     読み込み
282     ----
283     ?edit=true
284     ----
285     編集モード
286     の状態で起動
287     ----
288     HEADER::
289     CHAPTER::このアプリケーションについて
290     ファイ
291     ル構成
292     ----
293     HEADER::ファイル構成
294     [[takahashi.xul]]
295     [[takahashi.css]]
296     [[monta-label.png]]
297     ----
298     HEADER::
299     ライセンスは
300     [MPL1.1]
301     ってことで
302     ----
303     ご自由に
304     お使い
305     下さい
306     ----
307     説明
308     おわり
309     ----
310     Let's Enjoy
311     Takahashi
312     Method
313     Life !!
314     </html:textarea>
315    
316    
317     <deck flex="1" id="deck">
318    
319     <vbox flex="1"
320     onmouseup="Presentation.handleEvent(event);"
321     onmousedown="Presentation.handleEvent(event);"
322     onmousemove="Presentation.handleEvent(event);">
323     <toolbox id="canvasToolbar">
324     <toolbar>
325     <toolbarbutton oncommand="Presentation.home()" label="|&lt;&lt;"
326     observes="canBack"/>
327     <toolbarbutton oncommand="Presentation.back()" label="&lt;"
328     observes="canBack"/>
329     <toolbarbutton oncommand="Presentation.forward()" label="&gt;"
330     observes="canForward"/>
331     <toolbarbutton oncommand="Presentation.end()" label="&gt;&gt;|"
332     observes="canForward"/>
333     <toolbarseparator/>
334     <hbox align="center">
335     <textbox id="current_page" size="4"
336     oninput="if (this.value) Presentation.showPage(parseInt(this.value)-1);"/>
337     <toolbarbutton id="pages-list-button"
338     type="menu"
339     label="Select Page"
340     tooltiptext="Select Page"
341     class="dropmarker-button">
342     <menupopup id="pages-list"
343     onpopupshowing="if (event.target == this) Presentation.preventToShowHideToolbar = true;"
344     onpopuphiding="if (event.target == this) Presentation.preventToShowHideToolbar = false;"
345     oncommand="Presentation.showPage(parseInt(event.target.value));"/>
346     </toolbarbutton>
347     <description value="/"/>
348     <description id="max_page"/>
349     </hbox>
350     <toolbarseparator/>
351     <vbox flex="2">
352     <spacer flex="1"/>
353     <scrollbar id="scroller"
354     align="center" orient="horizontal"
355     oncommand="Presentation.showPage(parseInt(event.target.getAttribute('curpos')));"
356     onclick="Presentation.showPage(parseInt(event.target.getAttribute('curpos')));"
357     onmousedown="Presentation.onScrollerDragStart();"
358     onmousemove="Presentation.onScrollerDragMove();"
359     onmouseup="Presentation.onScrollerDragDrop();"/>
360     <spacer flex="1"/>
361     </vbox>
362     <toolbarseparator/>
363     <hbox>
364     <toolbarbutton label="timer"
365     oncommand="Presentation.setTimer();" />
366     </hbox>
367     <spacer flex="1"/>
368     <hbox>
369     <toolbarbutton label="auto"
370     id="autoButton"
371     type="checkbox"
372     autoCheck="false"
373     oncommand="Presentation.toggleAutoCruiseMode();" />
374     <toolbarbutton id="auto-interval-button"
375     type="menu"
376     label="Interval"
377     tooltiptext="Change Interval"
378     class="dropmarker-button">
379     <menupopup id="auto-interval-list"
380     onpopupshowing="
381     Presentation.preventToShowHideToolbar = true;
382     (this.getElementsByAttribute('value', Presentation.autoCruiseInterval)[0] || this.lastChild).setAttribute('checked', true);
383     "
384     onpopuphiding="Presentation.preventToShowHideToolbar = false;"
385     oncommand="Presentation.changeAutoCruiseInterval(parseInt(event.target.value));">
386     <menuitem type="radio" radiogroup="autocruise-interval"
387     label="1 sec" value="1000"/>
388     <menuitem type="radio" radiogroup="autocruise-interval"
389     label="2 sec" value="2000"/>
390     <menuitem type="radio" radiogroup="autocruise-interval"
391     label="3 sec" value="3000"/>
392     <menuitem type="radio" radiogroup="autocruise-interval"
393     label="4 sec" value="4000"/>
394     <menuitem type="radio" radiogroup="autocruise-interval"
395     label="5 sec" value="5000"/>
396     <menuseparator/>
397     <menuitem type="radio" radiogroup="autocruise-interval"
398     label="1 min" value="60000"/>
399     <menuitem type="radio" radiogroup="autocruise-interval"
400     label="2 min" value="120000"/>
401     <menuitem type="radio" radiogroup="autocruise-interval"
402     label="3 min" value="180000"/>
403     <menuitem type="radio" radiogroup="autocruise-interval"
404     label="4 min" value="240000"/>
405     <menuitem type="radio" radiogroup="autocruise-interval"
406     label="5 min" value="300000"/>
407     <menuseparator/>
408     <menuitem type="radio" radiogroup="autocruise-interval"
409     label="Custom"
410     oncommand="
411     var current = Presentation.autoCruiseInterval;
412     var val = parseInt(prompt('input interval (sec)', parseInt(current/1000)));
413     if (isNaN(val)) {
414     event.preventBubble();
415     return;
416     }
417     else
418     val = val * 1000;
419     this.value = val;
420     "/>
421     </menupopup>
422     </toolbarbutton>
423     </hbox>
424     <toolbarbutton label="Pen"
425     id="penButton"
426     type="checkbox"
427     autoCheck="false"
428     oncommand="StrokablePresentationService.toggleCheck();"/>
429     <toolbarseparator/>
430     <toolbarbutton id="toggleEva" label="Eva"
431     type="checkbox"
432     autoCheck="false"
433     oncommand="Presentation.toggleEvaMode();"/>
434     <toolbarseparator/>
435     <toolbarbutton label="Edit"
436     oncommand="Presentation.toggleEditMode();"/>
437     <toolbarbutton oncommand="Presentation.reload();" label="Reload"/>
438     </toolbar>
439     </toolbox>
440     <vbox flex="1" id="canvas">
441     <stack flex="1">
442     <vbox flex="1">
443     <hbox id="headerBox" flex="1">
444     <label id="header"/>
445     <spacer flex="1"/>
446     </hbox>
447     <spacer flex="19"/>
448     <hbox id="footerBox" flex="1">
449     <spacer flex="1"/>
450     <label id="footer"/>
451     </hbox>
452     </vbox>
453     <vbox flex="1"
454     onclick="Presentation.onPresentationClick(event);">
455     <spacer flex="1"/>
456     <hbox flex="1" id="contentBox">
457     <spacer flex="1"/>
458     <vbox id="content"/>
459     <spacer flex="1"/>
460     </hbox>
461     <spacer flex="1"/>
462     </vbox>
463     </stack>
464     </vbox>
465     <hbox id="indicatorBar"
466     onclick="Presentation.onIndicatorBarClick(event);">
467     <stack flex="1">
468     <vbox>
469     <progressmeter id="remainingPageIndicator"
470     type="determined" value="0"
471     flex="1"/>
472     <progressmeter id="remainingTimeIndicator"
473     type="determined" value="0"
474     flex="1"
475     collapsed="true"/>
476     </vbox>
477     <hbox flex="1">
478     <label value="Next:"/>
479     <description id="nextPage" flex="1" crop="end"/>
480     </hbox>
481     </stack>
482     </hbox>
483     </vbox>
484    
485    
486     <vbox flex="1" id="edit">
487     <toolbox>
488     <toolbar>
489     <menubar flex="1">
490     <menu label="File">
491     <menupopup>
492     <menuitem label="Save"
493     key="key_save"
494     oncommand="Presentation.output()"/>
495     <menuitem label="Reload"
496     key="key_reload"
497     oncommand="Presentation.reload()"/>
498     </menupopup>
499     </menu>
500     <menu label="Insert">
501     <menupopup>
502     <menuitem label="New Page"
503     key="key_insert_newpage"
504     oncommand="Presentation.insert('page')"/>
505     <menuseparator/>
506     <menuitem label="Header"
507     oncommand="Presentation.insert('header')"/>
508     <menuitem label="Footer"
509     oncommand="Presentation.insert('footer')"/>
510     <menuseparator/>
511     <menuitem label="Link"
512     oncommand="Presentation.insert('link')"/>
513     <menuitem label="Emphasis"
514     oncommand="Presentation.insert('em')"/>
515     <menuitem label="Preformatted"
516     oncommand="Presentation.insert('pre')"/>
517     <menuitem label="Monta"
518     oncommand="Presentation.insert('monta')"/>
519     <menuitem label="Image"
520     oncommand="Presentation.insert('img')"/>
521     </menupopup>
522     </menu>
523     </menubar>
524     <toolbarseparator/>
525     <toolbarbutton label="View"
526     oncommand="Presentation.toggleEditMode();"/>
527     <toolbarbutton oncommand="Presentation.reload();" label="Reload"/>
528     </toolbar>
529     </toolbox>
530     <textbox id="textField" flex="1" multiline="true"
531     oninput="Presentation.onEdit()"/>
532     </vbox>
533    
534     </deck>
535    
536    
537     <broadcasterset>
538     <broadcaster id="canBack"/>
539     <broadcaster id="canForward"/>
540     </broadcasterset>
541    
542     <commandset>
543     <command id="cmd_forward"
544     oncommand="if (Presentation.isPresentationMode) Presentation.forward();"/>
545     <command id="cmd_forwardStep"
546     oncommand="if (Presentation.isPresentationMode) Presentation.forwardStep();"/>
547     <command id="cmd_back"
548     oncommand="if (Presentation.isPresentationMode) Presentation.back();"/>
549     <command id="cmd_home"
550     oncommand="if (Presentation.isPresentationMode) Presentation.home();"/>
551     <command id="cmd_end"
552     oncommand="if (Presentation.isPresentationMode) Presentation.end();"/>
553     </commandset>
554     <keyset>
555     <key keycode="VK_ENTER" command="cmd_forwardStep"/>
556     <key keycode="VK_RETURN" command="cmd_forwardStep"/>
557     <key keycode="VK_PAGE_DOWN" command="cmd_forwardStep"/>
558     <key keycode="VK_RIGHT" command="cmd_forwardStep"/>
559     <key keycode="VK_DOWN" command="cmd_forwardStep"/>
560     <!--key keycode="VK_BACK_SPACE" command="cmd_back"/-->
561     <key keycode="VK_PAGE_UP" command="cmd_back"/>
562     <key keycode="VK_UP" command="cmd_back"/>
563     <key keycode="VK_LEFT" command="cmd_back"/>
564     <key keycode="VK_HOME" command="cmd_home"/>
565     <key keycode="VK_END" command="cmd_end"/>
566    
567     <key id="key_insert_newpage"
568     key="n" modifiers="accel" oncommand="Presentation.insert('page');"/>
569    
570     <key id="key_save"
571     key="s" modifiers="accel" oncommand="Presentation.output();"/>
572     <key id="key_reload"
573     key="r" modifiers="accel" oncommand="Presentation.reload();"/>
574    
575     <key key="e" modifiers="accel" oncommand="Presentation.toggleEditMode();"/>
576     <key key="e" modifiers="accel,shift" oncommand="Presentation.toggleEvaMode();"/>
577     </keyset>
578    
579    
580     <script type="application/x-javascript"><![CDATA[
581    
582     var Presentation = {
583    
584     size : 9,
585     montaLabelImage : 'monta-label.png',
586    
587     phraseOpenParen : '[',
588     phraseCloseParen : ']',
589     makePhraseRegExp : function(aPattern, aFlags)
590     {
591     return new RegExp(
592     aPattern.replace(/%o(pen)?/gi, '\\'+this.phraseOpenParen)
593     .replace(/%c(lose)?/gi, '\\'+this.phraseCloseParen),
594     aFlags
595     );
596     },
597    
598     dragStartDelta : 8,
599    
600    
601     initialized : false,
602    
603     preventToShowHideToolbar : false,
604    
605     showMontaKeywordTimeout : 100,
606     autoCruiseInterval : 2000,
607     timerUpdatingInterval : 30000,
608     standByMontaLabels : [],
609     shownMontaLabels : [],
610    
611     init : function(option){
612     if (this.initialized) {
613     this.startPresentation();
614     return;
615     }
616     this.initialized = true;
617    
618    
619     this._offset = 0;
620     this.canvas = document.getElementById('canvas');
621     this.content = document.getElementById('content');
622     this.header = document.getElementById('header');
623     this.footer = document.getElementById('footer');
624     this.next = document.getElementById('nextPage');
625    
626     this.indicatorBar = document.getElementById('indicatorBar');
627     this.remainder = document.getElementById('remainingPageIndicator');
628     this.timer = document.getElementById('remainingTimeIndicator');
629    
630     this.list = document.getElementById('pages-list');
631     this.textbox = document.getElementById('textField');
632     this.deck = document.getElementById('deck');
633     this.scroller = document.getElementById('scroller');
634    
635     this.toolbar = document.getElementById('canvasToolbar');
636     this.toolbarHeight = this.toolbar.boxObject.height;
637     this.isToolbarHidden = true;
638     this.toolbar.setAttribute('style', 'margin-top:'+(0-this.toolbarHeight)+'px;margin-bottom:0px;');
639    
640     this.preloadImage(this.montaLabelImage);
641    
642     window.addEventListener('resize', this, false);
643     window.addEventListener('contextmenu', this, false);
644    
645     if(option){
646     for(var i in option){this[i] = option[i]}
647     }
648    
649     if (this.readParameter()) {
650     this.startPresentation();
651     }
652    
653     document.documentElement.focus();
654     },
655    
656     startPresentation : function()
657     {
658     if (this.data.length)
659     document.title = this.data[0].title || this.data[0].header || this.data[0].text.join(' ');
660    
661     this.takahashi();
662     },
663    
664     takahashi : function() {
665     if(!this.data[this.offset]){
666     this.offset = this.data.length-1;
667     }
668     document.getElementById("current_page").value = this.offset+1;
669     document.getElementById("max_page").value = this.data.length;
670    
671     this.scroller.setAttribute('maxpos', this.data.length-1);
672     this.scroller.setAttribute('curpos', this.offset);
673    
674     var broadcaster = document.getElementById('canBack');
675     if (!this.offset)
676     broadcaster.setAttribute('disabled', true);
677     else
678     broadcaster.removeAttribute('disabled');
679    
680     var broadcaster = document.getElementById('canForward');
681     if (this.offset == this.data.length-1)
682     broadcaster.setAttribute('disabled', true);
683     else
684     broadcaster.removeAttribute('disabled');
685    
686     this.canvas.setAttribute('rendering', true);
687    
688    
689    
690     this.header.removeAttribute('style');
691     this.footer.removeAttribute('style');
692     this.content.removeAttribute('style');
693    
694     this.standByMontaLabels = [];
695     this.clickableNodes = [];
696    
697    
698     if ('title' in this.data[this.offset])
699     document.title = this.data[this.offset].title;
700    
701     this.header.setAttribute('style', 'font-size:10px;');
702     this.header.value = this.data[this.offset].header;
703     this.footer.setAttribute('style', 'font-size:10px;');
704     this.footer.value = this.data[this.offset].footer;
705    
706     var text = this.data[this.offset].text;
707     var range = document.createRange();
708     range.selectNodeContents(this.content);
709     range.deleteContents();
710     range.detach();
711    
712     var line;
713     var newLine;
714     var uri;
715     var image_width;
716     var image_total_width = 0;
717     var image_height;
718     var image_total_height = 0;
719     var image_src;
720    
721 dpavlin 2 var labelId = 0;
722 dpavlin 1 var lineRegExp = this.makePhraseRegExp('^([^%O]+)?(%O%Oem:((.+?)(:em)?%C%C)?|%O%Opre:((.+?)(:pre)?%C%C)?|%O%O\#[^:]+:((.+?)%C%C)?|%O%Oima?ge? +src="([^"]+)" +width="([0-9]+)" +height="([0-9]+)"[^%C]*%C%C|%O%O(([^\|]+)?\\||)([^%C]+)%C%C|%O([^%C]+)%C)(.+)?', 'i');
723    
724 dpavlin 3 var emRegExp = this.makePhraseRegExp('^([^%O]+)?%O%Oem:(.+?)(:em)?%C%C', 'i');
725 dpavlin 1 var emStartRegExp = this.makePhraseRegExp('^([^%O]+)?%O%Oem:(.*)', 'i');
726     var emEndRegExp = this.makePhraseRegExp('^(.*?)((:em)?%C%C)', 'i');
727    
728     var preRegExp = this.makePhraseRegExp('^([^%O]+)?%O%Opre:(.+?)(:pre)?%C%C', 'i');
729     var preStartRegExp = this.makePhraseRegExp('^([^%O]+)?%O%Opre:(.*)', 'i');
730     var preEndRegExp = this.makePhraseRegExp('^(.*?)((:pre)?%C%C)', 'i');
731    
732     var styleRegExp = this.makePhraseRegExp('^([^%O]+)?%O%O\\#([^:]+):(.+?)%C%C', '');
733     var styleStartRegExp = this.makePhraseRegExp('^([^%O]+)?%O%O\\#([^:]+):(.*)', '');
734     var styleEndRegExp = this.makePhraseRegExp('^(.*?)(%C%C)', '');
735    
736     var imagesRegExp = this.makePhraseRegExp('^([^%O]+)?%O%Oima?ge? +src="([^"]+)" +width="([0-9]+)" +height="([0-9]+)"[^%C]*%C%C', 'i');
737    
738     var linksRegExp = this.makePhraseRegExp('^([^%O]+)?%O%O(([^|]+)?\\||)([^%C]+)%C%C', '');
739    
740 dpavlin 7 var wikiRegExp = this.makePhraseRegExp('^([^%O]+)?%O([0-9]*)([#!])?([:\/\*_-])([^%C]+)[:\/\*_-]%C', '');
741 dpavlin 4
742 dpavlin 1 var montaRegExp = this.makePhraseRegExp('^([^%O]+)?%O([^%C]+)%C', '');
743    
744     var inBlock = false,
745     blockClass = '',
746     blockContents = [];
747    
748     var fragment = document.createDocumentFragment();
749    
750     for (var i = 0, max = text.length; i < max; i++)
751     {
752     fragment.appendChild(document.createElement('hbox'));
753     fragment.lastChild.setAttribute('align', 'center');
754     fragment.lastChild.setAttribute('pack', this.data[this.offset].align);
755    
756     line = text[i];
757     image_width = 0;
758     image_height = 0;
759     if (!line) line = ' ';
760    
761     if (inBlock) {
762     if (blockClass == 'preformatted-text' &&
763     preEndRegExp.test(line)) {
764     inBlock = false;
765     blockContents.push(RegExp.$1);
766     line = line.substring((RegExp.$1+RegExp.$2).length);
767    
768     fragment.lastChild.appendChild(document.createElement('description'));
769     fragment.lastChild.lastChild.setAttribute('class', 'preformatted-text block');
770     fragment.lastChild.lastChild.appendChild(document.createTextNode(
771     blockContents.join('\n')
772     .replace(/^[\r\n\s]+/, '')
773     .replace(/[\r\n\s]+$/, '')
774     .replace(/&amp;/g, '&')
775     .replace(/&quot;/g, '"')
776     .replace(/&gt;/g, '>')
777     .replace(/&lt;/g, '<')
778     ));
779    
780     blockClass = '';
781     blockContents = [];
782     }
783     else if (emEndRegExp.test(line) || styleEndRegExp.test(line)) {
784     inBlock = false;
785     blockContents.push(RegExp.$1);
786     line = line.substring((RegExp.$1+RegExp.$2).length);
787    
788     fragment.lastChild.appendChild(document.createElement('vbox'));
789     fragment.lastChild.lastChild.setAttribute('class', blockClass+' block');
790     fragment.lastChild.lastChild.setAttribute('align', this.data[this.offset].align);
791     blockContents = blockContents.join('\n')
792     .replace(/^[\r\n\s]+/, '')
793     .replace(/[\r\n\s]+$/, '')
794     .split('\n');
795     for (var j = 0, jmax = blockContents.length; j < jmax; j++)
796     {
797     fragment.lastChild.lastChild.appendChild(document.createElement('description'));
798     fragment.lastChild.lastChild.lastChild.setAttribute('value', blockContents[j]);
799     }
800    
801     blockClass = '';
802     blockContents = [];
803     }
804     else {
805     blockContents.push(line);
806     continue;
807     }
808     }
809    
810     while (line.match(lineRegExp))
811     {
812     if (RegExp.$1) {
813     fragment.lastChild.appendChild(document.createElement('description'));
814     fragment.lastChild.lastChild.setAttribute('value', RegExp.$1);
815     }
816     newLine = line.substring((RegExp.$1+RegExp.$2).length);
817    
818     // Preformatted Text
819     if (preRegExp.test(line)) {
820     fragment.lastChild.appendChild(document.createElement('description'));
821     fragment.lastChild.lastChild.setAttribute('value', RegExp.$2);
822     fragment.lastChild.lastChild.setAttribute('class', 'preformatted-text');
823     }
824     else if (preStartRegExp.test(line)) {
825     inBlock = true;
826     blockClass = 'preformatted-text';
827     blockContents = [RegExp.$2];
828     newLine = '';
829     }
830    
831     // Emphasis
832     else if (emRegExp.test(line)) {
833     fragment.lastChild.appendChild(document.createElement('description'));
834     fragment.lastChild.lastChild.setAttribute('value', RegExp.$2);
835     fragment.lastChild.lastChild.setAttribute('class', 'em-text');
836     }
837     else if (emStartRegExp.test(line)) {
838     inBlock = true;
839     blockClass = 'em-text';
840     blockContents = [RegExp.$2];
841     newLine = '';
842     }
843    
844     // User-defined Styles
845     else if (styleRegExp.test(line)) {
846     fragment.lastChild.appendChild(document.createElement('description'));
847     fragment.lastChild.lastChild.setAttribute('value', RegExp.$3);
848     fragment.lastChild.lastChild.setAttribute('class', RegExp.$2);
849     }
850     else if (styleStartRegExp.test(line)) {
851     inBlock = true;
852     blockClass = RegExp.$2;
853     blockContents = [RegExp.$3];
854     newLine = '';
855     }
856    
857     // Images
858     else if (imagesRegExp.test(line)) {
859     fragment.lastChild.appendChild(document.createElement('image'));
860     image_src = RegExp.$2;
861     if (image_src.indexOf('http://') < 0 &&
862     image_src.indexOf('https://') < 0)
863     image_src = this.dataFolder+image_src;
864     fragment.lastChild.lastChild.setAttribute('src', image_src);
865     fragment.lastChild.lastChild.setAttribute('width', parseInt(RegExp.$3 || '0'));
866     fragment.lastChild.lastChild.setAttribute('height', parseInt(RegExp.$4 || '0'));
867     image_width += parseInt(RegExp.$3 || '0');
868     image_height = Math.max(image_height, parseInt(RegExp.$4 || '0'));
869     }
870    
871     // Links
872     else if (linksRegExp.test(line)) {
873     uri = RegExp.$4;
874     if (uri.indexOf('://') < 0)
875     uri = this.dataFolder+uri;
876     fragment.lastChild.appendChild(document.createElement('description'));
877     fragment.lastChild.lastChild.setAttribute('value', RegExp.$3 || RegExp.$4);
878     fragment.lastChild.lastChild.setAttribute('href', uri);
879     fragment.lastChild.lastChild.setAttribute('tooltiptext', uri);
880     fragment.lastChild.lastChild.setAttribute('statustext', uri);
881     fragment.lastChild.lastChild.setAttribute('class', 'link-text');
882    
883     this.clickableNodes.push(fragment.lastChild.lastChild);
884     }
885    
886 dpavlin 4 // modify font size and wiki-style
887     else if (wikiRegExp.test(line)) {
888     fragment.lastChild.appendChild(document.createElement('description'));
889 dpavlin 5 fragment.lastChild.lastChild.setAttribute('value', RegExp.$5);
890 dpavlin 4 var style = 'font-size:'+ ( RegExp.$2 || 100 ) +'%';
891 dpavlin 5 if (RegExp.$4 == '*') {
892 dpavlin 4 style += '; font-weight: bold;';
893 dpavlin 5 } else if (RegExp.$4 == '/') {
894 dpavlin 4 style += '; font-style: italic;';
895 dpavlin 5 } else if (RegExp.$4 == '_') {
896 dpavlin 4 style += '; text-decoration: underline;';
897 dpavlin 7 } else if (RegExp.$4 == '-') {
898     style += '; text-decoration: line-through;';
899 dpavlin 4 }
900     fragment.lastChild.lastChild.setAttribute('style', style);
901 dpavlin 5 if (RegExp.$3 == '!') fragment.lastChild.lastChild.setAttribute('class', 'em-text');
902     else if (RegExp.$3 == '#') fragment.lastChild.lastChild.setAttribute('class', 'preformatted-text');
903 dpavlin 4 }
904    
905 dpavlin 1 // Monta
906     else if (montaRegExp.test(line)) {
907     fragment.lastChild.appendChild(document.createElement('stack'));
908    
909     fragment.lastChild.lastChild.appendChild(document.createElement('description'));
910     fragment.lastChild.lastChild.lastChild.setAttribute('value', RegExp.$2);
911     fragment.lastChild.lastChild.lastChild.setAttribute('class', 'monta-text');
912    
913     fragment.lastChild.lastChild.appendChild(document.createElement('spacer'));
914     fragment.lastChild.lastChild.lastChild.setAttribute('flex', 1);
915     fragment.lastChild.lastChild.lastChild.setAttribute('class', 'monta-label');
916    
917     fragment.lastChild.lastChild.lastChild.setAttribute('label-id', 'label-' + (++labelId));
918    
919     if (!this.shownMontaLabels[this.offset] || !this.shownMontaLabels[this.offset]['label-'+labelId]) {
920     fragment.lastChild.lastChild.lastChild.setAttribute('monta-hidden', 'true');
921     this.standByMontaLabels[this.standByMontaLabels.length] = fragment.lastChild.lastChild.lastChild;
922     }
923     else {
924     fragment.lastChild.lastChild.lastChild.setAttribute('monta-hidden', 'false');
925     }
926    
927     this.clickableNodes.push(fragment.lastChild.lastChild.lastChild);
928     }
929    
930     line = newLine;
931     }
932    
933     if (line) {
934     fragment.lastChild.appendChild(document.createElement('description'));
935     fragment.lastChild.lastChild.setAttribute('value', line);
936     }
937    
938     image_total_width = Math.max(image_total_width, image_width);
939     image_total_height += image_height;
940     }
941    
942     this.content.setAttribute('style', 'font-size:10px;');
943     this.content.appendChild(fragment);
944    
945     this.clickableNodes.push(this.content);
946    
947    
948     this.fitToCanvas(this.header, this.header.parentNode, 0, 0);
949     this.fitToCanvas(this.footer, this.footer.parentNode, 0, 0);
950     this.fitToCanvas(
951     this.content,
952     this.canvas,
953     image_total_width,
954     image_total_height
955     +(this.header.boxObject.height*2)
956     // +(this.footer.boxObject.height*2)
957     );
958    
959    
960     var checkedItems = this.list.getElementsByAttribute('checked', 'true');
961     max = checkedItems.length;
962     for (i = 0; i < max; i++)
963     checkedItems[i].removeAttribute('checked');
964    
965     this.list.getElementsByAttribute('value', this.offset)[0].setAttribute('checked', true);
966    
967     this.canvas.removeAttribute('rendering');
968     this.setHash('page', 'page'+(this.offset+1));
969    
970     this.next.value = (this.offset <= this.data.length-2) ? (this.data[this.offset+1].plain.join('') || this.data[this.offset+1].text.join('')).replace(/\s+/g, ' ') : '(no page)' ;
971     this.remainder.setAttribute('value', this.offset == 0 ? 0 : parseInt(((this.offset)/(this.data.length-1))*100));
972    
973     var event = document.createEvent('Events');
974     event.initEvent('PresentationRedraw', false, true);
975     this.canvas.dispatchEvent(event);
976     },
977     fitToCanvas : function(aContent, aCanvas, aOffsetWidth, aOffsetHeight)
978     {
979     aContent.removeAttribute('style');
980     aContent.setAttribute('style', 'font-size:10px;');
981    
982     if (!aContent.boxObject.width) return;
983    
984     var canvas_w = aCanvas.boxObject.width;
985     var canvas_h = aCanvas.boxObject.height-aOffsetHeight;
986    
987     var content_w = aContent.boxObject.width;
988     var new_fs = Math.round((canvas_w/content_w) * this.size);
989     aContent.setAttribute('style', 'font-size:'+ new_fs + "px");
990    
991     if (aContent.boxObject.width < aOffsetWidth) {
992     content_w = aOffsetWidth;
993     new_fs = Math.round((canvas_w/content_w) * this.size);
994     aContent.setAttribute('style', 'font-size:'+ new_fs + "px");
995     }
996    
997     var content_h = aContent.boxObject.height;
998     if(content_h >= canvas_h){
999     state='height';
1000     content_h = aContent.boxObject.height;
1001     new_fs = Math.round((canvas_h/content_h) * new_fs);
1002     aContent.setAttribute('style', 'font-size:'+ new_fs + "px");
1003     }
1004     },
1005    
1006     reload : function() {
1007     var file = String(location.href).replace(/#.+$/, '');
1008     if (this.dataPath != file) {
1009     var path = this.dataPath;
1010     var request = new XMLHttpRequest();
1011 dpavlin 8 request.open('GET', path + '?rand=' + Math.random() );
1012 dpavlin 1 request.onload = function() {
1013     Presentation.textbox.value = request.responseText;
1014     Presentation.data = Presentation.textbox.value;
1015     Presentation.init();
1016    
1017     path = null;
1018     request = null;
1019     };
1020     request.send(null);
1021     }
1022     else
1023     window.location.reload();
1024     },
1025    
1026     forward : function(){
1027     this.offset++;
1028     this.takahashi();
1029     },
1030     forwardStep : function(){
1031     if (this.standByMontaLabels.length > 0) {
1032     while (this.standByMontaLabels.length &&
1033     this.standByMontaLabels[0].getAttribute('monta-hidden') != 'true')
1034     this.standByMontaLabels.splice(0, 1);
1035    
1036     if (this.standByMontaLabels.length) {
1037     this.showMontaKeyword(this.standByMontaLabels[0]);
1038     this.standByMontaLabels.splice(0, 1);
1039     }
1040     }
1041     else
1042     this.forward();
1043     },
1044     back : function(){
1045     this.offset--;
1046     if(this.offset < 0){this.offset = 0}
1047     this.takahashi();
1048     },
1049     home : function(){
1050     this.offset = 0;
1051     this.takahashi();
1052     },
1053     end : function(){
1054     this.offset = this.data.length-1;
1055     this.takahashi();
1056     },
1057     showPage : function(aPageOffset){
1058     this.offset = aPageOffset ? aPageOffset : 0 ;
1059     this.takahashi();
1060     },
1061    
1062     insert : function(aType) {
1063     switch (aType)
1064     {
1065     case 'page':
1066     this.insertTextFor('\n----\n', this.textbox, 6);
1067     break;
1068     case 'header':
1069     this.insertTextFor('\nHEADER::\n', this.textbox, 9);
1070     break;
1071     case 'footer':
1072     this.insertTextFor('\nFOOTER::\n', this.textbox, 9);
1073     break;
1074    
1075     case 'em':
1076     case 'emphasis':
1077     this.insertTextFor(this.phraseOpenParen+this.phraseOpenParen+'EM:'+this.phraseCloseParen+this.phraseCloseParen, this.textbox, 5);
1078     break;
1079     case 'pre':
1080     case 'preformatted':
1081     this.insertTextFor(this.phraseOpenParen+this.phraseOpenParen+'PRE:'+this.phraseCloseParen+this.phraseCloseParen, this.textbox, 6);
1082     break;
1083     case 'monta':
1084     this.insertTextFor(this.phraseOpenParen+this.phraseCloseParen, this.textbox, 1);
1085     break;
1086     case 'link':
1087     this.insertTextFor(this.phraseOpenParen+this.phraseOpenParen+'|http://'+this.phraseCloseParen+this.phraseCloseParen, this.textbox, 2);
1088     break;
1089     case 'img':
1090     case 'image':
1091     this.insertTextFor(this.phraseOpenParen+this.phraseOpenParen+'image src="" width="" height=""'+this.phraseCloseParen+this.phraseCloseParen, this.textbox, 13);
1092     break;
1093    
1094     default:
1095     return;
1096     }
1097     this.onEdit();
1098     },
1099     insertTextFor : function(aString, aNode, aPosOffset)
1100     {
1101     var pos = aNode.selectionStart;
1102 dpavlin 11 var sel_len = aNode.selectionEnd - aNode.selectionStart;
1103 dpavlin 1 var value = aNode.value;
1104 dpavlin 11 if (! aPosOffset) aPosOffset = 0;
1105     aNode.value = [
1106     value.substring(0, pos),
1107     aString.substring(0,aPosOffset),
1108     value.substring(pos, pos + sel_len),
1109     aString.substring(aPosOffset, aString.length),
1110 dpavlin 12 value.substring(pos + sel_len, value.length)
1111 dpavlin 11 ].join('');
1112     aNode.selectionStart = pos + (aPosOffset || 0);
1113     aNode.selectionEnd = aNode.selectionStart + sel_len;
1114 dpavlin 1 },
1115    
1116    
1117     output : function()
1118     {
1119     location.href = 'data:application/octet-stream,'+encodeURIComponent(this.textbox.value);
1120     },
1121    
1122    
1123     toggleEditMode : function(){
1124     this.deck.selectedIndex = this.deck.selectedIndex == 0 ? 1 : 0 ;
1125     this.setHash('edit', this.deck.selectedIndex == 0 ? '' : 'edit' );
1126     },
1127     toggleEvaMode : function(){
1128     var check = document.getElementById('toggleEva');
1129     if (this.canvas.getAttribute('eva') == 'true') {
1130     this.canvas.removeAttribute('eva');
1131     check.checked = false;
1132     }
1133     else {
1134     this.canvas.setAttribute('eva', true);
1135     check.checked = true;
1136     }
1137     this.setHash('eva', check.checked ? 'eva' : '' );
1138     },
1139    
1140    
1141    
1142     toggleAutoCruiseMode : function()
1143     {
1144     var autoCruise = document.getElementById('autoButton');
1145     if(!autoCruise.checked)
1146     this.startAutoCruise();
1147     else
1148     autoCruise.checked = false;
1149     },
1150     startAutoCruise : function()
1151     {
1152     var autoCruise = document.getElementById('autoButton');
1153     autoCruise.checked = true;
1154    
1155     if (this.autoCruiseTimer) {
1156     window.clearTimeout(this.autoCruiseTimer);
1157     }
1158     this.autoCruiseTimer = window.setTimeout(this.autoCruise, this.autoCruiseInterval);
1159     },
1160    
1161     changeAutoCruiseInterval : function(aInterval)
1162     {
1163     this.autoCruiseInterval = aInterval;
1164     this.startAutoCruise();
1165     },
1166    
1167     autoCruise : function()
1168     {
1169     var autoCruise = document.getElementById('autoButton');
1170     if (!autoCruise.checked) return;
1171    
1172     if(Presentation.offset == Presentation.data.length-1) {
1173     Presentation.home();
1174     }
1175     else {
1176     Presentation.forwardStep();
1177     }
1178     Presentation.autoCruiseTimer = window.setTimeout(arguments.callee, Presentation.autoCruiseInterval);
1179     },
1180     autoCruiseTimer : null,
1181    
1182    
1183    
1184     setHash : function(aKey, aValue)
1185     {
1186     aKey = String(aKey).toLowerCase();
1187     var hashArray = String(location.hash).replace(/^#/, '').toLowerCase().split(',');
1188    
1189     for (var i = hashArray.length-1; i > -1; i--)
1190     if (!hashArray[i] || hashArray[i].indexOf(aKey) == 0)
1191     hashArray.splice(i, 1);
1192    
1193     if (aValue) hashArray.push(aValue);
1194     hashArray.sort();
1195    
1196     location.hash = hashArray.length ? hashArray.join(',') : '' ;
1197     },
1198    
1199    
1200     showMontaKeyword : function(aNode) {
1201     if (aNode.getAttribute('monta-hidden') != 'true') return;
1202    
1203     aNode.setAttribute('monta-hidden', 'progress');
1204    
1205     window.setTimeout(this.showMontaKeywordCallback, 0, {
1206     position : -100,
1207     node : aNode,
1208     interval : this.showMontaKeywordTimeout/10
1209     });
1210     },
1211     showMontaKeywordCallback : function(aInfo) {
1212     if (aInfo.position >= aInfo.node.boxObject.width) {
1213     aInfo.node.setAttribute('monta-hidden', 'false');
1214     if (!Presentation.shownMontaLabels[Presentation.offset])
1215     Presentation.shownMontaLabels[Presentation.offset] = [];
1216     Presentation.shownMontaLabels[Presentation.offset][aInfo.node.getAttribute('label-id')] = true;
1217     return;
1218     }
1219    
1220     aInfo.position += (aInfo.node.boxObject.width/10);
1221     aInfo.node.setAttribute('style', 'background-position: '+aInfo.position+'px 0 !important;');
1222     window.setTimeout(arguments.callee, aInfo.interval, aInfo);
1223     },
1224    
1225    
1226    
1227     onPresentationClick : function(aEvent)
1228     {
1229     if (!this.isToolbarHidden)
1230     this.showHideToolbar();
1231    
1232     switch(aEvent.button)
1233     {
1234     case 0:
1235     switch (aEvent.target.getAttribute('class'))
1236     {
1237     case 'link-text':
1238     var uri = aEvent.target.getAttribute('href');
1239     if (uri) {
1240     window.open(uri);
1241     return;
1242     }
1243     break;
1244    
1245     case 'monta-label':
1246     if (aEvent.target.getAttribute('monta-hidden') == 'true') {
1247     this.showMontaKeyword(aEvent.target);
1248     aEvent.preventBubble();
1249     return;
1250     }
1251    
1252     default:
1253     break;
1254     }
1255     this.forward();
1256     document.documentElement.focus();
1257     break;
1258     case 2:
1259     this.back();
1260     document.documentElement.focus();
1261     break;
1262     default:
1263     break;
1264     }
1265     },
1266    
1267     onScrollerDragStart : function(){
1268     this.scroller.dragging = true;
1269     },
1270     onScrollerDragMove : function(){
1271     if (this.scroller.dragging)
1272     this.showPage(parseInt(this.scroller.getAttribute('curpos')));
1273     },
1274     onScrollerDragDrop : function(){
1275     this.onScrollerDragMove();
1276     this.scroller.dragging = false;
1277     },
1278    
1279     onIndicatorBarClick : function(aEvent)
1280     {
1281     var bar = this.indicatorBar;
1282     this.showPage(Math.round((aEvent.screenX - bar.boxObject.screenX) / bar.boxObject.width * this.data.length));
1283     },
1284     onIndicatorBarDragStart : function()
1285     {
1286     this.indicatorBar.dragging = true;
1287     },
1288     onIndicatorBarDragMove : function(aEvent)
1289     {
1290     var bar = this.indicatorBar;
1291     this.showPage(Math.round((aEvent.screenX - bar.boxObject.screenX) / bar.boxObject.width * this.data.length));
1292     },
1293     onIndicatorBarDragEnd : function(aEvent)
1294     {
1295     this.onIndicatorBarDragMove(aEvent);
1296     this.indicatorBar.dragging = false;
1297     },
1298    
1299     onEdit : function() {
1300     this.data = this.textbox.value;
1301     this.init();
1302     },
1303    
1304     onKeyPress : function(aEvent) {
1305     switch(aEvent.keyCode)
1306     {
1307     case aEvent.DOM_VK_BACK_SPACE:
1308     if (this.isPresentationMode) {
1309     aEvent.preventBubble();
1310     aEvent.preventDefault();
1311     Presentation.back();
1312     }
1313     break;
1314     default:
1315     break;
1316     }
1317     },
1318    
1319    
1320    
1321     handleEvent : function(aEvent)
1322     {
1323     switch (aEvent.type)
1324     {
1325     default:
1326     break;
1327    
1328     case 'resize':
1329     this.takahashi(); // redrwa
1330     break;
1331    
1332     case 'contextmenu':
1333     aEvent.stopPropagation();
1334     aEvent.preventCapture();
1335     aEvent.preventDefault();
1336     aEvent.preventBubble();
1337     break;
1338    
1339    
1340     case 'mouseup':
1341     this.dragStartX = -1;
1342     this.dragStartY = -1;
1343     if (this.indicatorBar.dragging)
1344     this.onIndicatorBarDragEnd(aEvent);
1345     break;
1346    
1347     case 'mousedown':
1348     if (this.dragStartX < 0) {
1349     this.dragStartX = aEvent.clientX;
1350     this.dragStartY = aEvent.clientY;
1351     }
1352     var box = this.indicatorBar.boxObject;
1353     if (!(aEvent.screenX < box.screenX ||
1354     aEvent.screenY < box.screenY ||
1355     aEvent.screenX > box.screenX+box.width ||
1356     aEvent.screenY > box.screenY+box.height))
1357     this.onIndicatorBarDragStart();
1358     break;
1359    
1360     case 'mousemove':
1361     this.checkShowHideToolbar(aEvent);
1362     if (this.indicatorBar.dragging) {
1363     this.onIndicatorBarDragMove(aEvent);
1364     return;
1365     }
1366     if (this.dragStartX > -1) {
1367     if (Math.abs(this.dragStartX-aEvent.clientX) > Math.abs(this.dragStartDelta) ||
1368     Math.abs(this.dragStartY-aEvent.clientY) > Math.abs(this.dragStartDelta)) {
1369     var event = document.createEvent('Events');
1370     event.initEvent('StartDragOnCanvas', false, true);
1371     this.canvas.dispatchEvent(event);
1372     }
1373     }
1374     break;
1375    
1376    
1377     }
1378     },
1379     dragStartX : -1,
1380     dragStartY : -1,
1381    
1382    
1383    
1384     onToolbarArea : false,
1385     toolbarHeight : 0,
1386     toolbarDelay : 300,
1387     toolbarTimer : null,
1388     isToolbarHidden : false,
1389     checkShowHideToolbar : function(aEvent) {
1390     if (this.scroller.dragging || this.preventToShowHideToolbar) return;
1391    
1392     this.onToolbarArea = (aEvent.clientY < this.toolbarHeight);
1393    
1394     if (this.isToolbarHidden == this.onToolbarArea) {
1395     if (this.toolbarTimer) window.clearTimeout(this.toolbarTimer);
1396     this.toolbarTimer = window.setTimeout('Presentation.checkShowHideToolbarCallback()', this.toolbarDelay);
1397     }
1398     },
1399     checkShowHideToolbarCallback : function() {
1400     if (this.isToolbarHidden == this.onToolbarArea)
1401     this.showHideToolbar();
1402     },
1403    
1404     toolbarAnimationDelay : 100,
1405     toolbarAnimationSteps : 5,
1406     toolbarAnimationInfo : null,
1407     toolbarAnimationTimer : null,
1408     showHideToolbar : function()
1409     {
1410     if (this.toolbarAnimationTimer) window.clearTimeout(this.toolbarAnimationTimer);
1411    
1412     this.toolbarAnimationInfo = { count : 0 };
1413     if (this.isToolbarHidden) {
1414     this.toolbarAnimationInfo.start = 0;
1415     this.toolbarAnimationInfo.end = this.toolbarHeight;
1416     }
1417     else {
1418     this.toolbarAnimationInfo.start = this.toolbarHeight;
1419     this.toolbarAnimationInfo.end = 0;
1420     }
1421     this.toolbarAnimationInfo.current = 0;
1422    
1423     this.toolbar.setAttribute('style', 'margin-top:'+(0-(this.toolbarHeight-this.toolbarAnimationInfo.start))+'px; margin-bottom:'+(0-this.toolbarAnimationInfo.start)+'px;');
1424    
1425     this.toolbarAnimationTimer = window.setTimeout('Presentation.animateToolbar()', this.toolbarAnimationDelay/this.toolbarAnimationSteps);
1426     },
1427     animateToolbar : function()
1428     {
1429     this.toolbarAnimationInfo.current += parseInt(this.toolbarHeight/this.toolbarAnimationSteps);
1430    
1431     var top, bottom;
1432     if (this.toolbarAnimationInfo.start < this.toolbarAnimationInfo.end) {
1433     top = this.toolbarHeight-this.toolbarAnimationInfo.current;
1434     bottom = this.toolbarAnimationInfo.current;
1435     }
1436     else {
1437     top = this.toolbarAnimationInfo.current;
1438     bottom = this.toolbarHeight-this.toolbarAnimationInfo.current;
1439     }
1440    
1441     top = Math.min(Math.max(top, 0), this.toolbarHeight);
1442     bottom = Math.min(Math.max(bottom, 0), this.toolbarHeight);
1443    
1444     this.toolbar.setAttribute('style', 'margin-top:'+(0-top)+'px; margin-bottom:'+(0-bottom)+'px');
1445    
1446     if (this.toolbarAnimationInfo.count < this.toolbarAnimationSteps) {
1447     this.toolbarAnimationInfo.count++;
1448     this.toolbarAnimationTimer = window.setTimeout('Presentation.animateToolbar()', this.toolbarAnimationDelay/this.toolbarAnimationSteps);
1449     }
1450     else
1451     this.isToolbarHidden = !this.isToolbarHidden;
1452     },
1453    
1454    
1455    
1456     get offset(){
1457     return this._offset;
1458     },
1459     set offset(aValue){
1460     this._offset = parseInt(aValue || 0);
1461     document.documentElement.setAttribute('lastoffset', this.offset);
1462     return this.offset;
1463     },
1464    
1465     get data(){
1466     if (!this._data) {
1467     // mozilla splits very long text node into multiple text nodes whose length is less than 4096 bytes.
1468     // so, we must concat all the text nodes.
1469     this.textbox.value = "";
1470     for (var i = 0; i < document.getElementById('builtinCode').childNodes.length; i++) {
1471     this.textbox.value += document.getElementById('builtinCode').childNodes[i].nodeValue;
1472     }
1473    
1474     this._data = this.textbox.value.split(/----+/);
1475     this.initData();
1476     }
1477    
1478     return this._data;
1479     },
1480     set data(aValue){
1481     this._data = aValue.split(/----+/);
1482     this.initData();
1483     return aValue;
1484     },
1485     initData : function()
1486     {
1487     var range = document.createRange();
1488     range.selectNodeContents(this.list);
1489     range.deleteContents();
1490    
1491    
1492     var regexp = [
1493     /^[\r\n\s]+/g,
1494     /[\r\n\s]+$/g,
1495     /(\r\n|[\r\n])/g
1496     ];
1497    
1498     var title;
1499     var titleRegExp = /^(TITLE::)([^\n]*)\n?/im;
1500     var header = '';
1501     var headerRegExp = /^(HEADER::)([^\n]*)\n?/im;
1502     var footer = '';
1503     var footerRegExp = /^(FOOTER::)([^\n]*)\n?/im;
1504     var chapter = '';
1505     var chapterRegExp = /^(CHAPTER::)([^\n]*)\n?/im;
1506     var lastChapter;
1507     var alignGlobal = 'center';
1508     var align;
1509     var alignRegExp = /^((GLOBAL-)?ALIGN::)(left|right|center|start|end)?\n?/im;
1510    
1511     var imageMatchResults;
1512     var imagesRegExp = this.makePhraseRegExp('%O%Oima?ge? +src="[^"]+" +width="[0-9]+" +height="[0-9]+"[^%C]*%C%C', 'gi');
1513     var imagesRegExp2 = this.makePhraseRegExp('%O%Oima?ge? +src="([^"]+)"', 'i');
1514     var image_src;
1515    
1516     var plainTextRegExp = this.makePhraseRegExp('(%O%O\#[^:]+:(.+)%C%C|%O%OEM:(.+)(:EM)?%C%C|%O%OPRE:(.+)(:PRE)?%C%C|%O%Oima?ge? +src="[^"]*"[^%C]+%C%C|%O%O([^\\|%C]+)(\\|[^%C]+)?%C%C|%O([^%O]+)%C)', 'gi');
1517    
1518     var dataObj;
1519     var i, j,
1520     max = this._data.length;
1521     var fragment = document.createDocumentFragment();
1522     var popup;
1523     for (i = 0; i < max; i++)
1524     {
1525     image_src = null;
1526     align = null;
1527    
1528     this._data[i] = this._data[i]
1529     .replace(regexp[0], '')
1530     .replace(regexp[1], '')
1531     .replace(regexp[2], '\n');
1532    
1533     while (titleRegExp.test(this._data[i])) {
1534     this._data[i] = this._data[i].replace(titleRegExp, '');
1535     if (String(RegExp.$1).toUpperCase() == 'TITLE::')
1536     title = RegExp.$2 || '' ;
1537     }
1538    
1539     while (headerRegExp.test(this._data[i])) {
1540     this._data[i] = this._data[i].replace(headerRegExp, '');
1541     if (String(RegExp.$1).toUpperCase() == 'HEADER::')
1542     header = RegExp.$2 || '' ;
1543     }
1544    
1545     while (footerRegExp.test(this._data[i])) {
1546     this._data[i] = this._data[i].replace(footerRegExp, '');
1547     if (String(RegExp.$1).toUpperCase() == 'FOOTER::')
1548     footer = RegExp.$2 || '' ;
1549     }
1550    
1551     while (chapterRegExp.test(this._data[i])) {
1552     this._data[i] = this._data[i].replace(chapterRegExp, '');
1553     if (String(RegExp.$1).toUpperCase() == 'CHAPTER::')
1554     chapter = RegExp.$2 || '' ;
1555     }
1556    
1557     while (alignRegExp.test(this._data[i])) {
1558     this._data[i] = this._data[i].replace(alignRegExp, '');
1559    
1560     align = (RegExp.$3 || '').toLowerCase();
1561     if (align == 'left')
1562     align = 'start';
1563     else if (align == 'right')
1564     align = 'end';
1565    
1566     if (String(RegExp.$1).toUpperCase() == 'GLOBAL-ALIGN::') {
1567     alignGlobal = align;
1568     align = null;
1569     }
1570     }
1571    
1572     imageMatchResults = this._data[i].match(imagesRegExp);
1573     if (imageMatchResults) {
1574     for (j = imageMatchResults.length-1; j > -1; j--)
1575     image_src = this.preloadImage(imageMatchResults[j].match(imagesRegExp2)[1]);
1576     }
1577    
1578     this._data[i] = {
1579     header : header,
1580     footer : footer,
1581     text : this._data[i].split('\n'),
1582     image : image_src,
1583     align : align || alignGlobal
1584     };
1585     this._data[i].plain = this._data[i].text
1586     .join('\n')
1587     .replace(plainTextRegExp, '$2$3$5$7$9')
1588     .split('\n');
1589     if (title !== void(0))
1590     this._data[i].title = title;
1591    
1592     this._data[i].chapter = chapter || title || '';
1593     if (lastChapter === void(0) ||
1594     lastChapter != this._data[i].chapter) {
1595     lastChapter = this._data[i].chapter;
1596    
1597     if (popup && popup.childNodes.length == 1) {
1598     fragment.removeChild(fragment.lastChild);
1599     fragment.appendChild(popup.removeChild(popup.lastChild));
1600     }
1601    
1602     popup = document.createElement('menupopup');
1603     fragment.appendChild(document.createElement('menu'));
1604     fragment.lastChild.setAttribute('label', this._data[i].chapter);
1605     fragment.lastChild.appendChild(popup);
1606     }
1607    
1608     popup.appendChild(document.createElement('menuitem'));
1609     popup.lastChild.setAttribute('type', 'radio');
1610     popup.lastChild.setAttribute('radiogroup', 'pages');
1611     popup.lastChild.setAttribute('label', (i+1)+': '+(
1612     (this._data[i].plain.join('') || this._data[i].text.join(' ')).replace(/\s+/g, ' ')
1613     ));
1614     popup.lastChild.setAttribute('value', i);
1615    
1616     // if (image_src) {
1617     // popup.lastChild.setAttribute('image', image_src);
1618     // popup.lastChild.setAttribute('class', 'menuitem-iconic');
1619     // }
1620     }
1621    
1622     if (fragment.childNodes.length == 1) {
1623     range.selectNodeContents(fragment.firstChild.firstChild);
1624     fragment = range.extractContents();
1625     }
1626     this.list.appendChild(fragment);
1627    
1628     range.detach();
1629    
1630    
1631     this.shownMontaLabels = [];
1632     },
1633    
1634     preloadImage : function(aURI)
1635     {
1636     if (aURI in this.imageRequests) return;
1637    
1638     if (aURI.indexOf('http://') < 0 &&
1639     aURI.indexOf('https://') < 0)
1640     aURI = this.dataFolder+aURI;
1641    
1642     this.imageRequests[aURI] = new XMLHttpRequest();
1643     try {
1644     this.imageRequests[aURI].open('GET', aURI);
1645     this.imageRequests[aURI].onload = function() {
1646     Presentation.imageRequests[aURI] = null;
1647     };
1648     this.imageRequests[aURI].send(null);
1649     }
1650     catch(e) {
1651     this.imageRequests[aURI] = null;
1652     }
1653     return aURI;
1654     },
1655     imageRequests : {},
1656    
1657    
1658     get isPresentationMode(){
1659     return (this.deck.selectedIndex == 0);
1660     },
1661    
1662    
1663     get dataPath(){
1664     if (!this._dataPath)
1665     this.dataPath = String(location.href).replace(/#.+$/, '');
1666     return this._dataPath;
1667     },
1668     set dataPath(aValue){
1669     var oldDataPath = this._dataPath;
1670     this._dataPath = aValue;
1671     if (oldDataPath != aValue) {
1672     this._dataFolder = this._dataPath.split('?')[0].replace(/[^\/]+$/, '');
1673     }
1674     return this._dataPath;
1675     },
1676    
1677     get dataFolder(){
1678     if (!this._dataFolder)
1679     this.dataPath = this.dataPath;
1680     return this._dataFolder;
1681     },
1682     set dataFolder(aValue){
1683     this._dataFolder = aValue;
1684     return this._dataFolder;
1685     },
1686    
1687     readParameter : function() {
1688     if (location.search || location.hash) {
1689     var param = location.search.replace(/^\?/, '');
1690    
1691     if (location.hash.match(/page([0-9]+)/i) ||
1692     param.match(/page=([0-9]+)/i))
1693     this.offset = parseInt(RegExp.$1)-1;
1694    
1695     if (location.hash.match(/edit/i) ||
1696     param.match(/edit=(1|true|yes)/i))
1697     this.toggleEditMode();
1698    
1699     if (location.hash.match(/eva/i) ||
1700     param.match(/eva=(1|true|yes)/i))
1701     this.toggleEvaMode();
1702    
1703     if (location.hash.match(/timer(\d+)\-(\d+)/i))
1704     this.setTimer(RegExp.$1, RegExp.$2);
1705    
1706     if (param.match(/(style|css)=([^&;]+)/i)) {
1707     var style = unescape(RegExp.$2);
1708     var pi = document.createProcessingInstruction('xml-stylesheet', 'href="'+style+'" type="text/css"');
1709     document.insertBefore(pi, document.documentElement);
1710     }
1711    
1712     if (param.match(/data=([^&;]+)/i)) {
1713     var path = unescape(RegExp.$1);
1714     this.dataPath = path;
1715     var request = new XMLHttpRequest();
1716     request.open('GET', path);
1717     request.onload = function() {
1718     Presentation.textbox.value = request.responseText;
1719     Presentation.data = Presentation.textbox.value;
1720     Presentation.init();
1721     };
1722     request.send(null);
1723     return false;
1724     }
1725     }
1726     return true;
1727     },
1728    
1729    
1730    
1731     resetTimer : function()
1732     {
1733     if (this.timerTimer) {
1734     window.clearInterval(this.timerTimer);
1735     this.timerTimer = null;
1736     }
1737     this.timer.setAttribute('value', 0);
1738     this.timer.setAttribute('collapsed', true);
1739     this.setHash('timer', '');
1740     },
1741     setTimer : function(aStart, aEnd)
1742     {
1743     var now = (new Date()).getTime();
1744     if (aStart === void(0) || aEnd === void(0)) {
1745 dpavlin 2 var rest = prompt('Remaining Time (minits)');
1746     if (rest == '') {
1747     this.resetTimer();
1748 dpavlin 1 return;
1749 dpavlin 2 }
1750 dpavlin 1 else {
1751     rest = Number(rest);
1752 dpavlin 2 if (!rest || isNaN(rest)) return;
1753 dpavlin 1 }
1754    
1755     rest = Math.abs(rest);
1756     this.timerStart = now;
1757     this.timerEnd = this.timerStart + (rest * 60000);
1758     }
1759     else {
1760     aStart = Number(aStart);
1761     aEnd = Number(aEnd);
1762     if (isNaN(aStart) || isNaN(aEnd)) return;
1763    
1764     this.timerStart = Math.min(aStart, aEnd);
1765     this.timerEnd = Math.max(aStart, aEnd);
1766    
1767     if (this.timerStart >= now || this.timerEnd <= now) return;
1768     }
1769    
1770     this.resetTimer();
1771    
1772     this.timer.removeAttribute('collapsed');
1773     this.setHash('timer', 'timer'+this.timerStart+'-'+this.timerEnd);
1774    
1775     if (now != this.timerStart)
1776     this.updateTimer(this);
1777    
1778     window.setInterval(this.updateTimer, Math.min(this.timerUpdatingInterval, (this.timerEnd-this.timerStart)/(this.data.length*2)), this);
1779     },
1780     updateTimer : function(aThis)
1781     {
1782     var now = (new Date()).getTime();
1783     if (now >= aThis.timerEnd) {
1784     aThis.resetTimer();
1785     aThis.timer.setAttribute('value', 100);
1786     aThis.timer.removeAttribute('collapsed');
1787     aThis.setHash('timer', '');
1788     }
1789     else {
1790     var value = parseInt(((now - aThis.timerStart) / (aThis.timerEnd - aThis.timerStart)) * 100);
1791     aThis.timer.setAttribute('value', value);
1792     }
1793     },
1794     timerStart : 0,
1795     timerEnd : 0,
1796     timerTimer : null
1797    
1798     };
1799    
1800    
1801    
1802    
1803    
1804     var StrokeService = {
1805     className : 'stroke-dot',
1806     dragStartDelta : 8,
1807     lineColor : 'red',
1808     lineWidth : 3,
1809    
1810     initialized : false,
1811    
1812    
1813     mode : null,
1814     canvas : null,
1815     canvasContext : null,
1816     startX : -1,
1817     startY : -1,
1818    
1819     init : function(aCanvas)
1820     {
1821     this.initialized = true;
1822    
1823     this.canvas = aCanvas;
1824    
1825     var canvas = document.createElementNS('http://www.w3.org/1999/xhtml', 'canvas');
1826     this.canvas.appendChild(canvas);
1827     if (!('getContext' in canvas) || !canvas.getContext) {
1828     this.canvas.removeChild(canvas);
1829     this.mode = 'box';
1830     }
1831     else {
1832     this.canvas = canvas;
1833     this.canvasContext = this.canvas.getContext('2d');
1834     this.mode = 'canvas';
1835     }
1836    
1837     document.documentElement.addEventListener('PresentationRedraw', this, false);
1838     window.addEventListener('resize', this, false);
1839     this.canvas.addEventListener('mouseup', this, false);
1840     this.canvas.addEventListener('mousedown', this, false);
1841     this.canvas.addEventListener('mousemove', this, false);
1842    
1843     this.canvas.addEventListener('click', this, false);
1844     this.canvas.addEventListener('dblclick', this, false);
1845    
1846     this.clear();
1847     },
1848    
1849     destroy : function()
1850     {
1851     document.documentElement.removeEventListener('PresentationRedraw', this, false);
1852     window.removeEventListener('resize', this, false);
1853     this.canvas.removeEventListener('mouseup', this, false);
1854     this.canvas.removeEventListener('mousedown', this, false);
1855     this.canvas.removeEventListener('mousemove', this, false);
1856     this.canvas.removeEventListener('click', this, false);
1857    
1858     this.cliclableNodesManager = null;
1859     this.canvas = null;
1860    
1861     this.initialized = false;
1862     },
1863    
1864    
1865    
1866     handleEvent : function(aEvent)
1867     {
1868     switch(aEvent.type)
1869     {
1870     default:
1871     break;
1872    
1873     case 'mouseup':
1874     this.finish(aEvent);
1875     this.startX = -1;
1876     this.startY = -1;
1877     window.setTimeout('StrokeService.preventToSendClickEvent = false', 10);
1878     break;
1879    
1880     case 'mousedown':
1881     if (this.startX < 0) {
1882     this.startX = aEvent.clientX;
1883     this.startY = aEvent.clientY;
1884     }
1885     break;
1886    
1887     case 'mousemove':
1888     if (this.startX > -1 && !this.active) {
1889     if (Math.abs(this.startX-aEvent.clientX) > Math.abs(this.dragStartDelta) ||
1890     Math.abs(this.startY-aEvent.clientY) > Math.abs(this.dragStartDelta)) {
1891     this.start(aEvent, this.startX, this.startY);
1892     this.preventToSendClickEvent = true;
1893     }
1894     }
1895     else
1896     this.trace(aEvent);
1897    
1898     break;
1899    
1900     case 'PresentationRedraw':
1901     case 'resize':
1902     this.clear();
1903     break;
1904    
1905     case 'click':
1906     if (this.preventToSendClickEvent) {
1907     aEvent.stopPropagation();
1908     aEvent.preventCapture();
1909     aEvent.preventDefault();
1910     aEvent.preventBubble();
1911     this.preventToSendClickEvent = false;
1912     }
1913     else if (this.cliclableNodesManager && this.cliclableNodesManager.clickableNodes) {
1914     var nodes = this.cliclableNodesManager.clickableNodes;
1915     var max = nodes.length;
1916     var x, y, width, height
1917     for (var i = 0; i < max; i++)
1918     {
1919     if (nodes[i].boxObject) {
1920     x = nodes[i].boxObject.x;
1921     y = nodes[i].boxObject.y;
1922     width = nodes[i].boxObject.width;
1923     height = nodes[i].boxObject.height;
1924     }
1925     else {
1926     x = nodes[i].offsetLeft;
1927     y = nodes[i].offsetTop;
1928     width = nodes[i].offsetWidth;
1929     height = nodes[i].offsetHeight;
1930     }
1931     if (aEvent.clientX < x ||
1932     aEvent.clientX > x+width ||
1933     aEvent.clientY < y ||
1934     aEvent.clientY > y+height)
1935     continue;
1936    
1937     var event = document.createEvent('MouseEvents');
1938     event.initMouseEvent(
1939     aEvent.type, aEvent.canBubble, aEvent.cancelable, aEvent.view,
1940     aEvent.detail,
1941     aEvent.screenX, aEvent.screenY, aEvent.clientX, aEvent.clientY,
1942     aEvent.ctrlKey, aEvent.altKey, aEvent.shiftKey, aEvent.metaKey,
1943     aEvent.button,
1944     aEvent.relatedTarget
1945     );
1946     nodes[i].dispatchEvent(event);
1947     break;
1948     }
1949     }
1950     break;
1951     }
1952     },
1953     preventToSendClickEvent : false,
1954    
1955    
1956    
1957     start : function(aEvent, aX, aY)
1958     {
1959     this.active = true;
1960     this.trace(aEvent, aX, aY);
1961     },
1962    
1963     finish : function(aEvent)
1964     {
1965     if (!this.active) return;
1966     this.trace(aEvent);
1967     this.finishStroke();
1968     },
1969    
1970     trace : function(aEvent, aX, aY)
1971     {
1972     if (!this.active) return;
1973     this.addPoint((aX === void(0) ? aEvent.clientX : aX ), (aY === void(0) ? aEvent.clientY : aY ));
1974     },
1975    
1976    
1977     finishStroke : function()
1978     {
1979     this.active = false;
1980     this.lastX = -1;
1981     this.lastY = -1;
1982     },
1983    
1984    
1985     addPoint : function(aX, aY)
1986     {
1987     if (this.lastX != -1)
1988     this.drawLine(this.lastX, this.lastY, aX, aY);
1989     else
1990     this.drawDot(aX, aY);
1991    
1992     this.lastX = aX;
1993     this.lastY = aY;
1994     },
1995    
1996    
1997    
1998     clear : function()
1999     {
2000     this.active = false;
2001     this.lastX = -1;
2002     this.lastY = -1;
2003    
2004     if (this.mode == 'canvas') {
2005     if (this.canvas.lastWindowWidth != window.innerWidth ||
2006     this.canvas.lastWindowHeight != window.innerHeight) {
2007     this.canvas.width = this.canvas.parentNode.boxObject.width-2;
2008     this.canvas.height = this.canvas.parentNode.boxObject.height-2;
2009    
2010     this.canvas.lastWindowWidth = window.innerWidth;
2011     this.canvas.lastWindowHeight = window.innerHeight;
2012     }
2013     this.canvasContext.clearRect(0, 0, this.canvas.width, this.canvas.height);
2014     this.canvasContext.strokeStyle = this.lineColor;
2015     this.canvasContext.lineWidth = this.lineWidth;
2016     }
2017     else {
2018     var dotes = this.canvas.getElementsByAttribute('class', this.className);
2019     if (!dotes.length) return;
2020    
2021     var range = document.createRange();
2022     range.selectNodeContents(this.canvas);
2023     range.setStartBefore(dotes[0]);
2024     range.setEndAfter(dotes[dotes.length-1]);
2025     range.deleteContents();
2026     range.detach();
2027     }
2028     },
2029    
2030     drawDot : function(aX, aY, aParent)
2031     {
2032     if (this.mode == 'canvas') {
2033     this.canvasContext.strokeRect(aX, aY, 0, 0);
2034     this.canvasContext.stroke();
2035     }
2036     else {
2037     var dot = document.createElement('spacer');
2038     dot.setAttribute('style', 'left:'+aX+'px; top:'+aY+'px');
2039     dot.setAttribute('class', this.className);
2040     (aParent || this.canvas).appendChild(dot);
2041     }
2042     },
2043     drawLine : function(aX1, aY1, aX2, aY2)
2044     {
2045     if (aX1 == aX2 && aY1 == aY2) return;
2046    
2047    
2048     if (this.mode == 'canvas') {
2049     this.canvasContext.beginPath();
2050     this.canvasContext.moveTo(aX1, aY1);
2051     this.canvasContext.lineTo(aX2, aY2);
2052     /*
2053     this.canvasContext.bezierCurveTo(
2054     parseInt(aX1+((aX2-this.lastX)*0.3)), parseInt(aY1+((aY2-this.lastY)*0.3)),
2055     parseInt(aX1+((aX2-this.lastX)*0.6)), parseInt(aY1+((aY2-this.lastY)*0.6)),
2056     aX2, aY2
2057     );
2058     */
2059     this.canvasContext.closePath();
2060     this.canvasContext.stroke();
2061     }
2062     else {
2063     var x_move = aX2 - aX1;
2064     var y_move = aY2 - aY1;
2065     var x_diff = x_move < 0 ? 1 : -1;
2066     var y_diff = y_move < 0 ? 1 : -1;
2067    
2068     var fragment = document.createDocumentFragment();
2069     if (Math.abs(x_move) >= Math.abs(y_move)) {
2070     for (var i = x_move; i != 0; i += x_diff)
2071     this.drawDot(aX2 - i, aY2 - Math.round(y_move * i / x_move), fragment);
2072     }
2073     else {
2074     for (var i = y_move; i != 0; i += y_diff)
2075     this.drawDot(aX2 - Math.round(x_move * i / y_move), aY2 - i, fragment);
2076     }
2077     this.canvas.appendChild(fragment);
2078     }
2079     }
2080     };
2081    
2082    
2083    
2084    
2085    
2086     var StrokablePresentationService = {
2087    
2088     id : 'stroke-canvas-box',
2089    
2090     strokeService : null,
2091     cliclableNodesManager : null,
2092     canvasContainer : null,
2093     canvas : null,
2094    
2095     autoStart : false,
2096    
2097     init : function(aPresentation, aStrokeService)
2098     {
2099     this.cliclableNodesManager = aPresentation;
2100     this.strokeService = aStrokeService;
2101     this.canvasContainer = document.getElementById('canvas').firstChild;
2102     this.check = document.getElementById('penButton');
2103    
2104     document.documentElement.addEventListener('StartDragOnCanvas', this, false);
2105     document.documentElement.addEventListener('PresentationRedraw', this, false);
2106     },
2107    
2108     toggle : function(aEnable)
2109     {
2110     if (aEnable)
2111     this.start();
2112     else
2113     this.end();
2114     },
2115    
2116     start : function()
2117     {
2118     if (!this.strokeService || !this.canvasContainer) return;
2119    
2120     this.strokeService.cliclableNodesManager = this.cliclableNodesManager;
2121     var box = document.createElement('vbox');
2122     box.setAttribute('flex', 1);
2123     box.setAttribute('id', this.id);
2124     this.canvas = this.canvasContainer.appendChild(box);
2125     this.strokeService.init(this.canvas);
2126    
2127     this.canvas.addEventListener('dblclick', this, false);
2128     },
2129    
2130     end : function()
2131     {
2132     this.canvas.removeEventListener('dblclick', this, false);
2133    
2134     this.strokeService.destroy();
2135     this.canvasContainer.removeChild(this.canvas);
2136     this.canvas = null;
2137     },
2138    
2139     handleEvent : function(aEvent)
2140     {
2141     switch (aEvent.type)
2142     {
2143     default:
2144     break;
2145    
2146     case 'StartDragOnCanvas':
2147     if (!this.check.checked) {
2148     this.toggleCheck();
2149     this.strokeService.startX = Presentation.dragStartX;
2150     this.strokeService.startY = Presentation.dragStartY;
2151    
2152     this.autoStart = true;
2153     }
2154     break;
2155    
2156     case 'PresentationRedraw':
2157     if (this.autoStart && this.check.checked) {
2158     this.autoStart = false;
2159     this.toggleCheck();
2160     }
2161     break;
2162    
2163     case 'dblclick':
2164     if (this.canvas)
2165     this.end();
2166     break;
2167     }
2168     },
2169    
2170     toggleCheck : function()
2171     {
2172     var enable = !this.check.checked;
2173     this.toggle(enable);
2174     this.check.checked = enable;
2175    
2176     this.autoStart = false;
2177     }
2178    
2179     };
2180    
2181    
2182    
2183    
2184     function init()
2185     {
2186     window.removeEventListener('load', init, false);
2187    
2188     Presentation.init();
2189     StrokablePresentationService.init(Presentation, StrokeService);
2190     }
2191     window.addEventListener('load', init, false);
2192    
2193    
2194     ]]></script>
2195    
2196     </page>

Properties

Name Value
svn:eol-style CRLF

  ViewVC Help
Powered by ViewVC 1.1.26