1 <?xml version="1.0" encoding="UTF-8"?>
3 高橋メソッドなプレゼンツール in XUL リターンズ
5 http://piro.sakura.ne.jp/
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
14 <!-- ***** BEGIN LICENSE BLOCK *****
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/
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
27 - The Original Code is the Takahashi-Method-based Presentation Tool
30 - The Initial Developer of the Original Code is SHIMODA Hiroshi.
31 - Portions created by the Initial Developer are Copyright (C) 2005-2007
32 - the Initial Developer. All Rights Reserved.
34 - Contributor(s): SHIMODA Hiroshi <piro@p.club.ne.jp>
35 - dynamis <dynamis@mozilla-japan.org>
36 - matobaa <matobaa@lily.freemail.ne.jp>
38 - ***** END LICENSE BLOCK ***** -->
40 <?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
41 <?xml-stylesheet href="#builtinStyle" type="text/css"?>
43 <page xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
45 xmlns:html="http://www.w3.org/1999/xhtml"
47 onkeypress="Presentation.onKeyPress(event);">
49 <!-- Built-in Content -->
50 <html:textarea id="builtinCode" style="visibility: collapse">
51 TITLE::Moose in the wild
69 theres an explanation on the cpan page... It's a ref to Larry talking about perl as a postmodern language... let's move on.
80 by 'borrowing' features
85 - I do not really know these that well so I can not really speak to there cribbed features
91 %%%%IMG src="http://bp2.blogger.com/_dH0q9hvpVHg/R86WXUE5b2I/AAAAAAAABh4/N9A5fc5KPnI/s320/thumb.jpg" height='*' width='*' %%%%
99 For me the biggest thing was to strictly wrap my head on how OO was ~meant~ to be.
100 I have an art school background, I missed out on all the CS OO classes.
101 I had been thinking of OO backwards
110 My pre-moose days had a really hard time with OO. I understood the basics
111 like a $car has $wheels, ect. But things were very fuzzy in my head.
112 It's not really wrong, per say, but it's just not a very clear way to see the world.
113 Basically my OO world view said that $car $wheels were completely different from $bike $wheels
120 Moose really flipped things for me.
121 It forced me to think of objects as attributes and subs that modify them.
129 It made me focus on the $wheels as the thing that defines the $car or the $bike.
130 It's easy to talk about but, but for me, it was a completely different way to think about my code.
138 a quick blow thru on what features you will be hearing more about
150 first, simple things, like why should some one opt-in for the proper way to do something?
159 ever get tired of writing the same 7 lines of code, now you don't have to.
166 once you define an attribute, why not have a getter/setter built for you?
172 Extend the basic perl data types to be much more specific
178 Hello eye opeining experence.
182 ... ehh, not convinced
183 I'd have to see it in action.
185 don't worry it took me a while to wrap my head around all of this stuff too
189 what does Moose look like?
191 let's look at some code
199 really simple example, but it will illustrate the general overview.
222 print $bullwinkle->name;
226 Animal::Moose->new( name => 'Skippy' )
231 yup thats what we want, now let's take a look at what Animal::Moose looks like.
237 package Animal::Moose;
242 my ($class, %opts) = @_;
244 name => $opts{name} || 'Bullwinkle',
246 return bless $self, $class;
250 my ($self, $new_name) = @_;
251 if ( defined $new_name ) {
252 $self->{name} = $new_name;
254 return $self->{name};
265 package Animal::Moose;
271 default => 'Bullwinkle',
276 see no constructor, no strict, no warnings
277 if you want show the test
284 ok So there you have it... Moose in the... err... code.
285 So, what is this 'has' thing? Moose runs with the
286 theory that an object is a collection of attributes.
287 A moose has a name, thus name is an attribute.
297 has "attribute name" => (
298 #attribute definition
302 an attribute has a name, and it has to define something in some manner.
303 Here are the definitions that I use the most:
304 I think that these first three are required.
314 if you need something to be updated, then it's 'rw'.
315 If it will never changed once set, it's 'ro'.
316 really this just specifies what accessors are built for you.
326 isa => 'CGI::Simple',
329 let's moose know what type of thing to expect to be here
330 we'll get in to types a bit more later
338 default => sub{ [] },
339 default => sub{ {} },
342 scalars can just be specified any thing else needs to be wrapped in a sub {}
351 If this attribute is not specified on construction then die
360 I use this mostly as a timing safety net, IE if one attribute needs another to be built, then make the second one lazy.
361 Lazy attributes get built right be fore they are used, so this is also a really good way to keep your code 'lite' by
362 setting things up so that you only use what you really need.
366 %%%% there's more | http://search.cpan.org/~stevan/Moose-0.38/lib/Moose.pm %%%%
379 Moose's type structure is basically a built-in assertion for the content of an attribute.
383 they make my code die!
385 This is super handy as Moose is making sure that you know what your dealing with,
386 you do not have to have everything check to make sure that $input_data is going to be > 0 or what ever.
387 At first this was really annoying for me. As I was porting my instal run of Search things would always die.
388 it was another symptom of bad code, Again Moose is forcing me to think about what I really want, and staying on task.
416 %%%% more info on types | http://search.cpan.org/~stevan/Moose-0.38/lib/Moose/Util/TypeConstraints.pm %%%%
418 There are many types that Moose provides by default, mostly there an extension of the existing perl data objects.
422 ... they're missing one ...
424 but theres more... You can write your own.
428 ... so make your own ...
430 Here are some examples from work, ignore the role bit for now.
435 package PowellsData::Types::Web;
437 use Moose::Util::TypeConstraints;
442 m/^(Apache2::Request|CGI::Simple)$/
446 '(%s) needs to be an Apache2::Request
447 object or a CGI::Simple object and
455 OK so this is from the Search code... There are a many ways to access this code... many are web based, let's specify that the object that holds our CGI session is of the right type and not just some weird chunk of data.
456 So as you can see, it's very much an assertion... is this thing the right type. ( I forget why I'm using ref vs isa there might be a reason, there might not be).
457 A type has a {where} block that returns 0|1, if one were good, if 0 bail,
458 you can also specify a {message} if you would like to gussy up your error log with more helpful errors.
467 package PowellsData::Types::SQL;
469 use Moose::Util::TypeConstraints;
474 $_ =~ m/\bSELECT\b.+\bFROM\b/i
481 m/\bINSERT\b.+(?:\bINTO\b)?.+\b(?:VALUES|SET|SELECT)\b/i
487 $_ =~ m/\bUPDATE\b.+\bSET\b/i
493 $_ =~ m/\bDELETE\b.+\bFROM\b/i };
496 => as q{SQL_Select|SQL_Insert|SQL_Update|SQL_Delete} ;
499 In this example, I just built out some regexes that sit on top of the string type.
500 So if you were to pass in an arrayref for example, these would die long before the regex were to be checked.
502 - subtypes just extend an existing type (as)
503 - where is the same, something that returns (0|1)
504 - you can extend any other defined type/subtype and even group them (SQL)
519 Roles are another thing that blew my mind. At it's most basic you can think of a role as
520 a include in to the current file.
525 1) abstract the common
527 Before we really jump to some example, theres basically two
528 ways that I find my self using roles. The first is as
529 an abstarction layer to something very common.
535 package PowellsData::Setup::Database;
540 has d => ( is => 'rw',
543 default => sub{ my $d = _dbiconnect('current');
544 $d->{mysql_auto_reconnect} = 1;
545 $d->do("SET NAMES utf8");
555 So this basically sets up a database handle for us. It's an abstraction of
556 DBHost, a Powells rapper around DBI that manages what server to use and
557 what user:password to use. This layer does some minor set up on top of that.
558 We check the type, we are saying that this is required and default will build
559 one for us if there was not passed in at construction.
561 - use Moose::Role is the only thing that has changed from a 'Moose' Object.
566 now in our code just say:
568 package My::Bad::DB::Example;
571 with q{PowellsData::Setup::Database};
574 my ($self, $query) = @_;
575 return $self->d->do($query);
579 this one line now gives me an attribute 'd' that hast to be a 'DBI::db',
580 everything gets set up for us, it's all in the role. So now I never have to
581 remember specifics, I just get a DB handle.
582 it's like I had written all of that code in-line.
587 2) big idea as small chunks
589 the other way that I often find my self using roles is to really
590 lean on on that 'include' nature. Because the code ends up as though
591 its one big file, then I take large files and 'break-them-up'.
592 It's got it's pros and cons, First why I like this:
600 In that set up my DB example, we only had to write only the part
601 about setting up the DB handle.
606 package PowellsData::Setup::Database;
611 has d => ( is => 'rw',
614 default => sub{ my $d = _dbiconnect('current');
615 $d->{mysql_auto_reconnect} = 1;
616 $d->do("SET NAMES utf8");
626 Search is web based, but in this code we don't care, we can focus just on one
627 simple part of a very complex problem.
634 with roles you just get stuff for 'free', it's almost like magic. Santa just showed up and you
635 got a DB handle. ~Woo~.
640 with q{PowellsData::Setup::Database};
644 use Some::Other::Magic::DB::Manager q{d};
647 when you set up a role next to the use qw{import} way of things, you can maintain context
648 you are stating the origin of things. Theres so many times that ack has saved me time because
649 I have completely lost track where method or attribute is.
654 group logical actions
656 If I take advantage of the Roles as includes then I can take that section of code
657 that does that one thing and pull it off to it's own file, even if it's only used
663 package Search::Runtime::FPSearch::Section;
665 use Carp::Assert::More;
668 Search::Runtime::Common
669 PowellsData::Setup::Database
670 PowellsData::Tools::String
675 my ( $self, $needle) = @_;
676 if ( $self->_has_valid_value($needle) ) {
677 my $needles = $self->array_of_words( lc( $needle ) );
678 my $query = _query($needles);
679 my $r = $self->d->selectall_arrayref($query, { Slice => {} }, @$needles, @$need
681 my $score_limit = scalar( @$needles);
683 if ( scalar( @$r ) > 0 ) {
686 foreach my $s ( @$r ) {
687 if ( $s->{score} >= $score_limit ) {
688 push @$out, {$s->{name} => $s->{link}};
698 assert_listref($needles);
701 SELECT DISTINCT X.MAJORSec as name,
702 CONCAT( 'psection/',X.HTML ) AS link,
708 count(SWC.word_id) AS score,
712 FROM Sections.section_word_category SWC
713 JOIN Sections.category C
714 ON (SWC.category_id = C.id)
715 JOIN Sections.section_words SW
716 ON (SWC.word_id = SW.id)
717 WHERE SW.word IN (%s)
718 AND C.MAJORSec NOT LIKE '%%Reader eBook%%'
719 AND C.MAJORSec NOT LIKE '%%sale%%'
720 AND C.MAJORSec != '$7 or Less'
721 AND C.MAJORSec != 'At the Movies'
722 AND C.MAJORSec != 'New Arrivals'
723 AND C.MAJORSec != 'Coming Soon!'
724 AND SWC.type = 'major'
731 SELECT CONCAT( Y.MAJORSec, ' - ', Y.MINORSec ) as name,
732 CONCAT( 'subsecti on/', Y.sectionkey, '.html' ) AS link,
738 count(SWC.word_id) AS score,
742 FROM Sections.section_word_category SWC
743 JOIN Sections.category C
744 ON (SWC.category_id = C.id)
745 JOIN Sections.section_words SW
746 ON (SWC.word_id = SW.id)
747 WHERE SW.word IN (%s)
748 AND C.MAJORSec NOT LIKE '%%Reader eBook%%'
749 AND C.MAJORSec NOT LIKE '%%sale%%'
750 AND C.MAJORSec != '$7 or Less'
751 AND C.MAJORSec != 'At the Movies'
752 AND C.MAJORSec != 'New Arrivals'
753 AND C.MAJORSec != 'Coming Soon!'
754 AND SWC.type = 'minor'
760 ORDER BY type = 'major' DESC , score DESC
771 I don't know if this is readable but what is going on here is a section search. I take in
772 a $needle and then build up a query based on that $needle and try and find it in the DB.
773 This code only does one specific thing, So I pulled it out. It could have become it's own object
774 but it really doesn't need to hold on to any thing, it just needs a DB handle and a needle, this
775 a quick handy way to keep things grouped by logical tasks.
783 As cool as this is, you really need to be careful, things can get really messy really fast.
784 Here let's just take a quick gander at the dir for Search:
789 benh@noodleboy:~/svn/lib_common/dev/Search$ tree .
791 |-- CompleteResults.pm
792 |-- CompleteResults_distance.pm
798 | |-- CompleteResults
800 | | |-- LimitedQuery.pm
804 | | `-- Restrictions.pm
805 | |-- CompleteResults.pm
811 | | |-- PublisherKw.pm
812 | | |-- PublisherKwOld.pm
814 | | |-- SearchCacheClasses.pm
815 | | |-- SearchCacheCounter.pm
816 | | |-- SearchCacheMeta.pm
817 | | |-- SearchCacheParams.pm
818 | | |-- SearchCacheResults.pm
819 | | |-- SearchCacheSections.pm
821 | | |-- SearchKwOld.pm
823 | | |-- SearchTitle.pm
824 | | |-- SearchTitleOld.pm
825 | | |-- SectionsKw.pm
826 | | |-- SectionsKwOld.pm
862 | `-- runsearch_lite.pl
867 Lets see what is really an object in all of this...
872 Runtime is called from Search Core, it extends Default, but everything else is a role, it is just included.
873 I've tried to keep things organized, but roles are like kudzu. So just like most things, with great power comes great responsibly.
874 This is one of the biggest reasons I've been in some level of constant refactoring of this code base.
881 Because there actions in separate files it's really handy to be able to hand out parts of the puzzle
882 to other people and then just come back with a big working object. It's a dream that I have at work,
883 so far not much has come of it.
891 Moose roles are only use-able via moose. You can write mini-object thats collect your roles,
892 It's not ~hard~ to get around, just need to mention it though. Also to note, Moose is not the only
893 way to implement 'roles', check cpan for 'traits' or 'mix-ins'. There all kinda the same thing
897 there's a lot more to roles
898 %%%% CookBook Example | http://search.cpan.org/~stevan/Moose-0.38/lib/Moose/Cookbook/Recipe6.pod %%%%
902 how we doing on time?
908 ** possible filler if needed **
912 how to extend a Moose?
914 let's see how am I doing on time... cause I can just skip this if I'm over
927 Basically does the same thing but makes sure that all the Moose stuff stays in the right place
928 in the @ISA stack. Also I have not played with it, but extends will take an array of parents
929 and should handle any weird multiple inheritance juju for you.
938 I still have not completely wrapped my head around what bits of Moose are compile time
939 and what happens at run time. Theres so many layers to things.
940 There are often times that you will find your self missing that constructor.
941 just need something to be run at creation time?
947 #... code to be run on create
955 sadly no, this is not a free lunch. There is a hit on performance, I have not done any
956 testing, no hard number. Though I have not really noticed any significant hit. Though
957 this is mostly sidelined as Search runs in mod_perl so things only get built once.
958 There are all sorts of warnings all over the place about not using Moose for a
959 simple CGI.pm application.
966 Things that I'm still learning
967 - meta, it all just perl
969 - triggers, almost a method modifier
970 - method modification events
974 - unimport ( 'no moose', when to use? )
975 - mostly just a way to clean up things
976 - %%%% namespace::clean | http://search.cpan.org/~phaylon/namespace-clean-0.08/lib/namespace/clean.pm %%%%
977 - insure that there are no funky issues down stream
979 - override, makes sense just have not run in to a need to use
982 - Moose specific testing
983 - mostly how to test roles by them self?
984 - %%%% Test::Moose | http://search.cpan.org/~stevan/Moose-0.38/lib/Test/Moose.pm %%%%
985 - %%%% Test::Moose::MockObjectCompile | http://search.cpan.org/~zaphar/Test-Moose-MockObjectCompile-0.2.1/lib/Test/Moose/MockObjectCompile.pm %%%%
990 * a perl object system
991 * meta syntax for object/class declaration
994 * Ride the Moose (code in "the real world")
995 * Constructors for free
997 * under the hood - the meta() method
998 * getters and setters
1000 * possible name space collisions
1002 * timing issues ( lazy => 1 )
1004 * things die if they are wrong, just like they should (assertion)
1007 * Love the Moose (techniques and practices)
1008 * composition / modularization / encapsulation
1009 * layout of logical file structure with roles
1010 * easier team workflow / merging
1015 thanks to Stevan Little
1016 and the whole moose crew #moose
1022 Thanks for putting up with my yammering
1026 - %%%% CPAN | http://search.cpan.org/~stevan/Moose-0.38/ %%%%
1027 - %%%% Cookbook | http://search.cpan.org/~stevan/Moose-0.38/lib/Moose/Cookbook.pod %%%%
1028 - %%%% Moose Site | http://www.iinteractive.com/moose/ %%%%
1029 - IRC: irc.perl.org #moose
1037 <!-- Built-in Style -->
1038 <html:style id="builtinStyle" type="text/css" style="visibility: collapse">
1040 @namespace url(http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul);
1041 @namespace html url(http:/www.w3.org/1999/xhtml);
1044 background: white !important;
1045 color: black !important;
1047 "Florencesans Black"
1062 "Arphic PGothic SuperBold JIS"
1068 "Arphic Gothic SuperBold JIS"
1070 "HGPSoeiKakugothicUB"
1073 "HGSoeiKakugothicUB"
1077 sans-serif !important;
1081 color: red !important;
1086 color: blue !important;
1087 text-decoration: underline !important;
1090 color: #3366FF !important;
1093 color: red !important;
1096 .preformatted-text.block {
1097 border: 1px dashed gray;
1104 background-color: white;
1105 background-repeat: no-repeat;
1106 /* background-image: url("./monta-label.png");*/
1113 border: 1px solid gray;
1116 #canvas grid .special {
1117 background: #CFCFCF;
1140 progressmeter .progress-bar,
1141 progressmeter .progress-remainder {
1142 -moz-appearance: none;
1143 background: transparent;
1148 #remainingTimeIndicator .progress-bar {
1149 background: #333333;
1151 #remainingPageIndicator .progress-bar {
1152 background: #444444;
1157 background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH1wYGCSMfVbRtUAAAAB10RVh0Q29tbWVudABDcmVhdGVkIHdpdGggVGhlIEdJTVDvZCVuAAAAGElEQVR42mNkYGCoZyACMDEQCUYVUkchANsIAJN3G7QXAAAAAElFTkSuQmCC');
1161 font-family: monospace;
1164 background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH1wYGCTURrpT1gAAAAB10RVh0Q29tbWVudABDcmVhdGVkIHdpdGggVGhlIEdJTVDvZCVuAAAAGUlEQVR42mP8////fgYiABMDkWBUIXUUAgAEGgPQ5w4kBAAAAABJRU5ErkJggg==');
1165 border: 2px solid gray;
1166 border-color: black white white black;
1167 -moz-appearance: none;
1173 #canvas[eva="true"] {
1174 background: black !important;
1175 color: white !important;
1186 "Arphic PMincho Ultra JIS"
1188 "Arphic Mincho Ultra JIS"
1190 "HGPHeiseiMinchotaiW9"
1192 "HGSHeiseiMinchotaiW9"
1194 "HGHeiseiMinchotaiW9"
1198 #canvas[eva="true"] .em-text {
1199 color: red !important;
1200 /* color: green !important;*/
1202 #canvas[eva="true"] .link-text {
1203 color: red !important;
1204 text-decoration: none !important;
1206 #canvas[eva="true"] .link-text:hover {
1207 color: pink !important;
1209 #canvas[eva="true"] .link-text:active {
1210 color: orange !important;
1213 #canvas[eva="true"] #header,
1214 #canvas[eva="true"] #footer {
1219 #canvas[eva="true"] .monta-label {
1220 background-color: black;
1240 /* System:: DO NOT CHANGE FOLLOWING LINES!! */
1244 cursor: pointer !important;
1251 #canvas[rendering="true"] image {
1255 #canvas[rendering="true"] *,
1256 #canvas[rendering="true"] .text-link {
1257 color: inherit !important;
1260 #canvas[rendering="true"] #contentBox {
1269 .preformatted-text {
1270 font-family: -moz-fixed !important;
1271 white-space: pre !important;
1277 font-family: sans-serif !important;
1278 font-size: medium !important;
1281 cursor: default !important;
1288 tabbox, tabpanels, tabpanel {
1294 .dropmarker-button > image {
1295 display: none !important;
1297 .dropmarker-button > label {
1298 width: 0 !important;
1299 overflow: hidden !important;
1302 #pages-list-button {
1305 #pages-list-button > label {
1308 #pages-list-button menupopup {
1311 #pages-list-button menuitem image {
1328 -moz-box-align: center;
1329 -moz-box-pack: center;
1338 .monta-label[monta-hidden="true"],
1339 .monta-label[monta-hidden="progress"] {
1340 background-position: -100px 0;
1342 .monta-label[monta-hidden="progress"] {
1343 background-color: transparent;
1345 .monta-label[monta-hidden="false"] {
1346 background: transparent !important;
1351 #canvas row description {
1352 border: 1px solid transparent;
1364 #pageEditFields textbox {
1365 font-family: -moz-fixed !important;
1372 #pageEditFields textbox {
1379 #stroke-canvas-box {
1384 #stroke-canvas-box *|canvas {
1397 background-image: url("data:image/png;base64,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AAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwgRAAAAAAAgTAAEAAAAgTAAEAAAAgDABEAAAAADCBEAAAAAACBMAAQAAACBMAAQAAACAMAEQAAAAAMIEQAAAAAAIEwABAAAAIEwABAAAAIAwARAAAAAAwv60rDzN2YM6WgAAAABJRU5ErkJggg==");
1405 <deck flex="1" id="deck">
1408 <toolbox id="canvasToolbar">
1410 <toolbarbutton oncommand="Presentation.home()" label="|<<"
1411 observes="canBack"/>
1412 <toolbarbutton oncommand="Presentation.back()" label="<"
1413 observes="canBack"/>
1414 <toolbarbutton oncommand="Presentation.forward()" label=">"
1415 observes="canForward"/>
1416 <toolbarbutton oncommand="Presentation.end()" label=">>|"
1417 observes="canForward"/>
1419 <hbox align="center">
1420 <textbox id="current_page" size="4"
1421 oninput="if (this.value) Presentation.showPage(parseInt(this.value)-1);"/>
1422 <toolbarbutton id="pages-list-button"
1425 tooltiptext="Select Page"
1426 class="dropmarker-button">
1427 <menupopup id="pages-list"
1428 onpopupshowing="if (event.target == this) Presentation.preventToShowHideToolbar = true;"
1429 onpopuphiding="if (event.target == this) Presentation.preventToShowHideToolbar = false;"
1430 oncommand="Presentation.showPage(parseInt(event.target.value));"/>
1432 <description value="/"/>
1433 <description id="max_page"/>
1438 <scrollbar id="scroller"
1439 align="center" orient="horizontal"
1440 oncommand="Presentation.showPage(parseInt(event.target.getAttribute('curpos')));"
1441 onclick="Presentation.showPage(parseInt(event.target.getAttribute('curpos')));"
1442 onmousedown="Presentation.onScrollerDragStart();"
1443 onmousemove="Presentation.onScrollerDragMove();"
1444 onmouseup="Presentation.onScrollerDragDrop();"/>
1448 <toolbarbutton label="Pen"
1452 oncommand="StrokablePresentationService.toggleCheck();"/>
1454 <toolbarbutton id="func-menu-button"
1458 onpopupshowing="if (event.target == this) { Presentation.preventToShowHideToolbar = true; Presentation.updateTimerItem(); }"
1459 onpopuphiding="if (event.target == this) Presentation.preventToShowHideToolbar = false;">
1460 <menuitem id="timerItem"
1462 label-normal="Set Timer"
1463 label-active="Reset Timer (rest %smin)"
1464 oncommand="Presentation.setTimer();" />
1466 <menuitem label="Start Auto-Cruise"
1470 oncommand="Presentation.toggleAutoCruiseMode();" />
1471 <menu id="auto-interval-button"
1472 label="Change Interval">
1473 <menupopup id="auto-interval-list"
1474 onpopupshowing="(this.getElementsByAttribute('value', Presentation.autoCruiseInterval)[0] || this.lastChild).setAttribute('checked', true);"
1475 oncommand="Presentation.changeAutoCruiseInterval(parseInt(event.target.value));">
1476 <menuitem type="radio" radiogroup="autocruise-interval"
1477 label="1 sec" value="1000"/>
1478 <menuitem type="radio" radiogroup="autocruise-interval"
1479 label="2 sec" value="2000"/>
1480 <menuitem type="radio" radiogroup="autocruise-interval"
1481 label="3 sec" value="3000"/>
1482 <menuitem type="radio" radiogroup="autocruise-interval"
1483 label="4 sec" value="4000"/>
1484 <menuitem type="radio" radiogroup="autocruise-interval"
1485 label="5 sec" value="5000"/>
1487 <menuitem type="radio" radiogroup="autocruise-interval"
1488 label="1 min" value="60000"/>
1489 <menuitem type="radio" radiogroup="autocruise-interval"
1490 label="2 min" value="120000"/>
1491 <menuitem type="radio" radiogroup="autocruise-interval"
1492 label="3 min" value="180000"/>
1493 <menuitem type="radio" radiogroup="autocruise-interval"
1494 label="4 min" value="240000"/>
1495 <menuitem type="radio" radiogroup="autocruise-interval"
1496 label="5 min" value="300000"/>
1498 <menuitem type="radio" radiogroup="autocruise-interval"
1501 var current = Presentation.autoCruiseInterval;
1502 var val = parseInt(prompt('input interval (sec)', parseInt(current/1000)));
1504 event.preventBubble();
1514 <menuitem oncommand="Presentation.print();" label="Print"/>
1515 <menu id="auto-interval-button"
1516 label="Thumbnail Format">
1518 onpopupshowing="(this.getElementsByAttribute('value', Presentation.imageType)[0] || this.firstChild).setAttribute('checked', true);"
1519 oncommand="Presentation.imageType = event.target.value;">
1520 <menuitem type="radio" radiogroup="print-image-type"
1521 label="PNG" value="png"/>
1522 <menuitem type="radio" radiogroup="print-image-type"
1523 label="JPEG (50%)" value="jpeg"/>
1527 <menuitem id="showPlainText" label="View Source"
1529 oncommand="Presentation.showPlainText();"/>
1531 <menuitem id="toggleEva" label="Eva Mode"
1532 key="key_toggleEvaMode"
1535 oncommand="Presentation.toggleEvaMode();"/>
1539 <toolbarbutton label="Edit"
1540 oncommand="Presentation.toggleEditMode();"/>
1541 <toolbarbutton oncommand="Presentation.reload();" label="Reload"/>
1544 <vbox flex="1" id="canvas">
1547 <hbox id="headerBox" flex="1">
1548 <label id="header"/>
1556 <hbox id="footerBox" flex="1">
1558 <label id="footer"/>
1561 <vbox id="canvasMain"
1563 onmouseup="Presentation.handleEvent(event);"
1564 onmousedown="Presentation.handleEvent(event);"
1565 onmousemove="Presentation.handleEvent(event);"
1566 onclick="Presentation.onPresentationClick(event);">
1568 <hbox flex="1" id="contentBox">
1570 <vbox id="content"/>
1575 <vbox id="plainTextBox"
1578 onclick="Presentation.hidePlainText();"
1581 <textbox id="plainTextField" multiline="true"
1582 onkeypress="if (event.keyCode == event.DOM_VK_ESCAPE) Presentation.hidePlainText();"
1583 onclick="event.stopPropagation();"/>
1587 <hbox id="indicatorBar"
1588 onclick="Presentation.onIndicatorBarClick(event);">
1591 <progressmeter id="remainingPageIndicator"
1592 type="determined" value="0"
1594 <progressmeter id="remainingTimeIndicator"
1595 type="determined" value="0"
1600 <label value="Next:"/>
1601 <description id="nextPage" flex="1" crop="end"/>
1607 <vbox flex="1" id="edit">
1613 <menuitem label="Save"
1615 oncommand="Presentation.output()"/>
1616 <menuitem label="Reload"
1618 oncommand="Presentation.reload()"/>
1621 <menu label="Insert">
1623 <menuitem label="New Page"
1624 key="key_insert_newpage"
1625 oncommand="Presentation.insert('page')"/>
1627 <menuitem label="Header"
1628 oncommand="Presentation.insert('header')"/>
1629 <menuitem label="Footer"
1630 oncommand="Presentation.insert('footer')"/>
1632 <menuitem label="Link"
1633 oncommand="Presentation.insert('link')"/>
1634 <menuitem label="Emphasis"
1635 oncommand="Presentation.insert('em')"/>
1636 <menuitem label="Preformatted"
1637 oncommand="Presentation.insert('pre')"/>
1638 <menuitem label="Monta"
1639 oncommand="Presentation.insert('monta')"/>
1640 <menuitem label="Image"
1641 oncommand="Presentation.insert('img')"/>
1646 <toolbarbutton label="View"
1647 oncommand="Presentation.toggleEditMode();"/>
1648 <toolbarbutton oncommand="Presentation.reload();" label="Reload"/>
1651 <tabbox id="editTabBox" flex="1">
1652 <tabs onselect="Presentation.toggleEditStyle(event);">
1653 <tab label="Page Edit" id="editTab-pages"/>
1654 <tab label="Source" id="editTab-source"/>
1656 <tabpanels flex="1">
1657 <scrollbox id="pageEditFields"
1660 <textbox id="sourceEditField"
1663 oninput="Presentation.onEditSource()"/>
1670 <data style="visibility: collapse;">
1671 <hbox id="pageEditBoxTemplate">
1672 <textbox multiline="true"
1673 class="page-edit-box-main"
1675 oninput="Presentation.onEditPage(Number(this.parentNode.parentNode.id.match(/\d+/)))"/>
1677 <toolbarbutton label="×"
1678 oncommand="Presentation.removePage(Number(this.parentNode.parentNode.id.match(/\d+/)));"/>
1684 <broadcaster id="canBack"/>
1685 <broadcaster id="canForward"/>
1689 <command id="cmd_forward"
1690 oncommand="if (Presentation.isPresentationMode) Presentation.forward();"/>
1691 <command id="cmd_forwardStep"
1692 oncommand="if (Presentation.isPresentationMode) Presentation.forwardStep();"/>
1693 <command id="cmd_back"
1694 oncommand="if (Presentation.isPresentationMode) Presentation.back();"/>
1695 <command id="cmd_home"
1696 oncommand="if (Presentation.isPresentationMode) Presentation.home();"/>
1697 <command id="cmd_end"
1698 oncommand="if (Presentation.isPresentationMode) Presentation.end();"/>
1702 <key keycode="VK_ENTER" command="cmd_forwardStep"/>
1703 <key keycode="VK_RETURN" command="cmd_forwardStep"/>
1704 <key keycode="VK_PAGE_DOWN" command="cmd_forwardStep"/>
1705 <key keycode="VK_RIGHT" command="cmd_forwardStep"/>
1706 <key keycode="VK_DOWN" command="cmd_forwardStep"/>
1707 <!--key keycode="VK_BACK_SPACE" command="cmd_back"/-->
1708 <key keycode="VK_PAGE_UP" command="cmd_back"/>
1709 <key keycode="VK_UP" command="cmd_back"/>
1710 <key keycode="VK_LEFT" command="cmd_back"/>
1711 <key keycode="VK_HOME" command="cmd_home"/>
1712 <key keycode="VK_END" command="cmd_end"/>
1714 <key id="key_insert_newpage"
1715 key="n" modifiers="accel" oncommand="Presentation.insert('page');"/>
1718 key="s" modifiers="accel" oncommand="Presentation.output();"/>
1719 <key id="key_reload"
1720 key="r" modifiers="accel" oncommand="Presentation.reload();"/>
1721 <key id="key_reload"
1722 key="p" modifiers="accel" oncommand="Presentation.print();"/>
1724 <key id="key_toggleEditMode"
1725 key="e" modifiers="accel" oncommand="Presentation.toggleEditMode();"/>
1726 <key id="key_toggleEvaMode"
1727 key="e" modifiers="accel,shift" oncommand="Presentation.toggleEvaMode();"/>
1729 <key id="key_plainText"
1730 key="u" modifiers="accel" oncommand="Presentation.showPlainText();"/>
1731 <key keycode="VK_ESCAPE" oncommand="Presentation.hidePlainText();"/>
1734 <!-- Implementation -->
1735 <script type="application/x-javascript; e4x=1"><![CDATA[
1737 const XULNS = 'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul';
1738 const XHTMLNS = 'http://www.w3.org/1999/xhtml';
1740 var Presentation = {
1743 montaLabelImage : 'monta-label.png',
1745 //phraseOpenParen : '[',
1746 //phraseCloseParen : ']',
1747 phraseOpenParen : '%%',
1748 phraseCloseParen : '%%',
1749 makePhraseRegExp : function(aPattern, aFlags)
1752 aPattern.replace(/%o(pen)?/gi, '\\'+this.phraseOpenParen)
1753 .replace(/%c(lose)?/gi, '\\'+this.phraseCloseParen),
1762 EDIT_BOX_ID_PREFIX : 'editPageBox-',
1764 initialized : false,
1766 preventToShowHideToolbar : false,
1768 showMontaKeywordTimeout : 100,
1769 autoCruiseInterval : 2000,
1770 timerUpdatingInterval : 30000,
1772 cachedContents : [],
1775 init : function(option){
1776 if (this.initialized) {
1777 this.startPresentation();
1780 this.initialized = true;
1784 this.canvas = document.getElementById('canvas');
1785 this.canvasMain = document.getElementById('canvasMain');
1786 this.content = document.getElementById('content');
1787 this.header = document.getElementById('header');
1788 this.footer = document.getElementById('footer');
1789 this.logo = document.getElementById('logo');
1790 this.next = document.getElementById('nextPage');
1792 this.indicatorBar = document.getElementById('indicatorBar');
1793 this.remainder = document.getElementById('remainingPageIndicator');
1794 this.timer = document.getElementById('remainingTimeIndicator');
1796 this.list = document.getElementById('pages-list');
1797 this.source = document.getElementById('sourceEditField');
1798 this.pages = document.getElementById('pageEditFields');
1799 this.deck = document.getElementById('deck');
1800 this.scroller = document.getElementById('scroller');
1802 this.toolbar = document.getElementById('canvasToolbar');
1803 this.toolbarHeight = this.toolbar.boxObject.height;
1804 this.isToolbarHidden = true;
1805 this.toolbar.setAttribute('style', 'margin-top:'+(0-this.toolbarHeight)+'px;margin-bottom:0px;');
1807 this.preloadImage(this.montaLabelImage);
1809 window.addEventListener('resize', this, false);
1810 window.addEventListener('contextmenu', this, false);
1811 window.addEventListener('CanvasContentAdded', this, false);
1813 this.canvasMain.addEventListener('DOMMouseScroll', this, false);
1814 this.indicatorBar.addEventListener('DOMMouseScroll', this, false);
1817 for(var i in option){this[i] = option[i]}
1820 this.cachedContents = [];
1822 if (this.readParameter()) {
1823 this.startPresentation();
1826 document.documentElement.focus();
1831 startPresentation : function()
1833 if (this.data.length)
1834 document.title = this.data[0].title || this.data[0].header || this.data[0].text.join(' ');
1841 takahashi : function() {
1842 this.isRendering = true;
1844 if (!this.data[this.offset]) {
1845 this.offset = this.data.length-1;
1847 document.getElementById("current_page").value = this.offset+1;
1848 document.getElementById("max_page").value = this.data.length;
1850 this.scroller.setAttribute('maxpos', this.data.length-1);
1851 this.scroller.setAttribute('curpos', this.offset);
1853 var broadcaster = document.getElementById('canBack');
1855 broadcaster.setAttribute('disabled', true);
1857 broadcaster.removeAttribute('disabled');
1859 var broadcaster = document.getElementById('canForward');
1860 if (this.offset == this.data.length-1)
1861 broadcaster.setAttribute('disabled', true);
1863 broadcaster.removeAttribute('disabled');
1865 this.canvas.setAttribute('rendering', true);
1868 this.header.removeAttribute('style');
1869 this.footer.removeAttribute('style');
1870 this.content.removeAttribute('style');
1872 this.clickableNodes = [];
1875 if ('title' in this.data[this.offset])
1876 document.title = this.data[this.offset].title;
1878 this.header.setAttribute('style', 'font-size:10px;');
1879 this.header.value = this.data[this.offset].header;
1880 this.footer.setAttribute('style', 'font-size:10px;');
1881 this.footer.value = this.data[this.offset].footer;
1883 var page = this.content.getAttribute('page');
1884 var range = document.createRange();
1885 range.selectNodeContents(this.content);
1886 this.cachedContents[page] = !this.content.hasChildNodes() ? null : {
1887 fragment : range.extractContents(),
1888 offsetWidth : parseInt(this.content.getAttribute('offsetWidth')),
1889 offsetHeight : parseInt(this.content.getAttribute('offsetHeight'))
1894 if (this.data[this.offset].load) {
1895 this.isRendering = false;
1896 location.replace(location.href.split('?')[0] + '?'+this.data[this.offset].load);
1900 var content = (this.offset in this.cachedContents && this.cachedContents[this.offset]) ?
1901 this.cachedContents[this.offset] :
1902 this.createContent();
1904 this.content.setAttribute('style', 'font-size:10px;');
1905 this.content.setAttribute('page', this.offset);
1906 this.content.setAttribute('offsetWidth', content.offsetWidth);
1907 this.content.setAttribute('offsetHeight', content.offsetHeight);
1909 this.content.appendChild(content.fragment);
1911 this.clickableNodes.push(this.content);
1914 this.fitHeaderFooterToCanvas();
1915 this.fitMainContentToCanvas();
1919 var checkedItems = this.list.getElementsByAttribute('checked', 'true');
1920 max = checkedItems.length;
1921 for (i = max-1; i > -1 ; i--)
1922 checkedItems[i].removeAttribute('checked');
1927 this.list.getElementsByAttribute('value', this.offset)[0].setAttribute('checked', true);
1929 this.canvas.removeAttribute('rendering');
1930 this.isRendering = false;
1931 this.setHash('page', 'page'+(this.offset+1));
1933 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)' ;
1934 this.remainder.setAttribute('value', this.offset == 0 ? 0 : parseInt(((this.offset)/(this.data.length-1))*100));
1936 var event = document.createEvent('Events');
1937 event.initEvent('PresentationRedraw', false, true);
1938 this.canvas.dispatchEvent(event);
1941 createContent : function()
1947 var text = this.data[this.offset].text;
1956 var lineRegExp = this.makePhraseRegExp('^([^%O]+)?(%O%Oem:((.+?)(:em)?%C%C)?|%O%O(raw|encoded):((.+?)(:raw|:encoded)?%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');
1958 var emRegExp = this.makePhraseRegExp('^([^%O]+)?%O%Oem({([^}]*)})?:(.+?)()?%C%C', 'i');
1959 var emStartRegExp = this.makePhraseRegExp('^([^%O]+)?%O%Oem({([^}]*)})?:(.*)', 'i');
1960 var emEndRegExp = this.makePhraseRegExp('^(.*?)((:em)?%C%C)', 'i');
1962 var preRegExp = this.makePhraseRegExp('^([^%O]+)?%O%Opre({([^}]*)})?:(.+?)(:pre)?%C%C', 'i');
1963 var preStartRegExp = this.makePhraseRegExp('^([^%O]+)?%O%Opre({([^}]*)})?:(.*)', 'i');
1964 var preEndRegExp = this.makePhraseRegExp('^(.*?)((:pre)?%C%C)', 'i');
1966 var rawRegExp = this.makePhraseRegExp('^([^%O]+)?%O%O(raw|encoded)({([^}]*)})?:(.+?)(:raw|:encoded)?%C%C', 'i');
1967 var rawStartRegExp = this.makePhraseRegExp('^([^%O]+)?%O%O(raw|encoded)({([^}]*)})?:(.*)', 'i');
1968 var rawEndRegExp = this.makePhraseRegExp('^(.*?)((:raw|:encoded)?%C%C)', 'i');
1970 var styleRegExp = this.makePhraseRegExp('^([^%O]+)?%O%O(#([^:{]*))?({([^}]*)})?:(.+?)%C%C', '');
1971 var styleStartRegExp = this.makePhraseRegExp('^([^%O]+)?%O%O(#([^:{]*))?({([^}]*)})?:(.*)', '');
1972 var styleEndRegExp = this.makePhraseRegExp('^(.*?)(%C%C)', '');
1974 var imagesRegExp = this.makePhraseRegExp('^([^%O]+)?%O%Oima?ge? +src="([^"]+)" +width="([0-9]+)" +height="([0-9]+)"[^%C]*%C%C', 'i');
1976 var linksRegExp = this.makePhraseRegExp('^([^%O]+)?%O%O(([^|]+)?\\||)([^%C]+)%C%C', '');
1978 var montaRegExp = this.makePhraseRegExp('^([^%O]+)?%O([^%C]+)%C', '');
1980 var inBlock = false,
1986 gridContents = null;
1988 var fragment = document.createDocumentFragment();
1991 for (var i = 0, max = text.length; i < max; i++)
1993 lineBox = document.createElement('hbox');
1994 lineBox.setAttribute('align', 'center');
1995 lineBox.setAttribute('pack', this.data[this.offset].align);
2000 if (!line) line = ' ';
2003 if (blockClass == 'raw' &&
2004 rawEndRegExp.test(line)) {
2006 blockContents.push(RegExp.$1);
2007 line = line.substring((RegExp.$1+RegExp.$2).length);
2009 eval('var xml = <hbox class="raw" style="blockStyle" onclick="event.stopPropagation();" onkeypress="event.stopPropagation();">'+blockContents.join('\n')+'</hbox>;');
2010 importNodeTreeWithDelay(importE4XNode(xml, document, XULNS), lineBox, XULNS);
2016 else if (blockClass == 'preformatted-text' &&
2017 preEndRegExp.test(line)) {
2019 blockContents.push(RegExp.$1);
2020 line = line.substring((RegExp.$1+RegExp.$2).length);
2022 lineBox.appendChild(document.createElement('description'));
2023 lineBox.lastChild.setAttribute('class', 'preformatted-text block');
2025 lineBox.lastChild.setAttribute('style', blockStyle);
2026 lineBox.lastChild.appendChild(document.createTextNode(
2027 blockContents.join('\n')
2028 .replace(/^[\r\n\s]+/, '')
2029 .replace(/[\r\n\s]+$/, '')
2030 .replace(/&/g, '&')
2031 .replace(/"/g, '"')
2032 .replace(/>/g, '>')
2033 .replace(/</g, '<')
2040 else if (emEndRegExp.test(line) || styleEndRegExp.test(line)) {
2042 blockContents.push(RegExp.$1);
2043 line = line.substring((RegExp.$1+RegExp.$2).length);
2045 lineBox.appendChild(document.createElement('vbox'));
2046 lineBox.lastChild.setAttribute('class', blockClass+' block');
2048 lineBox.lastChild.setAttribute('style', blockStyle);
2049 lineBox.lastChild.setAttribute('align', this.data[this.offset].align);
2050 blockContents = blockContents.join('\n')
2051 .replace(/^[\r\n\s]+/, '')
2052 .replace(/[\r\n\s]+$/, '')
2054 for (var j = 0, jmax = blockContents.length; j < jmax; j++)
2056 lineBox.lastChild.appendChild(document.createElement('description'));
2057 lineBox.lastChild.lastChild.setAttribute('value', blockContents[j]);
2065 blockContents.push(line);
2070 if (line.indexOf('|') == 0) {
2071 fragment.appendChild(lineBox);
2073 if (fragment.childNodes.length == 1 ||
2074 !fragment.childNodes[fragment.childNodes.length-2] ||
2075 !fragment.childNodes[fragment.childNodes.length-2].lastChild ||
2076 fragment.childNodes[fragment.childNodes.length-2].lastChild.localName != 'grid') {
2077 fragment.lastChild.appendChild(document.createElement('grid'));
2078 fragment.lastChild.lastChild.appendChild(document.createElement('columns'));
2079 fragment.lastChild.lastChild.appendChild(document.createElement('rows'));
2082 fragment.removeChild(fragment.lastChild);
2084 fragment.lastChild.lastChild.lastChild.appendChild(document.createElement('row'));
2085 fragment.lastChild.lastChild.lastChild.lastChild.setAttribute('flex', 1);
2087 line = line.split('|');
2088 for (var j = 1, jmax = line.length; j < jmax; j++)
2090 fragment.lastChild.lastChild.lastChild.lastChild.appendChild(document.createElement('vbox'));
2091 fragment.lastChild.lastChild.lastChild.lastChild.lastChild.setAttribute('align', this.data[this.offset].align);
2092 fragment.lastChild.lastChild.lastChild.lastChild.lastChild.setAttribute('pack', 'center');
2093 if (line[j].charAt(0) == '~') {
2094 fragment.lastChild.lastChild.lastChild.lastChild.lastChild.setAttribute('class', 'special');
2095 line[j] = line[j].substring(1);
2097 line[j] = line[j].split(/<br\s*\/>/g);
2098 for (var k = 0, kmax = line[j].length; k < kmax; k++)
2100 fragment.lastChild.lastChild.lastChild.lastChild.lastChild.appendChild(document.createElement('description'));
2101 fragment.lastChild.lastChild.lastChild.lastChild.lastChild.lastChild.appendChild(document.createTextNode(line[j][k].replace(/^\s+|\s+$/g, '')));
2103 if (fragment.lastChild.lastChild.firstChild.childNodes.length < j) {
2104 fragment.lastChild.lastChild.firstChild.appendChild(document.createElement('column'));
2105 fragment.lastChild.lastChild.firstChild.lastChild.setAttribute('flex', 1);
2112 while (line.match(lineRegExp))
2115 lineBox.appendChild(document.createElement('description'));
2116 lineBox.lastChild.setAttribute('value', RegExp.$1);
2118 newLine = line.substring((RegExp.$1+RegExp.$2).length);
2120 // Raw Codes: Parsed as XML
2121 if (rawRegExp.test(line)) {
2122 eval('var xml = <hbox class="raw" style="'+RegExp.$4+'" onclick="event.stopPropagation();" onkeypress="event.stopPropagation();">'+RegExp.$5+'</hbox>;');
2123 importNodeTreeWithDelay(importE4XNode(xml, document, XULNS), lineBox, XULNS);
2125 else if (rawStartRegExp.test(line)) {
2128 blockStyle = RegExp.$4;
2129 blockContents = [RegExp.$5];
2133 // Preformatted Text
2134 if (preRegExp.test(line)) {
2135 lineBox.appendChild(document.createElement('description'));
2137 lineBox.lastChild.setAttribute('style', RegExp.$3);
2138 lineBox.lastChild.setAttribute('value', RegExp.$4);
2139 lineBox.lastChild.setAttribute('class', 'preformatted-text');
2141 else if (preStartRegExp.test(line)) {
2143 blockClass = 'preformatted-text';
2144 blockStyle = RegExp.$3;
2145 blockContents = [RegExp.$4];
2150 else if (emRegExp.test(line)) {
2151 lineBox.appendChild(document.createElement('description'));
2153 lineBox.lastChild.setAttribute('style', RegExp.$3);
2154 lineBox.lastChild.setAttribute('value', RegExp.$4);
2155 lineBox.lastChild.setAttribute('class', 'em-text');
2157 else if (emStartRegExp.test(line)) {
2159 blockClass = 'em-text';
2160 blockStyle = RegExp.$3;
2161 blockContents = [RegExp.$4];
2165 // User-defined Styles
2166 else if (styleRegExp.test(line)) {
2167 lineBox.appendChild(document.createElement('description'));
2168 lineBox.lastChild.setAttribute('class', RegExp.$3);
2170 lineBox.lastChild.setAttribute('style', RegExp.$5);
2171 lineBox.lastChild.setAttribute('value', RegExp.$6);
2173 else if (styleStartRegExp.test(line)) {
2175 blockClass = RegExp.$3;
2176 blockStyle = RegExp.$5;
2177 blockContents = [RegExp.$6];
2182 else if (imagesRegExp.test(line)) {
2183 lineBox.appendChild(document.createElement('image'));
2184 image_src = RegExp.$2;
2185 if (image_src.indexOf('http://') < 0 &&
2186 image_src.indexOf('https://') < 0 &&
2187 image_src.indexOf('data:') < 0)
2188 image_src = this.dataFolder+image_src;
2189 lineBox.lastChild.setAttribute('src', image_src);
2190 lineBox.lastChild.setAttribute('width', parseInt(RegExp.$3 || '0'));
2191 lineBox.lastChild.setAttribute('height', parseInt(RegExp.$4 || '0'));
2192 image_width += parseInt(RegExp.$3 || '0');
2193 image_height = Math.max(image_height, parseInt(RegExp.$4 || '0'));
2197 else if (linksRegExp.test(line)) {
2199 if (uri.indexOf('://') < 0)
2200 uri = this.dataFolder+uri;
2201 lineBox.appendChild(document.createElement('description'));
2202 lineBox.lastChild.setAttribute('value', RegExp.$3 || RegExp.$4);
2203 lineBox.lastChild.setAttribute('href', uri);
2204 lineBox.lastChild.setAttribute('tooltiptext', uri);
2205 lineBox.lastChild.setAttribute('statustext', uri);
2206 lineBox.lastChild.setAttribute('class', 'link-text');
2208 this.clickableNodes.push(lineBox.lastChild);
2212 else if (montaRegExp.test(line)) {
2213 lineBox.appendChild(document.createElement('stack'));
2215 lineBox.lastChild.appendChild(document.createElement('description'));
2216 lineBox.lastChild.lastChild.setAttribute('value', RegExp.$2);
2217 lineBox.lastChild.lastChild.setAttribute('class', 'monta-text');
2219 lineBox.lastChild.appendChild(document.createElement('spacer'));
2220 lineBox.lastChild.lastChild.setAttribute('flex', 1);
2221 lineBox.lastChild.lastChild.setAttribute('class', 'monta-label');
2223 lineBox.lastChild.lastChild.setAttribute('label-id', 'label-' + (++labelId));
2225 lineBox.lastChild.lastChild.setAttribute('monta-hidden', 'true');
2227 this.clickableNodes.push(lineBox.lastChild.lastChild);
2234 lineBox.appendChild(document.createElement('description'));
2235 lineBox.lastChild.setAttribute('value', line);
2238 retVal.offsetWidth = Math.max(retVal.offsetWidth, image_width);
2239 retVal.offsetHeight += image_height;
2241 if (lineBox.hasChildNodes())
2242 fragment.appendChild(lineBox);
2245 retVal.fragment = fragment;
2249 fitToCanvas : function(aContent, aCanvas, aOffsetWidth, aOffsetHeight)
2251 aContent.removeAttribute('style');
2252 aContent.setAttribute('style', 'font-size:10px;');
2254 var grids = aContent.getElementsByTagName('grid');
2255 var gridsCount = grids.length;
2257 if (!aContent.boxObject.width) return;
2259 var canvas_w = aCanvas.boxObject.width;
2260 var canvas_h = aCanvas.boxObject.height-aOffsetHeight;
2262 var content_w = aContent.boxObject.width;
2263 var new_fs = Math.round((canvas_w/content_w) * this.data[this.offset].size);
2264 aContent.setAttribute('style', 'font-size:'+ new_fs + "px");
2266 for (var i = 0; i < gridsCount; i++)
2268 grids[i].firstChild.lastChild.removeAttribute('flex', 1);
2269 grids[i].firstChild.lastChild.setAttribute('flex', 1);
2272 if (aContent.boxObject.width < aOffsetWidth) {
2273 content_w = aOffsetWidth;
2274 new_fs = Math.round((canvas_w/content_w) * this.data[this.offset].size);
2275 aContent.setAttribute('style', 'font-size:'+ new_fs + "px");
2277 for (var i = 0; i < gridsCount; i++)
2279 grids[i].firstChild.lastChild.removeAttribute('flex', 1);
2280 grids[i].firstChild.lastChild.setAttribute('flex', 1);
2284 var content_h = aContent.boxObject.height;
2285 if(content_h >= canvas_h){
2287 content_h = aContent.boxObject.height;
2288 new_fs = Math.round((canvas_h/content_h) * new_fs);
2289 aContent.setAttribute('style', 'font-size:'+ new_fs + "px");
2291 for (var i = 0; i < gridsCount; i++)
2293 grids[i].firstChild.lastChild.removeAttribute('flex', 1);
2294 grids[i].firstChild.lastChild.setAttribute('flex', 1);
2299 fitMainContentToCanvas : function()
2304 parseInt(this.content.getAttribute('offsetWidth')),
2305 parseInt(this.content.getAttribute('offsetHeight'))
2306 +this.header.boxObject.height
2307 +this.footer.boxObject.height
2311 fitHeaderFooterToCanvas : function()
2313 this.fitToCanvas(this.header, this.header.parentNode, 0, 0);
2314 this.fitToCanvas(this.footer, this.footer.parentNode, 0, 0);
2318 return this._offset;
2321 this._offset = parseInt(aValue || 0);
2322 document.documentElement.setAttribute('lastoffset', this.offset);
2328 setHash : function(aKey, aValue)
2330 aKey = String(aKey).toLowerCase();
2331 var hashArray = String(location.hash).replace(/^#/, '').toLowerCase().split(',');
2333 for (var i = hashArray.length-1; i > -1; i--)
2334 if (!hashArray[i] || hashArray[i].indexOf(aKey) == 0)
2335 hashArray.splice(i, 1);
2337 if (aValue) hashArray.push(aValue);
2340 location.replace(location.href.replace(/#.*$/, '') + (hashArray.length ? '#' + hashArray.join(',') : '' ));
2344 var codes = document.getElementById('builtinCode');
2346 // mozilla splits very long text node into multiple text nodes whose length is less than 4096 bytes.
2347 // so, we must concat all the text nodes.
2348 this.source.value = "";
2349 this.sourceData = [];
2350 for (var i = 0; i < codes.childNodes.length; i++) {
2351 this.source.value += codes.childNodes[i].nodeValue;
2354 this._data = this.source.value.split(/----+/);
2358 codes.parentNode.removeChild(codes);
2363 this._data = aValue.split(/----+/);
2368 initData : function()
2370 var range = document.createRange();
2372 range.selectNodeContents(this.list);
2373 range.deleteContents();
2376 this.sourceData = [];
2380 /^[\r\n\s]+|[\r\n\s]+$/g,
2385 var titleRegExp = /^(TITLE::)([^\n]*)\n?/im;
2387 var headerRegExp = /^(HEADER::)([^\n]*)\n?/im;
2389 var footerRegExp = /^(FOOTER::)([^\n]*)\n?/im;
2391 var chapterRegExp = /^(CHAPTER::)([^\n]*)\n?/im;
2393 var alignGlobal = 'center';
2395 var alignRegExp = /^((GLOBAL-)?ALIGN::)(left|right|center|start|end)?\n?/im;
2398 var sizeRegExp = /^((GLOBAL-)?SIZE::)(\d+(\.\d+)?)\n?/im;
2400 var imageMatchResults;
2401 var imagesRegExp = this.makePhraseRegExp('%O%Oima?ge? +src="[^"]+" +width="[0-9]+" +height="[0-9]+"[^%C]*%C%C', 'gi');
2402 var imagesRegExp2 = this.makePhraseRegExp('%O%Oima?ge? +src="([^"]+)"', 'i');
2405 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');
2407 var hiddenRegExp = /^(HIDDEN|IGNORE)::true\n?/im;
2409 var loadRegExp = /^LOAD::(.+)\n?/im;
2410 var timerRegExp = /^SET-TIMER::(\d+)(.*)\n?/im;
2414 max = this._data.length;
2415 var menuContents = document.createDocumentFragment();
2419 for (i = 0; i < max; i++)
2426 this._data[i] = this._data[i]
2427 .replace(regexp[0], '')
2428 .replace(regexp[1], '\n');
2430 this.sourceData[i] = this._data[i];
2432 if (loadRegExp.test(this._data[i])) {
2433 this._data[i] = this._data[i].replace(loadRegExp, '');
2434 dataPath = RegExp.$1;
2437 if (timerRegExp.test(this._data[i])) {
2438 this._data[i] = this._data[i].replace(timerRegExp, '');
2439 window.setTimeout(function(aSelf, aTime, aUnit) {
2440 if (!aSelf.timerTimer) {
2460 aSelf.setTimer(aTime);
2462 }, 100, this, parseInt(RegExp.$1), (RegExp.$2 || '').toLowerCase());
2465 if (hiddenRegExp.test(this._data[i])) {
2466 this._data.splice(i, 1);
2472 while (titleRegExp.test(this._data[i])) {
2473 this._data[i] = this._data[i].replace(titleRegExp, '');
2474 if (String(RegExp.$1).toUpperCase() == 'TITLE::')
2475 title = RegExp.$2 || '' ;
2478 while (headerRegExp.test(this._data[i])) {
2479 this._data[i] = this._data[i].replace(headerRegExp, '');
2480 if (String(RegExp.$1).toUpperCase() == 'HEADER::')
2481 header = RegExp.$2 || '' ;
2484 while (footerRegExp.test(this._data[i])) {
2485 this._data[i] = this._data[i].replace(footerRegExp, '');
2486 if (String(RegExp.$1).toUpperCase() == 'FOOTER::')
2487 footer = RegExp.$2 || '' ;
2490 while (chapterRegExp.test(this._data[i])) {
2491 this._data[i] = this._data[i].replace(chapterRegExp, '');
2492 if (String(RegExp.$1).toUpperCase() == 'CHAPTER::')
2493 chapter = RegExp.$2 || '' ;
2496 while (alignRegExp.test(this._data[i])) {
2497 this._data[i] = this._data[i].replace(alignRegExp, '');
2499 align = (RegExp.$3 || '').toLowerCase();
2500 if (align == 'left')
2502 else if (align == 'right')
2505 if (String(RegExp.$1).toUpperCase() == 'GLOBAL-ALIGN::') {
2506 alignGlobal = align;
2511 while (sizeRegExp.test(this._data[i])) {
2512 this._data[i] = this._data[i].replace(sizeRegExp, '');
2513 size = Math.max(0, Number(RegExp.$3 || this.baseSize));
2514 if (String(RegExp.$1).toUpperCase() == 'GLOBAL-SIZE::') {
2520 imageMatchResults = this._data[i].match(imagesRegExp);
2521 if (imageMatchResults) {
2522 for (j = imageMatchResults.length-1; j > -1; j--)
2523 image_src = this.preloadImage(imageMatchResults[j].match(imagesRegExp2)[1]);
2530 text : this._data[i].split('\n'),
2532 align : align || alignGlobal,
2533 size : size || sizeGlobal
2535 this._data[i].plain = this._data[i].text
2537 .replace(plainTextRegExp, '$2$3$5$7$9')
2539 if (title !== void(0))
2540 this._data[i].title = title;
2542 this._data[i].chapter = chapter || title || '';
2543 if (lastChapter === void(0) ||
2544 lastChapter != this._data[i].chapter) {
2545 lastChapter = this._data[i].chapter;
2547 if (popup && popup.childNodes.length == 1) {
2548 menuContents.removeChild(menuContents.lastChild);
2549 menuContents.appendChild(popup.removeChild(popup.lastChild));
2552 popup = document.createElement('menupopup');
2553 menuContents.appendChild(document.createElement('menu'));
2554 menuContents.lastChild.setAttribute('label', this._data[i].chapter);
2555 menuContents.lastChild.appendChild(popup);
2558 popup.appendChild(document.createElement('menuitem'));
2559 popup.lastChild.setAttribute('type', 'radio');
2560 popup.lastChild.setAttribute('radiogroup', 'pages');
2561 popup.lastChild.setAttribute('label', (i+1)+': '+(
2562 (this._data[i].plain.join('') || this._data[i].text.join(' ')).replace(/\s+/g, ' ')
2564 popup.lastChild.setAttribute('value', i);
2567 // popup.lastChild.setAttribute('image', image_src);
2568 // popup.lastChild.setAttribute('class', 'menuitem-iconic');
2572 if (menuContents.childNodes.length == 1) {
2573 range.selectNodeContents(menuContents.firstChild.firstChild);
2574 menuContents = range.extractContents();
2576 this.list.appendChild(menuContents);
2581 this.shownMontaLabels = [];
2585 if (!this._dataPath)
2586 this.dataPath = String(location.href).replace(/#.+$/, '');
2587 return this._dataPath;
2589 set dataPath(aValue){
2590 var oldDataPath = this._dataPath;
2591 this._dataPath = aValue;
2592 if (oldDataPath != aValue) {
2593 this._dataFolder = this._dataPath.split('?')[0].replace(/[^\/]+$/, '');
2595 return this._dataPath;
2599 if (!this._dataFolder)
2600 this.dataPath = this.dataPath;
2601 return this._dataFolder;
2603 set dataFolder(aValue){
2604 this._dataFolder = aValue;
2605 return this._dataFolder;
2608 loadData : function(aPath)
2610 this.dataPath = aPath;
2611 var request = new XMLHttpRequest();
2612 request.open('GET', aPath);
2613 request.onload = function() {
2614 Presentation.data = request.responseText;
2615 Presentation.init();
2620 readParameter : function() {
2621 if (location.search || location.hash) {
2622 var param = location.search.replace(/^\?/, '');
2624 if (location.hash.match(/page([0-9]+)/i) ||
2625 param.match(/page=([0-9]+)/i))
2626 this.offset = parseInt(RegExp.$1)-1;
2628 if (location.hash.match(/edit/i) ||
2629 param.match(/edit=(1|true|yes)/i)) {
2630 window.setTimeout('Presentation.toggleEditMode();', 0);
2633 if (location.hash.match(/eva/i) ||
2634 param.match(/eva=(1|true|yes)/i))
2635 this.toggleEvaMode();
2637 if (location.hash.match(/timer(\d+)\-(\d+)/i))
2638 this.setTimer(RegExp.$1, RegExp.$2);
2640 if (param.match(/(style|css)=([^&;]+)/i)) {
2641 var style = unescape(RegExp.$2);
2642 var pi = document.createProcessingInstruction('xml-stylesheet', 'href="'+style+'" type="text/css"');
2643 document.insertBefore(pi, document.documentElement);
2646 if (param.match(/data=([^&;]+)/i)) {
2647 this.loadData(RegExp.$1);
2654 preloadImage : function(aURI)
2656 if (aURI in this.imageRequests) return;
2658 if (aURI.indexOf('http://') < 0 &&
2659 aURI.indexOf('https://') < 0)
2660 aURI = this.dataFolder+aURI;
2662 this.imageRequests[aURI] = new XMLHttpRequest();
2664 this.imageRequests[aURI].open('GET', aURI);
2665 this.imageRequests[aURI].onload = function() {
2666 Presentation.imageRequests[aURI] = null;
2668 this.imageRequests[aURI].send(null);
2671 this.imageRequests[aURI] = null;
2679 reload : function() {
2680 var file = String(location.href).replace(/#.+$/, '');
2681 if (this.dataPath != file) {
2682 var path = this.dataPath;
2683 var request = new XMLHttpRequest();
2684 request.open('GET', path);
2685 request.onload = function() {
2686 Presentation.data = request.responseText;
2687 Presentation.init();
2695 window.location.reload();
2698 forward : function(){
2699 if (!this.canForward) return;
2704 forwardStep : function(){
2705 if (!this.canForward) return;
2706 var monta = document.getElementsByAttribute('monta-hidden', 'true');
2707 if (monta && monta.length) {
2708 this.showMontaKeyword(monta[0]);
2715 if (!this.canBack) return;
2717 if(this.offset < 0){this.offset = 0}
2722 if (!this.canMove) return;
2728 if (!this.canMove) return;
2729 this.offset = this.data.length-1;
2733 showPage : function(aPageOffset){
2734 if (!this.canMove) return;
2735 this.offset = aPageOffset ? aPageOffset : 0 ;
2739 toggleEditMode : function()
2741 if (this.deck.selectedIndex == 1) {
2742 if (document.getElementById('editTabBox').selectedTab.id == 'editTab-pages') {
2743 this.source.value = this.sourceData.join('\n----\n');
2745 this.data = this.source.value;
2746 this.cachedContents = [];
2747 var range = document.createRange();
2748 range.selectNodeContents(this.content);
2749 range.deleteContents();
2754 this.initEditPages();
2757 this.deck.selectedIndex = this.deck.selectedIndex == 0 ? 1 : 0 ;
2758 this.setHash('edit', this.deck.selectedIndex == 0 ? '' : 'edit' );
2761 toggleEvaMode : function()
2763 var check = document.getElementById('toggleEva');
2764 if (this.canvas.getAttribute('eva') == 'true') {
2765 this.canvas.removeAttribute('eva');
2766 this.logo.removeAttribute('eva');
2767 check.checked = false;
2770 this.canvas.setAttribute('eva', true);
2771 this.logo.setAttribute('eva',true);
2772 check.checked = true;
2774 this.setHash('eva', check.checked ? 'eva' : '' );
2779 toggleAutoCruiseMode : function()
2781 var autoCruise = document.getElementById('autoButton');
2782 if(!autoCruise.checked)
2783 this.startAutoCruise();
2785 autoCruise.checked = false;
2788 startAutoCruise : function()
2790 var autoCruise = document.getElementById('autoButton');
2791 autoCruise.checked = true;
2793 if (this.autoCruiseTimer) {
2794 window.clearTimeout(this.autoCruiseTimer);
2796 this.autoCruiseTimer = window.setTimeout(this.autoCruise, this.autoCruiseInterval);
2799 changeAutoCruiseInterval : function(aInterval)
2801 this.autoCruiseInterval = aInterval;
2802 this.startAutoCruise();
2805 autoCruise : function()
2807 var autoCruise = document.getElementById('autoButton');
2808 if (!autoCruise.checked) return;
2810 if (Presentation.offset == Presentation.data.length-1) {
2811 if (Presentation.canMove)
2812 Presentation.home();
2815 if (Presentation.canForward)
2816 Presentation.forwardStep();
2818 Presentation.autoCruiseTimer = window.setTimeout(arguments.callee, Presentation.autoCruiseInterval);
2820 autoCruiseTimer : null,
2824 resetTimer : function()
2826 if (this.timerTimer) {
2827 window.clearInterval(this.timerTimer);
2828 this.timerTimer = null;
2830 this.timer.setAttribute('value', 0);
2831 this.timer.setAttribute('collapsed', true);
2832 this.setHash('timer', '');
2835 setTimer : function(aStart, aEnd)
2837 var now = (new Date()).getTime();
2838 if (aStart !== void(0) && aEnd === void(0)) {
2839 var rest = Math.abs(aStart);
2840 this.timerStart = now;
2841 this.timerEnd = this.timerStart + (rest * 60000);
2843 else if (aStart === void(0) && aEnd === void(0)) {
2844 var rest = prompt('Remaining Time (minits)');
2850 rest = Number(rest);
2851 if (!rest || isNaN(rest)) return;
2854 rest = Math.abs(rest);
2855 this.timerStart = now;
2856 this.timerEnd = this.timerStart + (rest * 60000);
2859 aStart = Number(aStart);
2860 aEnd = Number(aEnd);
2861 if (isNaN(aStart) || isNaN(aEnd)) return;
2863 this.timerStart = Math.min(aStart, aEnd);
2864 this.timerEnd = Math.max(aStart, aEnd);
2866 if (this.timerStart >= now || this.timerEnd <= now) return;
2871 this.timer.removeAttribute('collapsed');
2872 this.setHash('timer', 'timer'+this.timerStart+'-'+this.timerEnd);
2874 if (now != this.timerStart)
2875 this.updateTimer(this);
2877 this.timerTimer = window.setInterval(this.updateTimer, Math.min(this.timerUpdatingInterval, (this.timerEnd-this.timerStart)/(this.data.length*2)), this);
2884 updateTimer : function(aThis)
2886 var now = (new Date()).getTime();
2887 if (now >= aThis.timerEnd) {
2889 aThis.timer.setAttribute('value', 100);
2890 aThis.timer.removeAttribute('collapsed');
2891 aThis.setHash('timer', '');
2894 var value = parseInt(((now - aThis.timerStart) / (aThis.timerEnd - aThis.timerStart)) * 100);
2895 aThis.timer.setAttribute('value', value);
2899 updateTimerItem : function()
2901 var item = document.getElementById('timerItem');
2902 if (this.timerTimer) {
2903 item.setAttribute('label', item.getAttribute('label-active').replace(/%s/gi, Math.round((this.timerEnd - (new Date()).getTime()) / 60000)));
2906 item.setAttribute('label', item.getAttribute('label-normal'));
2914 if (!this.canMove) {
2915 alert('Please wait for a while, and retry later.');
2920 if (this.printWindow) {
2921 this.printWindow.close();
2922 this.printWindow = null;
2925 if (!this.isToolbarHidden)
2926 this.showHideToolbar(true);
2928 this.printWindow = window.open('output.htm', 'PresentationPrint', 'dependent=yes,hotkeys=yes,location=yes,menubar=yes,personalbar=yes,scrollbars=yes,status=yes,toolbar=yes');
2929 if (!this.printWindow) return;
2931 this.isPrinting = true;
2933 if (!this.printCanvas)
2934 this.printCanvas = document.createElementNS(XHTMLNS, 'canvas');
2936 this.printWindow.document.write('<html><head><title>'+document.title+'</title></head><body></body></html>');
2938 this.printTimer = window.setInterval(this.printCallback, 0, this);
2941 printCallback : function(aThis)
2948 var monta = document.getElementsByAttribute('monta-hidden', 'true');
2949 if (monta && monta.length) {
2950 for (var i = monta.length-1; i > -1; i--)
2951 aThis.showMontaKeyword(monta[i], true);
2954 var doc = aThis.printWindow.document;
2955 var body = doc.getElementsByTagName('body')[0];
2956 var img = doc.createElement('img');
2958 if ((aThis.offset+1) % 2 == 1) {
2959 body.appendChild(doc.createElement('div'));
2960 // body.lastChild.style.clear = 'both';
2962 var box = doc.createElement('div');
2963 box.appendChild(doc.createElement('div'));
2964 box.lastChild.appendChild(document.createTextNode(aThis.offset+1));
2965 body.lastChild.appendChild(box);
2967 var w = window.innerWidth;
2968 var h = window.innerHeight;
2969 var canvasW = parseInt(w * aThis.printSize);
2970 var canvasH = parseInt(h * aThis.printSize);
2972 aThis.printCanvas.width = canvasW;
2973 aThis.printCanvas.height = canvasH;
2974 aThis.printCanvas.style.border = 'black solid medium';
2976 img.style.border = 'black solid medium';
2977 img.style.width = canvasW+'px';
2978 img.style.height = canvasH+'px';
2980 box.style.margin = '1em';
2981 box.style.width = parseInt(w * aThis.printSize)+'px';
2982 box.style.cssFloat = ((aThis.offset+1) % 2 == 1) ? 'left' : 'right' ;
2985 netscape.security.PrivilegeManager.enablePrivilege('UniversalBrowserRead');
2987 var ctx = aThis.printCanvas.getContext('2d');
2988 ctx.clearRect(0, 0, canvasW, canvasH);
2990 ctx.scale(aThis.printSize, aThis.printSize);
2991 ctx.drawWindow(window, 0, 0, w, h, 'rgb(255,255,255)');
2994 if (aThis.imageType == 'jpeg')
2995 img.src = aThis.printCanvas.toDataURL('image/jpeg', 'quality=50');
2997 img.src = aThis.printCanvas.toDataURL('image/png', 'transparency=none');
2999 box.appendChild(img);
3002 box.appendChild(aThis.printCanvas.cloneNode(true));
3003 ctx = box.lastChild.getContext('2d');
3004 ctx.clearRect(0, 0, canvasW, canvasH);
3006 ctx.scale(aThis.printSize, aThis.printSize);
3007 ctx.drawWindow(window, 0, 0, w, h, 'rgb(255,255,255)');
3012 alert('Error: Failed to create a document for printing.\n\n------\n'+e);
3017 if (aThis.offset == aThis.data.length-1) {
3019 aThis.printWindow.focus();
3026 stopPrint : function()
3028 window.clearInterval(this.printTimer);
3029 this.printTimer = null;
3030 this.isPrinting = false;
3040 plainTextShown : false,
3044 return document.getElementById('plainTextBox');
3047 get plainTextField()
3049 return document.getElementById('plainTextField');
3052 showPlainText : function()
3054 if (this.plainTextShown) return;
3055 this.plainTextShown = true;
3056 this.plainTextBox.removeAttribute('hidden');
3057 this.plainTextField.style.width = parseInt(this.canvas.boxObject.width * 0.8)+'px';
3058 this.plainTextField.style.height = parseInt(this.canvas.boxObject.height * 0.8)+'px';
3059 this.plainTextField.value = this.data[this.offset].text.join('\n').replace(/\u200b/g, '');
3060 this.plainTextField.select();
3061 this.plainTextField.focus();
3064 hidePlainText : function()
3066 if (!this.plainTextShown) return;
3067 this.plainTextShown = false;
3068 this.plainTextBox.setAttribute('hidden', true);
3069 this.plainTextField.value = '';
3070 this.plainTextField.blur();
3079 importNodeTreeWithDelayTimers ||
3086 return this.canMove;
3091 return this.canMove;
3094 get isPresentationMode(){
3095 return (this.deck.selectedIndex == 0);
3098 /* event handling */
3100 handleEvent : function(aEvent)
3102 if (this.isPrinting) return;
3104 var node = aEvent.target;
3105 var inRawContents = false;
3107 if (node.nodeType == Node.ELEMENT_NODE &&
3108 /\braw\b/i.test(node.getAttribute('class'))) {
3109 inRawContents = true;
3113 node = node.parentNode;
3115 while (node.parentNode)
3118 switch (aEvent.type)
3124 this.takahashi(); // redrwa
3128 aEvent.stopPropagation();
3129 aEvent.preventCapture();
3130 aEvent.preventDefault();
3131 aEvent.preventBubble();
3136 if (inRawContents) return;
3137 this.dragStartX = -1;
3138 this.dragStartY = -1;
3139 if (this.indicatorBar.dragging)
3140 this.onIndicatorBarDragEnd(aEvent);
3144 if (inRawContents) return;
3145 if (this.dragStartX < 0) {
3146 this.dragStartX = aEvent.clientX;
3147 this.dragStartY = aEvent.clientY;
3149 var box = this.indicatorBar.boxObject;
3150 if (!(aEvent.screenX < box.screenX ||
3151 aEvent.screenY < box.screenY ||
3152 aEvent.screenX > box.screenX+box.width ||
3153 aEvent.screenY > box.screenY+box.height))
3154 this.onIndicatorBarDragStart();
3158 if (inRawContents) return;
3159 this.checkShowHideToolbar(aEvent);
3160 if (this.indicatorBar.dragging) {
3161 this.onIndicatorBarDragMove(aEvent);
3164 if (this.dragStartX > -1) {
3165 if (Math.abs(this.dragStartX-aEvent.clientX) > Math.abs(this.dragStartDelta) ||
3166 Math.abs(this.dragStartY-aEvent.clientY) > Math.abs(this.dragStartDelta)) {
3167 var event = document.createEvent('Events');
3168 event.initEvent('StartDragOnCanvas', false, true);
3169 this.canvas.dispatchEvent(event);
3174 case 'CanvasContentAdded':
3175 if (this.fitToCanvasTimer) {
3176 window.clearTimeout(this.fitToCanvasTimer);
3177 this.fitToCanvasTimer = null;
3179 this.fitToCanvasTimer = window.setTimeout('Presentation.fitMainContentToCanvas()', 100);
3182 case 'DOMMouseScroll':
3184 (aEvent.detail > 0 && this.scrollCounter < 0) ||
3185 (aEvent.detail < 0 && this.scrollCounter > 0)
3187 this.scrollCounter = 0;
3189 this.scrollCounter += aEvent.detail;
3190 if (Math.abs(this.scrollCounter) >= this.scrollThreshold) {
3191 if (aEvent.detail > 0)
3192 Presentation.forwardStep();
3194 Presentation.back();
3196 this.scrollCounter = 0;
3205 scrollThreshold : 10,
3207 onKeyPress : function(aEvent) {
3208 if (this.isPrinting) return;
3210 switch(aEvent.keyCode)
3212 case aEvent.DOM_VK_BACK_SPACE:
3213 if (this.isPresentationMode) {
3214 aEvent.preventBubble();
3215 aEvent.preventDefault();
3216 Presentation.back();
3224 /* actions on presentation */
3226 onPresentationClick : function(aEvent)
3228 if (this.isPrinting) {
3229 if (confirm('Do you want printing operation to be stopped?')) {
3235 if (!this.isToolbarHidden)
3236 this.showHideToolbar();
3238 switch(aEvent.button)
3241 switch (aEvent.target.getAttribute('class'))
3244 var uri = aEvent.target.getAttribute('href');
3252 if (aEvent.target.getAttribute('monta-hidden') == 'true') {
3253 this.showMontaKeyword(aEvent.target);
3254 aEvent.preventBubble();
3262 document.documentElement.focus();
3266 document.documentElement.focus();
3275 onScrollerDragStart : function(){
3276 if (this.isPrinting) return;
3278 this.scroller.dragging = true;
3281 onScrollerDragMove : function(){
3282 if (this.isPrinting) return;
3284 if (this.scroller.dragging)
3285 this.showPage(parseInt(this.scroller.getAttribute('curpos')));
3288 onScrollerDragDrop : function(){
3289 if (this.isPrinting) return;
3291 this.onScrollerDragMove();
3292 this.scroller.dragging = false;
3297 onIndicatorBarClick : function(aEvent)
3299 if (this.isPrinting) return;
3301 var bar = this.indicatorBar;
3302 this.showPage(Math.round((aEvent.screenX - bar.boxObject.screenX) / bar.boxObject.width * this.data.length));
3305 onIndicatorBarDragStart : function()
3307 if (this.isPrinting) return;
3309 this.indicatorBar.dragging = true;
3312 onIndicatorBarDragMove : function(aEvent)
3314 if (this.isPrinting) return;
3316 var bar = this.indicatorBar;
3317 this.showPage(Math.round((aEvent.screenX - bar.boxObject.screenX) / bar.boxObject.width * this.data.length));
3320 onIndicatorBarDragEnd : function(aEvent)
3322 if (this.isPrinting) return;
3324 this.onIndicatorBarDragMove(aEvent);
3325 this.indicatorBar.dragging = false;
3328 showMontaKeyword : function(aNode, aWithoutAnimation) {
3329 if (aNode.getAttribute('monta-hidden') != 'true') return;
3331 if (aWithoutAnimation) {
3332 aNode.setAttribute('monta-hidden', 'false');
3336 aNode.setAttribute('monta-hidden', 'progress');
3338 this.montaAnimating = true;
3340 window.setTimeout(this.showMontaKeywordCallback, 0, {
3343 interval : this.showMontaKeywordTimeout/10
3347 showMontaKeywordCallback : function(aInfo) {
3348 if (aInfo.position >= aInfo.node.boxObject.width) {
3349 aInfo.node.setAttribute('monta-hidden', 'false');
3350 Presentation.montaAnimating = false;
3354 aInfo.position += (aInfo.node.boxObject.width/10);
3355 aInfo.node.setAttribute('style', 'background-position: '+aInfo.position+'px 0 !important;');
3356 window.setTimeout(arguments.callee, aInfo.interval, aInfo);
3358 montaAnimating : false,
3360 /* toolbar animation */
3362 onToolbarArea : false,
3365 toolbarTimer : null,
3366 isToolbarHidden : false,
3368 checkShowHideToolbar : function(aEvent) {
3369 if (!this.scroller || this.scroller.dragging || this.preventToShowHideToolbar) return;
3371 this.onToolbarArea = (aEvent.clientY < this.toolbarHeight);
3373 if (this.isToolbarHidden == this.onToolbarArea) {
3374 if (this.toolbarTimer) window.clearTimeout(this.toolbarTimer);
3375 this.toolbarTimer = window.setTimeout('Presentation.checkShowHideToolbarCallback()', this.toolbarDelay);
3379 checkShowHideToolbarCallback : function() {
3380 if (this.isToolbarHidden == this.onToolbarArea)
3381 this.showHideToolbar();
3384 showHideToolbar : function(aWithoutAnimation)
3386 if (this.isPrinting) return;
3388 if (this.toolbarAnimationTimer) window.clearTimeout(this.toolbarAnimationTimer);
3390 this.toolbarAnimationInfo = { count : 0 };
3391 if (this.isToolbarHidden) {
3392 this.toolbarAnimationInfo.start = 0;
3393 this.toolbarAnimationInfo.end = this.toolbarHeight;
3396 this.toolbarAnimationInfo.start = this.toolbarHeight;
3397 this.toolbarAnimationInfo.end = 0;
3399 this.toolbarAnimationInfo.current = 0;
3401 this.toolbar.setAttribute('style', 'margin-top:'+(0-(this.toolbarHeight-this.toolbarAnimationInfo.start))+'px; margin-bottom:'+(0-this.toolbarAnimationInfo.start)+'px;');
3403 if (aWithoutAnimation) {
3404 this.toolbarAnimationInfo.current = this.toolbarHeight;
3405 Presentation.animateToolbar();
3408 this.toolbarAnimationTimer = window.setTimeout('Presentation.animateToolbar()', this.toolbarAnimationDelay/this.toolbarAnimationSteps);
3412 animateToolbar : function()
3414 this.toolbarAnimationInfo.current += parseInt(this.toolbarHeight/this.toolbarAnimationSteps);
3417 if (this.toolbarAnimationInfo.start < this.toolbarAnimationInfo.end) {
3418 top = this.toolbarHeight-this.toolbarAnimationInfo.current;
3419 bottom = this.toolbarAnimationInfo.current;
3422 top = this.toolbarAnimationInfo.current;
3423 bottom = this.toolbarHeight-this.toolbarAnimationInfo.current;
3426 top = Math.min(Math.max(top, 0), this.toolbarHeight);
3427 bottom = Math.min(Math.max(bottom, 0), this.toolbarHeight);
3429 this.toolbar.setAttribute('style', 'margin-top:'+(0-top)+'px; margin-bottom:'+(0-bottom)+'px');
3431 if (this.toolbarAnimationInfo.count < this.toolbarAnimationSteps) {
3432 this.toolbarAnimationInfo.count++;
3433 this.toolbarAnimationTimer = window.setTimeout('Presentation.animateToolbar()', this.toolbarAnimationDelay/this.toolbarAnimationSteps);
3436 this.isToolbarHidden = !this.isToolbarHidden;
3439 toolbarAnimationDelay : 100,
3440 toolbarAnimationSteps : 5,
3441 toolbarAnimationInfo : null,
3442 toolbarAnimationTimer : null,
3446 initEditPages : function()
3448 var range = document.createRange();
3449 range.selectNodeContents(this.pages);
3450 range.deleteContents();
3453 var editBox = document.getElementById('pageEditBoxTemplate');
3454 var contents = document.createDocumentFragment();
3455 for (var i = 0, maxi = this.sourceData.length; i < maxi; i++)
3457 var newBox = editBox.cloneNode(true);
3458 newBox.firstChild.setAttribute('value', this.sourceData[i])
3459 newBox.setAttribute('id', this.EDIT_BOX_ID_PREFIX+i);
3460 contents.appendChild(newBox);
3463 this.pages.appendChild(contents);
3466 toggleEditStyle : function(aEvent)
3468 var tabbox = document.getElementById('editTabBox');
3469 var tab = tabbox.selectedTab;
3470 if (tab.id == 'editTab-pages') {
3471 this.sourceData = this.source.value.split(/\n?----+\n?/);
3472 this.initEditPages();
3475 this.source.value = this.sourceData.join('\n----\n');
3479 insert : function(aType) {
3483 this.insertTextFor('\n----\n', this.source, 6);
3486 this.insertTextFor('\nHEADER::\n', this.source, 9);
3489 this.insertTextFor('\nFOOTER::\n', this.source, 9);
3494 this.insertTextFor(this.phraseOpenParen+this.phraseOpenParen+'EM:'+this.phraseCloseParen+this.phraseCloseParen, this.source, 5);
3497 case 'preformatted':
3498 this.insertTextFor(this.phraseOpenParen+this.phraseOpenParen+'PRE:'+this.phraseCloseParen+this.phraseCloseParen, this.source, 6);
3501 this.insertTextFor(this.phraseOpenParen+this.phraseCloseParen, this.source, 1);
3504 this.insertTextFor(this.phraseOpenParen+this.phraseOpenParen+'|http://'+this.phraseCloseParen+this.phraseCloseParen, this.source, 2);
3508 this.insertTextFor(this.phraseOpenParen+this.phraseOpenParen+'image src="" width="" height=""'+this.phraseCloseParen+this.phraseCloseParen, this.source, 13);
3514 this.onEditSource();
3517 insertTextFor : function(aString, aNode, aPosOffset)
3519 var pos = aNode.selectionStart;
3520 var value = aNode.value;
3521 aNode.value = [value.substring(0, pos), aString, value.substring(pos, value.length)].join('');
3522 aNode.selectionEnd = aNode.selectionStart = pos + (aPosOffset || 0);
3525 removePage : function(aPage)
3527 if (aPage === void(0) || this.pages.childNodes.length == 1) return;
3529 var target = document.getElementById(this.EDIT_BOX_ID_PREFIX+aPage);
3532 while (next = next.nextSibling)
3534 next.setAttribute('id', this.EDIT_BOX_ID_PREFIX + (Number(next.id.match(/\d+/)) - 1));
3536 this.pages.removeChild(target);
3538 this.sourceData.splice(aPage, 1);
3540 var maxPage = this.pages.childNodes.length-1;
3541 if (this.offset > maxPage) this.offset = maxPage;
3546 onEditSource : function() {
3547 if (this.isPrinting) return;
3551 onEditPage : function(aPage)
3553 if (aPage !== void(0)) {
3554 var target = document.getElementById(this.EDIT_BOX_ID_PREFIX+aPage);
3556 target = getNodesByXPath('descendant::*[@class="page-edit-box-main"]', target).snapshotItem(0);
3557 this.sourceData[aPage] = target.value;
3564 location.href = 'data:application/octet-stream,'+encodeURIComponent(this.source.value);
3569 var StrokeService = {
3571 className : 'stroke-dot',
3572 dragStartDelta : 10,
3576 initialized : false,
3581 canvasContext : null,
3585 init : function(aCanvas)
3587 this.initialized = true;
3589 this.canvas = aCanvas;
3590 this.canvasElement = aCanvas;
3592 var canvas = document.createElementNS('http://www.w3.org/1999/xhtml', 'canvas');
3593 canvas.width = this.canvas.boxObject.width;
3594 canvas.height = this.canvas.boxObject.height;
3595 this.canvas.appendChild(canvas);
3596 if (!('getContext' in canvas) || !canvas.getContext) {
3597 this.canvas.removeChild(canvas);
3601 this.canvasElement = canvas;
3602 this.canvasContext = canvas.getContext('2d');
3603 this.mode = 'canvas';
3606 document.documentElement.addEventListener('PresentationRedraw', this, false);
3607 window.addEventListener('resize', this, false);
3608 this.canvasElement.addEventListener('mouseup', this, false);
3609 this.canvasElement.addEventListener('mousedown', this, false);
3610 this.canvasElement.addEventListener('mousemove', this, false);
3612 this.canvasElement.addEventListener('click', this, false);
3613 this.canvasElement.addEventListener('dblclick', this, false);
3618 destroy : function()
3620 document.documentElement.removeEventListener('PresentationRedraw', this, false);
3621 window.removeEventListener('resize', this, false);
3622 if (this.canvasElement) {
3623 this.canvasElement.removeEventListener('mouseup', this, false);
3624 this.canvasElement.removeEventListener('mousedown', this, false);
3625 this.canvasElement.removeEventListener('mousemove', this, false);
3626 this.canvasElement.removeEventListener('click', this, false);
3629 this.cliclableNodesManager = null;
3630 this.canvasElement = null;
3633 this.initialized = false;
3636 handleEvent : function(aEvent)
3644 this.finish(aEvent);
3647 window.setTimeout('StrokeService.preventToSendClickEvent = false', 10);
3651 if (this.startX < 0) {
3652 this.startX = aEvent.clientX;
3653 this.startY = aEvent.clientY;
3658 if (this.startX > -1 && !this.active) {
3659 if (Math.abs(this.startX-aEvent.clientX) > Math.abs(this.dragStartDelta) ||
3660 Math.abs(this.startY-aEvent.clientY) > Math.abs(this.dragStartDelta)) {
3661 this.start(aEvent, this.startX, this.startY);
3662 this.preventToSendClickEvent = true;
3670 case 'PresentationRedraw':
3676 if (this.preventToSendClickEvent) {
3677 aEvent.stopPropagation();
3678 aEvent.preventCapture();
3679 aEvent.preventDefault();
3680 aEvent.preventBubble();
3681 this.preventToSendClickEvent = false;
3683 else if (this.cliclableNodesManager && this.cliclableNodesManager.clickableNodes) {
3684 var nodes = this.cliclableNodesManager.clickableNodes;
3685 var max = nodes.length;
3686 var x, y, width, height
3687 for (var i = 0; i < max; i++)
3689 if (nodes[i].boxObject) {
3690 x = nodes[i].boxObject.x;
3691 y = nodes[i].boxObject.y;
3692 width = nodes[i].boxObject.width;
3693 height = nodes[i].boxObject.height;
3696 x = nodes[i].offsetLeft;
3697 y = nodes[i].offsetTop;
3698 width = nodes[i].offsetWidth;
3699 height = nodes[i].offsetHeight;
3701 if (aEvent.clientX < x ||
3702 aEvent.clientX > x+width ||
3703 aEvent.clientY < y ||
3704 aEvent.clientY > y+height)
3707 var event = document.createEvent('MouseEvents');
3708 event.initMouseEvent(
3709 aEvent.type, aEvent.canBubble, aEvent.cancelable, aEvent.view,
3711 aEvent.screenX, aEvent.screenY, aEvent.clientX, aEvent.clientY,
3712 aEvent.ctrlKey, aEvent.altKey, aEvent.shiftKey, aEvent.metaKey,
3714 aEvent.relatedTarget
3716 nodes[i].dispatchEvent(event);
3723 preventToSendClickEvent : false,
3725 start : function(aEvent, aX, aY)
3728 this.trace(aEvent, aX, aY);
3731 finish : function(aEvent)
3733 if (!this.active) return;
3735 this.finishStroke();
3738 trace : function(aEvent, aX, aY)
3740 if (!this.active) return;
3741 this.addPoint((aX === void(0) ? aEvent.clientX : aX ), (aY === void(0) ? aEvent.clientY : aY ));
3744 finishStroke : function()
3746 this.active = false;
3751 addPoint : function(aX, aY)
3753 if (this.lastX != -1)
3754 this.drawLine(this.lastX, this.lastY, aX, aY);
3756 this.drawDot(aX, aY);
3764 this.active = false;
3768 if (this.mode == 'canvas') {
3769 if (this.canvasElement.lastWindowWidth != window.innerWidth ||
3770 this.canvasElement.lastWindowHeight != window.innerHeight) {
3771 this.canvasElement.width = this.canvasElement.parentNode.boxObject.width-2;
3772 this.canvasElement.height = this.canvasElement.parentNode.boxObject.height-2;
3774 this.canvasElement.lastWindowWidth = window.innerWidth;
3775 this.canvasElement.lastWindowHeight = window.innerHeight;
3777 this.canvasContext.clearRect(0, 0, this.canvasElement.width, this.canvasElement.height);
3778 this.canvasContext.strokeStyle = this.lineColor;
3779 this.canvasContext.lineWidth = this.lineWidth;
3782 var dotes = this.canvasElement.getElementsByAttribute('class', this.className);
3783 if (!dotes.length) return;
3785 var range = document.createRange();
3786 range.selectNodeContents(this.canvasElement);
3787 range.setStartBefore(dotes[0]);
3788 range.setEndAfter(dotes[dotes.length-1]);
3789 range.deleteContents();
3794 drawDot : function(aX, aY, aParent)
3796 if (this.mode == 'canvas') {
3797 this.canvasContext.strokeRect(aX, aY, 0, 0);
3798 this.canvasContext.stroke();
3801 var dot = document.createElement('spacer');
3802 dot.setAttribute('style', 'left:'+aX+'px; top:'+aY+'px');
3803 dot.setAttribute('class', this.className);
3804 (aParent || this.canvasElement).appendChild(dot);
3808 drawLine : function(aX1, aY1, aX2, aY2)
3810 if (aX1 == aX2 && aY1 == aY2) return;
3813 if (this.mode == 'canvas') {
3814 this.canvasContext.beginPath();
3815 this.canvasContext.moveTo(aX1, aY1);
3816 this.canvasContext.lineTo(aX2, aY2);
3818 this.canvasContext.bezierCurveTo(
3819 parseInt(aX1+((aX2-this.lastX)*0.3)), parseInt(aY1+((aY2-this.lastY)*0.3)),
3820 parseInt(aX1+((aX2-this.lastX)*0.6)), parseInt(aY1+((aY2-this.lastY)*0.6)),
3824 this.canvasContext.closePath();
3825 this.canvasContext.stroke();
3828 var x_move = aX2 - aX1;
3829 var y_move = aY2 - aY1;
3830 var x_diff = x_move < 0 ? 1 : -1;
3831 var y_diff = y_move < 0 ? 1 : -1;
3833 var fragment = document.createDocumentFragment();
3834 if (Math.abs(x_move) >= Math.abs(y_move)) {
3835 for (var i = x_move; i != 0; i += x_diff)
3836 this.drawDot(aX2 - i, aY2 - Math.round(y_move * i / x_move), fragment);
3839 for (var i = y_move; i != 0; i += y_diff)
3840 this.drawDot(aX2 - Math.round(x_move * i / y_move), aY2 - i, fragment);
3842 this.canvasElement.appendChild(fragment);
3848 var StrokablePresentationService = {
3850 id : 'stroke-canvas-box',
3852 strokeService : null,
3853 cliclableNodesManager : null,
3854 canvasContainer : null,
3859 init : function(aPresentation, aStrokeService)
3861 this.cliclableNodesManager = aPresentation;
3862 this.strokeService = aStrokeService;
3863 this.canvasContainer = document.getElementById('canvas').firstChild;
3864 this.check = document.getElementById('penButton');
3866 document.documentElement.addEventListener('StartDragOnCanvas', this, false);
3867 document.documentElement.addEventListener('PresentationRedraw', this, false);
3870 toggle : function(aEnable)
3880 if (!this.strokeService || !this.canvasContainer) return;
3882 this.strokeService.cliclableNodesManager = this.cliclableNodesManager;
3883 var box = document.createElement('vbox');
3884 box.setAttribute('flex', 1);
3885 box.setAttribute('id', this.id);
3886 box.style.width = this.canvasContainer.boxObject.width+'px';
3887 box.style.height = this.canvasContainer.boxObject.height+'px';
3888 this.canvas = this.canvasContainer.appendChild(box);
3889 this.strokeService.init(this.canvas);
3891 this.canvas.addEventListener('dblclick', this, false);
3896 this.strokeService.destroy();
3898 this.canvas.removeEventListener('dblclick', this, false);
3899 this.canvasContainer.removeChild(this.canvas);
3904 handleEvent : function(aEvent)
3906 switch (aEvent.type)
3911 case 'StartDragOnCanvas':
3912 if (!this.check.checked) {
3914 this.strokeService.startX = Presentation.dragStartX;
3915 this.strokeService.startY = Presentation.dragStartY;
3917 this.autoStart = true;
3921 case 'PresentationRedraw':
3922 if (this.autoStart && this.check.checked) {
3923 this.autoStart = false;
3935 toggleCheck : function()
3937 var enable = !this.check.checked;
3938 this.toggle(enable);
3939 this.check.checked = enable;
3941 this.autoStart = false;
3948 window.removeEventListener('load', init, false);
3950 Presentation.init();
3951 StrokablePresentationService.init(Presentation, StrokeService);
3953 window.addEventListener('load', init, false);
3955 function getNodesByXPath(aExpression, aContext, aLive)
3957 var d = aContext.ownerDocument || aContext;
3958 var type = aLive ? XPathResult.ORDERED_NODE_ITERATOR_TYPE : XPathResult.ORDERED_NODE_SNAPSHOT_TYPE ;
3961 nodes = d.evaluate(aExpression, aContext, null, type, null);
3964 nodes = document.evaluate(aExpression, aContext, null, type, null);
3969 // Import Node from E4X to DOM
3970 // http://ecmanaut.blogspot.com/2006/03/e4x-and-dom.html
3972 function importE4XNode( e4x, doc, aDefaultNS )
3974 aDefaultNS = aDefaultNS || XHTMLNS;
3975 var root, domTree, importMe;
3976 this.Const = this.Const || { mimeType: 'text/xml' };
3977 this.Static = this.Static || {};
3978 this.Static.parser = this.Static.parser || new DOMParser;
3979 eval('root = <testing xmlns="'+aDefaultNS+'" />;');
3981 domTree = this.Static.parser.parseFromString( root.toXMLString(),
3982 this.Const.mimeType );
3983 importMe = domTree.documentElement.firstChild;
3984 while( importMe && importMe.nodeType != 1 )
3985 importMe = importMe.nextSibling;
3986 if( !doc ) doc = document;
3987 return importMe ? doc.importNode( importMe, true ) : null;
3990 function appendE4XTo( e4x, node, doc, aDefaultNS )
3992 return node.appendChild( importE4XNode( e4x, (doc || node.ownerDocument), aDefaultNS ) );
3995 function setE4XContent( e4x, node, aDefaultNS )
3997 while( node.firstChild )
3998 node.removeChild( node.firstChild );
3999 appendE4XTo( e4x, node, aDefaultNS );
4002 // importE4XNodeで得たノードツリーを埋め込むと、XULでバインディングが適用されないことがある。
4003 // 遅延処理でこの問題を一部避けることができる(が、これでもまだダメな場合がある。menuとか。)
4004 // とりあえずXULとSVGとXHTMLはいけた。MathMLはダメだった。
4005 function importNodeTreeWithDelay(aNode, aParent, aDefaultNS, aFromTimeout)
4008 importNodeTreeWithDelayTimers--;
4013 switch (aNode.nodeType)
4015 case Node.ELEMENT_NODE:
4016 var ns = (aNode.namespaceURI || aDefaultNS);
4017 node = document.createElementNS(ns, aNode.localName);
4018 aParent.appendChild(node);
4020 var attr = aNode.attributes;
4021 for (var i = 0, maxi = attr.length; i < maxi; i++)
4022 node.setAttribute(attr[i].name, attr[i].value);
4024 if (ns == XULNS) delay = 1; else delay = 0;
4026 var children = aNode.childNodes;
4027 for (var i = 0, maxi = children.length; i < maxi; i++)
4029 importNodeTreeWithDelayTimers++;
4030 window.setTimeout(importNodeTreeWithDelay, delay, children[i], node, aDefaultNS, true);
4033 importNodeTreeWithDelay(children[i], node, aDefaultNS);
4038 aNode.nodeType == Node.TEXT_NODE &&
4039 /^\s*$/.test(aNode.nodeValue) &&
4040 (aNode.parentNode.namespaceURI || aDefaultNS) != XHTMLNS
4043 node = aParent.appendChild(aNode.cloneNode(true));
4047 var event = document.createEvent('Events');
4048 event.initEvent('CanvasContentAdded', true, true);
4049 node.dispatchEvent(event);
4053 var importNodeTreeWithDelayTimers = 0;