From 1e771f008dd196ad58b60483784022fdc2280a6a Mon Sep 17 00:00:00 2001 From: Martin Goik <goik@hdm-stuttgart.de> Date: Sun, 28 Aug 2016 09:53:12 +0200 Subject: [PATCH] Re- enabling SVG --- Doc/Sda1/Ref/Fig/xhtml.svg | 3559 +++++++++++++++++ Doc/Sda1/xmlintro.xml | 2 +- .../Extensions/Tdata/Components/intro.xml | 16 +- ws/Docbook/Extensions/Tdata/fig.xml | 40 +- 4 files changed, 3577 insertions(+), 40 deletions(-) create mode 100644 Doc/Sda1/Ref/Fig/xhtml.svg diff --git a/Doc/Sda1/Ref/Fig/xhtml.svg b/Doc/Sda1/Ref/Fig/xhtml.svg new file mode 100644 index 000000000..d383732fb --- /dev/null +++ b/Doc/Sda1/Ref/Fig/xhtml.svg @@ -0,0 +1,3559 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:ns1="https://launchpad.net/jessyink" + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + sodipodi:docname="xhtml.svg" + inkscape:version="0.48.4 r9939" + version="1.2" + id="svg2" + height="177.16534" + width="425.19684"> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="3.5066112" + inkscape:cx="210.03184" + inkscape:cy="95.426887" + inkscape:document-units="px" + inkscape:current-layer="layer6" + showgrid="true" + inkscape:window-width="1600" + inkscape:window-height="1176" + inkscape:window-x="0" + inkscape:window-y="24" + inkscape:window-maximized="1" + inkscape:snap-global="true" + showguides="true" + inkscape:guide-bbox="true" + inkscape:snap-grids="true" + units="mm"> + <inkscape:grid + units="mm" + snapvisiblegridlinesonly="true" + enabled="true" + visible="true" + empspacing="5" + id="grid5239" + type="xygrid" /> + <sodipodi:guide + id="guide3149" + position="680,750" + orientation="0,1" /> + </sodipodi:namedview> + <defs + id="defs4"> + <marker + style="overflow:visible;" + id="Arrow2Lend" + refX="0.0" + refY="0.0" + orient="auto" + inkscape:stockid="Arrow2Lend"> + <path + transform="scale(1.1) rotate(180) translate(1,0)" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + style="fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;" + id="path4332" /> + </marker> + <marker + inkscape:stockid="EmptyTriangleOutL" + orient="auto" + refY="0" + refX="0" + id="EmptyTriangleOutL" + style="overflow:visible"> + <path + id="path6166" + d="m 5.77,0 -8.65,5 0,-10 8.65,5 z" + style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:1pt" + transform="matrix(0.8,0,0,0.8,-4.8,0)" + inkscape:connector-curvature="0" /> + </marker> + <marker + style="overflow:visible" + id="DotM" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="DotM"> + <path + transform="matrix(0.4,0,0,0.4,2.96,0.4)" + style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt" + d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z" + id="path4359" + inkscape:connector-curvature="0" /> + </marker> + <marker + style="overflow:visible" + id="Arrow1Mend" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="Arrow1Mend"> + <path + transform="matrix(-0.4,0,0,-0.4,-4,0)" + style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt" + d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" + id="path5023" + inkscape:connector-curvature="0" /> + </marker> + <marker + style="overflow:visible" + id="Arrow1Mstart" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="Arrow1Mstart"> + <path + transform="matrix(0.4,0,0,0.4,4,0)" + style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt" + d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" + id="path5020" + inkscape:connector-curvature="0" /> + </marker> + <marker + style="overflow:visible" + id="Arrow1Lend" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="Arrow1Lend"> + <path + transform="matrix(-0.8,0,0,-0.8,-10,0)" + style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt" + d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" + id="path5017" + inkscape:connector-curvature="0" /> + </marker> + <marker + style="overflow:visible" + id="Arrow1Lstart" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="Arrow1Lstart"> + <path + transform="matrix(0.8,0,0,0.8,10,0)" + style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt" + d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" + id="path5014" + inkscape:connector-curvature="0" /> + </marker> + <marker + style="overflow:visible" + id="Arrow1Mstart-8" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="Arrow1Mstart"> + <path + transform="matrix(0.4,0,0,0.4,4,0)" + style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt" + d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" + id="path5020-3" + inkscape:connector-curvature="0" /> + </marker> + <marker + style="overflow:visible" + id="Arrow1Mend-2" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="Arrow1Mend"> + <path + transform="matrix(-0.4,0,0,-0.4,-4,0)" + style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt" + d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" + id="path5023-9" + inkscape:connector-curvature="0" /> + </marker> + <marker + style="overflow:visible" + id="Arrow1Mstart-4" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="Arrow1Mstart"> + <path + transform="matrix(0.4,0,0,0.4,4,0)" + style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt" + d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" + id="path5020-1" + inkscape:connector-curvature="0" /> + </marker> + <marker + style="overflow:visible" + id="Arrow1Mend-22" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="Arrow1Mend"> + <path + transform="matrix(-0.4,0,0,-0.4,-4,0)" + style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt" + d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" + id="path5023-1" + inkscape:connector-curvature="0" /> + </marker> + <marker + style="overflow:visible" + id="Arrow1Mstart-6" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="Arrow1Mstart"> + <path + transform="matrix(0.4,0,0,0.4,4,0)" + style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt" + d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" + id="path5020-8" + inkscape:connector-curvature="0" /> + </marker> + <marker + style="overflow:visible" + id="Arrow1Mend-6" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="Arrow1Mend"> + <path + transform="matrix(-0.4,0,0,-0.4,-4,0)" + style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt" + d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" + id="path5023-5" + inkscape:connector-curvature="0" /> + </marker> + <marker + style="overflow:visible" + id="DotMo" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="DotMo"> + <path + transform="matrix(0.4,0,0,0.4,2.96,0.4)" + style="fill:#d40000;fill-rule:evenodd;stroke:#d40000;stroke-width:1pt" + d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z" + id="path5187" + inkscape:connector-curvature="0" /> + </marker> + <marker + style="overflow:visible" + id="Arrow1Mend-6o" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="Arrow1Mend-6o"> + <path + transform="matrix(-0.4,0,0,-0.4,-4,0)" + style="fill:#d40000;fill-rule:evenodd;stroke:#d40000;stroke-width:1pt" + d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" + id="path5190" + inkscape:connector-curvature="0" /> + </marker> + <marker + style="overflow:visible" + id="DotMo1" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="DotMo1"> + <path + transform="matrix(0.4,0,0,0.4,2.96,0.4)" + style="fill:#000000;fill-rule:evenodd;stroke:#000000;stroke-width:1pt" + d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z" + id="path6031" + inkscape:connector-curvature="0" /> + </marker> + <marker + style="overflow:visible" + id="Arrow1Mend-6n" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="Arrow1Mend-6n"> + <path + transform="matrix(-0.4,0,0,-0.4,-4,0)" + style="fill:#000000;fill-rule:evenodd;stroke:#000000;stroke-width:1pt" + d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" + id="path6034" + inkscape:connector-curvature="0" /> + </marker> + <marker + style="overflow:visible" + id="DotMoc" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="DotMoc"> + <path + transform="matrix(0.4,0,0,0.4,2.96,0.4)" + style="fill:#000000;fill-rule:evenodd;stroke:#000000;stroke-width:1pt" + d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z" + id="path6037" + inkscape:connector-curvature="0" /> + </marker> + <marker + style="overflow:visible" + id="Arrow1Mend-6F" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="Arrow1Mend-6F"> + <path + transform="matrix(-0.4,0,0,-0.4,-4,0)" + style="fill:#000000;fill-rule:evenodd;stroke:#000000;stroke-width:1pt" + d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" + id="path6040" + inkscape:connector-curvature="0" /> + </marker> + <marker + style="overflow:visible" + id="DotMocK" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="DotMocK"> + <path + transform="matrix(0.4,0,0,0.4,2.96,0.4)" + style="fill:#000000;fill-rule:evenodd;stroke:#000000;stroke-width:1pt" + d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z" + id="path6279" + inkscape:connector-curvature="0" /> + </marker> + <marker + style="overflow:visible" + id="Arrow1Mend-6Fa" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="Arrow1Mend-6Fa"> + <path + transform="matrix(-0.4,0,0,-0.4,-4,0)" + style="fill:#000000;fill-rule:evenodd;stroke:#000000;stroke-width:1pt" + d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" + id="path6282" + inkscape:connector-curvature="0" /> + </marker> + <marker + style="overflow:visible" + id="DotMo17" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="DotMo17"> + <path + transform="matrix(0.4,0,0,0.4,2.96,0.4)" + style="fill:#d40000;fill-rule:evenodd;stroke:#d40000;stroke-width:1pt" + d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z" + id="path6529" + inkscape:connector-curvature="0" /> + </marker> + <marker + style="overflow:visible" + id="Arrow1Mend-6nl" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="Arrow1Mend-6nl"> + <path + transform="matrix(-0.4,0,0,-0.4,-4,0)" + style="fill:#d40000;fill-rule:evenodd;stroke:#d40000;stroke-width:1pt" + d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" + id="path6532" + inkscape:connector-curvature="0" /> + </marker> + <marker + style="overflow:visible" + id="DotMocKE" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="DotMocKE"> + <path + transform="matrix(0.4,0,0,0.4,2.96,0.4)" + style="fill:#d40000;fill-rule:evenodd;stroke:#d40000;stroke-width:1pt" + d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z" + id="path6535" + inkscape:connector-curvature="0" /> + </marker> + <marker + style="overflow:visible" + id="Arrow1Mend-6FaK" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="Arrow1Mend-6FaK"> + <path + transform="matrix(-0.4,0,0,-0.4,-4,0)" + style="fill:#d40000;fill-rule:evenodd;stroke:#d40000;stroke-width:1pt" + d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" + id="path6538" + inkscape:connector-curvature="0" /> + </marker> + <marker + style="overflow:visible" + id="Arrow1Mend-6-8" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="Arrow1Mend"> + <path + transform="matrix(-0.4,0,0,-0.4,-4,0)" + style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt" + d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" + id="path5023-5-4" + inkscape:connector-curvature="0" /> + </marker> + <marker + inkscape:stockid="EmptyTriangleOutL" + orient="auto" + refY="0" + refX="0" + id="EmptyTriangleOutL-6" + style="overflow:visible"> + <path + inkscape:connector-curvature="0" + id="path6166-3" + d="m 5.77,0 -8.65,5 0,-10 8.65,5 z" + style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:1pt" + transform="matrix(0.8,0,0,0.8,-4.8,0)" /> + </marker> + <marker + inkscape:stockid="EmptyTriangleOutL" + orient="auto" + refY="0" + refX="0" + id="EmptyTriangleOutL-3" + style="overflow:visible"> + <path + inkscape:connector-curvature="0" + id="path6166-9" + d="m 5.77,0 -8.65,5 0,-10 8.65,5 z" + style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:1pt" + transform="matrix(0.8,0,0,0.8,-4.8,0)" /> + </marker> + <marker + inkscape:stockid="EmptyTriangleOutL" + orient="auto" + refY="0" + refX="0" + id="EmptyTriangleOutL-9" + style="overflow:visible"> + <path + inkscape:connector-curvature="0" + id="path6166-5" + d="m 5.77,0 -8.65,5 0,-10 8.65,5 z" + style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:1pt" + transform="matrix(0.8,0,0,0.8,-4.8,0)" /> + </marker> + <marker + inkscape:stockid="EmptyTriangleOutL" + orient="auto" + refY="0" + refX="0" + id="EmptyTriangleOutL-8" + style="overflow:visible"> + <path + inkscape:connector-curvature="0" + id="path6166-53" + d="m 5.77,0 -8.65,5 0,-10 8.65,5 z" + style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:1pt" + transform="matrix(0.8,0,0,0.8,-4.8,0)" /> + </marker> + <marker + style="overflow:visible" + id="Arrow1Lends" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="Arrow1Lends"> + <path + transform="matrix(-0.8,0,0,-0.8,-10,0)" + style="fill:#ff0000;fill-rule:evenodd;stroke:#ff0000;stroke-width:1pt" + d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" + id="path4563" + inkscape:connector-curvature="0" /> + </marker> + <marker + style="overflow:visible" + id="Arrow1LendB" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="Arrow1LendB"> + <path + transform="matrix(-0.8,0,0,-0.8,-10,0)" + style="fill:#00ff00;fill-rule:evenodd;stroke:#00ff00;stroke-width:1pt" + d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" + id="path4992" + inkscape:connector-curvature="0" /> + </marker> + <marker + style="overflow:visible" + id="Arrow1LendU" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="Arrow1LendU"> + <path + transform="matrix(-0.8,0,0,-0.8,-10,0)" + style="fill:#ff00ff;fill-rule:evenodd;stroke:#ff00ff;stroke-width:1pt" + d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" + id="path5429" + inkscape:connector-curvature="0" /> + </marker> + <marker + style="overflow:visible;" + id="Arrow2Lend2" + refX="0.0" + refY="0.0" + orient="auto" + inkscape:stockid="Arrow2Lend2"> + <path + transform="scale(1.1) rotate(180) translate(1,0)" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + style="stroke-linejoin:round;stroke:#ff00ff;stroke-width:0.62500000;fill:#ff00ff;fill-rule:evenodd" + id="path9787" /> + </marker> + <marker + style="overflow:visible;" + id="Arrow2LendN" + refX="0.0" + refY="0.0" + orient="auto" + inkscape:stockid="Arrow2LendN"> + <path + transform="scale(1.1) rotate(180) translate(1,0)" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + style="stroke-linejoin:round;stroke:#00ff00;stroke-width:0.62500000;fill:#00ff00;fill-rule:evenodd" + id="path10254" /> + </marker> + <marker + style="overflow:visible;" + id="Arrow2LendL" + refX="0.0" + refY="0.0" + orient="auto" + inkscape:stockid="Arrow2LendL"> + <path + transform="scale(1.1) rotate(180) translate(1,0)" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + style="stroke-linejoin:round;stroke:#ff0000;stroke-width:0.62500000;fill:#ff0000;fill-rule:evenodd" + id="path10727" /> + </marker> + </defs> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title /> + </cc:Work> + </rdf:RDF> + </metadata> + <image + y="77.165352" + x="190" + id="image3621" + xlink:href="data:image/png;base64,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 3677NUBWeseOHVWtaHXf8g2nOXMekWTpheefZxN//PGnufPmfvLxx6ysP5OoXd9+8w19wbiaQi2t V6srd0uzENu4BoOhU8dOc+bMads2q8kM/6BO+GdKYX+PlqVdv/7aWFbNrmfwXvdnavJnks1mq6mp wwS3apXekPLeX0gFCLbwp6d933v33bCwMJpitVoFQaA/Q0LUR3b9PYF7JeQrFwDMZrP+eDIjvXm1 Gj582Lz58y9evJiQkKAmfv7FZ9dcc02LFi0AQJXVNP5NI1+7AnmggdUbKpcQWZYFQai/aEO4MY1b VVW1bt26ufPmfvjBB1fIsNk7oUYEIfRdmX+QlC8+/5x+ycvLe+zxx//94Qcmkxma1MGa3RvBe92f qcmfQHv37eM5rlOnTlarVRRF+iSmzWY7ceIExqR796u0xb12NWrhDzEx0XFxsfRjsZgP/n6wV+/e TDzv5fD++++PvX3s9f36jRg58pVXXpZl6QoCb43cuLhY+uR9ZVXlrNmzrrv++gkTJ5w6dUqVzmr1 4IMPAsBNAwb06t27V+/eTZDeu3evqKioL7/6Uk2prLz866+7hg0bqpMVyOqdO38ePGQIIRiA/P77 7716937jzTdo+ccee+yFF19sslsCpbBaffrZpyNHjerTt+/wEcPfefddWsCvWyRJ3Lhp44iRI6+7 /vrb77j9s88/Y7n98usv4++dcN311z/62KP33DOelTvmttveeeftK2zcNm0yx44dW1paKoru4PoE z1KdYLfbpk+fPnXaVJvNRk347bff7p1w7/X9+v190qTS0jOHDx+eMHHCdddff99995WWnqG1tm7d es8991zfr9/AQYOefPJJm63O1wPHjh31KyWQtxv1UTt5RGQEAERHR8fFxUZFRTbJFV5vXLli9fa6 QP2fLUY9+f3339865rYbbrxx+fLlkiRegTJ/4IfnOLPZdPbsWQBy1VU52dkdAMjZs2fNZhNH3y6u d4KHGrrwp7X0oTubyHzfsuW1b7/7dtas2ZkZGadPn17+jxWYkMmTJgfm3ki5AACwYsWK8vKKLa++ WlNbu3TpM341WbHiH48/PvfDD95XpvpGyxcEw+DBg7d+sfWeu++hKV9++XVYWFi/669voNVdunSt ra09ebIwKyvrwMGDUVGR+/cfuPuuuwkhvx86NHzE8KbM3L5u8dcW589fWLHi2alTH7yp/02VVVWX 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 " + height="92.5" + width="227" + style="fill:#ff0000" /> + <g + style="display:inline" + inkscape:groupmode="layer" + id="layer6" + inkscape:label="Classification" + transform="translate(0,-566.98465)"> + <path + sodipodi:type="arc" + style="color:#000000;fill:none;stroke:#ff0000;stroke-width:1.47704296;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" + id="path3632" + sodipodi:cx="70" + sodipodi:cy="203.24802" + sodipodi:rx="15" + sodipodi:ry="17.5" + d="m 85,203.24802 c 0,9.66498 -6.715729,17.5 -15,17.5 -8.284271,0 -15,-7.83502 -15,-17.5 0,-9.66499 6.715729,-17.5 15,-17.5 8.284271,0 15,7.83501 15,17.5 z" + transform="matrix(1.0451736,0,0,0.43855626,150.3645,561.38717)" /> + <path + sodipodi:type="arc" + style="color:#000000;fill:none;stroke:#ff00ff;stroke-width:1.5672979;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" + id="path3075" + sodipodi:cx="145" + sodipodi:cy="150.74802" + sodipodi:rx="40" + sodipodi:ry="20" + d="m 185,150.74802 c 0,11.04569 -17.90861,20 -40,20 -22.09139,0 -40,-8.95431 -40,-20 0,-11.0457 17.90861,-20 40,-20 22.09139,0 40,8.9543 40,20 z" + transform="matrix(1,0,0,0.40709606,79.328948,666.75401)" /> + <path + sodipodi:type="arc" + style="color:#000000;fill:none;stroke:#00ff00;stroke-width:1.50921479;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" + id="path3077" + sodipodi:cx="272.5" + sodipodi:cy="215.74802" + sodipodi:rx="57.5" + sodipodi:ry="15" + d="m 330,215.74802 c 0,8.28427 -25.74363,15 -57.5,15 -31.75637,0 -57.5,-6.71573 -57.5,-15 0,-8.28427 25.74363,-15 57.5,-15 31.75637,0 57.5,6.71573 57.5,15 z" + transform="matrix(0.60227561,0,0,0.72895819,55.745365,546.74665)" /> + <text + sodipodi:linespacing="125%" + id="text3164" + y="584.15002" + x="10" + style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Monospace;-inkscape-font-specification:'Monospace, Normal'" + xml:space="preserve"><tspan + y="584.15002" + x="10" + id="tspan3166" + sodipodi:role="line"><!DOCTYPE html></tspan></text> + <text + sodipodi:linespacing="125%" + id="text3168" + y="599.15002" + x="20" + style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Monospace;-inkscape-font-specification:'Monospace, Normal'" + xml:space="preserve"><tspan + y="599.15002" + x="20" + id="tspan3170" + sodipodi:role="line"><html xmlns="http://www.w3.org/1999/xhtml"></tspan></text> + <text + sodipodi:linespacing="125%" + id="text3172" + y="614.15002" + x="20" + style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Monospace;-inkscape-font-specification:'Monospace, Normal'" + xml:space="preserve"><tspan + y="614.15002" + x="20" + id="tspan3174" + sodipodi:role="line"><head></tspan></text> + <text + sodipodi:linespacing="125%" + id="text3176" + y="629.15002" + x="30" + style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Monospace;-inkscape-font-specification:'Monospace, Normal'" + xml:space="preserve"><tspan + y="629.15002" + x="30" + id="tspan3178" + sodipodi:role="line"><title><tspan + id="tspan3208" + style="fill:#ff0000">Intro</tspan></title></tspan></text> + <text + sodipodi:linespacing="125%" + id="text3180" + y="644.15002" + x="20" + style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Monospace;-inkscape-font-specification:'Monospace, Normal'" + xml:space="preserve"><tspan + y="644.15002" + x="20" + id="tspan3182" + sodipodi:role="line"></head></tspan></text> + <text + sodipodi:linespacing="125%" + id="text3184" + y="659.15002" + x="20" + style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Monospace;-inkscape-font-specification:'Monospace, Normal'" + xml:space="preserve"><tspan + y="659.15002" + x="20" + id="tspan3186" + sodipodi:role="line"><body></tspan></text> + <text + sodipodi:linespacing="125%" + id="text3188" + y="674.15002" + x="30" + style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Monospace;-inkscape-font-specification:'Monospace, Normal'" + xml:space="preserve"><tspan + y="674.15002" + x="30" + id="tspan3190" + sodipodi:role="line"><h1><tspan + id="tspan3210" + style="fill:#00ff00">Start</tspan></h1></tspan></text> + <text + sodipodi:linespacing="125%" + id="text3192" + y="689.15002" + x="30" + style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Monospace;-inkscape-font-specification:'Monospace, Normal'" + xml:space="preserve"><tspan + y="689.15002" + x="30" + id="tspan3194" + sodipodi:role="line"><p><tspan + id="tspan7253" + style="fill:#ff00ff">Very simple!</tspan></p></tspan></text> + <text + transform="translate(0,478.40198)" + sodipodi:linespacing="125%" + id="text3196" + y="148.25566" + x="37.07283" + style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Monospace;-inkscape-font-specification:'Monospace, Normal'" + xml:space="preserve"><tspan + y="148.25566" + x="37.07283" + id="tspan3198" + sodipodi:role="line" /></text> + <text + sodipodi:linespacing="125%" + id="text3200" + y="704.15002" + x="20" + style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Monospace;-inkscape-font-specification:'Monospace, Normal'" + xml:space="preserve"><tspan + y="704.15002" + x="20" + id="tspan3202" + sodipodi:role="line"></body></tspan></text> + <text + sodipodi:linespacing="125%" + id="text3204" + y="719.15002" + x="10" + style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Monospace;-inkscape-font-specification:'Monospace, Normal'" + xml:space="preserve"><tspan + y="719.15002" + x="10" + id="tspan3206" + sodipodi:role="line"></html></tspan></text> + <path + sodipodi:nodetypes="cscc" + inkscape:connector-curvature="0" + id="path4061" + d="m 115.85553,630.15753 c 0,0 15.89571,7.72393 44.99999,15 20,5 45,5 45,5 l 0,0" + style="stroke-linejoin:miter;enable-background:accumulate;marker-end:url(#Arrow2LendL);stroke-opacity:1;color:#000000;stroke-dashoffset:0;visibility:visible;stroke:#ff0000;stroke-linecap:butt;stroke-miterlimit:4;marker:none;stroke-dasharray:none;overflow:visible;stroke-width:1;display:inline;fill:none" /> + <path + sodipodi:nodetypes="cssc" + transform="translate(0,566.98465)" + inkscape:connector-curvature="0" + id="path5787" + d="m 90,97.165344 c 0,0 0,-5 20,-15 14.14214,-7.071068 45,5 60,19.999996 10,10 25,25 25,25" + style="color:#000000;fill:none;stroke:#00ff00;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;marker-end:url(#Arrow2LendN);visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> + <path + sodipodi:nodetypes="csc" + transform="translate(0,566.98465)" + inkscape:connector-curvature="0" + id="path7255" + d="m 135,127.16534 c 0,0 10.85787,7.92893 25,15 10,5 25,15 25,15" + style="stroke-linejoin:miter;enable-background:accumulate;marker-end:url(#Arrow2Lend2);stroke-opacity:1;color:#000000;stroke-dashoffset:0;visibility:visible;stroke:#ff00ff;stroke-linecap:butt;stroke-miterlimit:4;marker:none;stroke-dasharray:none;overflow:visible;stroke-width:1;display:inline;fill:none" /> + </g> + <script + ns1:version="1.5.5" + id="JessyInk">// Copyright 2008, 2009 Hannes Hochreiner +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see http://www.gnu.org/licenses/. + +// Set onload event handler. +window.onload = jessyInkInit; + +// Creating a namespace dictionary. The standard Inkscape namespaces are taken from inkex.py. +var NSS = new Object(); +NSS['sodipodi']='http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd'; +NSS['cc']='http://web.resource.org/cc/'; +NSS['svg']='http://www.w3.org/2000/svg'; +NSS['dc']='http://purl.org/dc/elements/1.1/'; +NSS['rdf']='http://www.w3.org/1999/02/22-rdf-syntax-ns#'; +NSS['inkscape']='http://www.inkscape.org/namespaces/inkscape'; +NSS['xlink']='http://www.w3.org/1999/xlink'; +NSS['xml']='http://www.w3.org/XML/1998/namespace'; +NSS['jessyink']='https://launchpad.net/jessyink'; + +// Keycodes. +var LEFT_KEY = 37; // cursor left keycode +var UP_KEY = 38; // cursor up keycode +var RIGHT_KEY = 39; // cursor right keycode +var DOWN_KEY = 40; // cursor down keycode +var PAGE_UP_KEY = 33; // page up keycode +var PAGE_DOWN_KEY = 34; // page down keycode +var HOME_KEY = 36; // home keycode +var END_KEY = 35; // end keycode +var ENTER_KEY = 13; // next slide +var SPACE_KEY = 32; +var ESCAPE_KEY = 27; + +// Presentation modes. +var SLIDE_MODE = 1; +var INDEX_MODE = 2; +var DRAWING_MODE = 3; + +// Mouse handler actions. +var MOUSE_UP = 1; +var MOUSE_DOWN = 2; +var MOUSE_MOVE = 3; +var MOUSE_WHEEL = 4; + +// Parameters. +var ROOT_NODE = document.getElementsByTagNameNS(NSS["svg"], "svg")[0]; +var HEIGHT = 0; +var WIDTH = 0; +var INDEX_COLUMNS_DEFAULT = 4; +var INDEX_COLUMNS = INDEX_COLUMNS_DEFAULT; +var INDEX_OFFSET = 0; +var STATE_START = -1; +var STATE_END = -2; +var BACKGROUND_COLOR = null; +var slides = new Array(); + +// Initialisation. +var currentMode = SLIDE_MODE; +var masterSlide = null; +var activeSlide = 0; +var activeEffect = 0; +var timeStep = 30; // 40 ms equal 25 frames per second. +var lastFrameTime = null; +var processingEffect = false; +var transCounter = 0; +var effectArray = 0; +var defaultTransitionInDict = new Object(); +defaultTransitionInDict["name"] = "appear"; +var defaultTransitionOutDict = new Object(); +defaultTransitionOutDict["name"] = "appear"; +var jessyInkInitialised = false; + +// Initialise char and key code dictionaries. +var charCodeDictionary = getDefaultCharCodeDictionary(); +var keyCodeDictionary = getDefaultKeyCodeDictionary(); + +// Initialise mouse handler dictionary. +var mouseHandlerDictionary = getDefaultMouseHandlerDictionary(); + +var progress_bar_visible = false; +var timer_elapsed = 0; +var timer_start = timer_elapsed; +var timer_duration = 15; // 15 minutes + +var history_counter = 0; +var history_original_elements = new Array(); +var history_presentation_elements = new Array(); + +var mouse_original_path = null; +var mouse_presentation_path = null; +var mouse_last_x = -1; +var mouse_last_y = -1; +var mouse_min_dist_sqr = 3 * 3; +var path_colour = "red"; +var path_width_default = 3; +var path_width = path_width_default; +var path_paint_width = path_width; + +var number_of_added_slides = 0; + +/** Initialisation function. + * The whole presentation is set-up in this function. + */ +function jessyInkInit() +{ + // Make sure we only execute this code once. Double execution can occur if the onload event handler is set + // in the main svg tag as well (as was recommended in earlier versions). Executing this function twice does + // not lead to any problems, but it takes more time. + if (jessyInkInitialised) + return; + + // Making the presentation scaleable. + var VIEWBOX = ROOT_NODE.getAttribute("viewBox"); + + if (VIEWBOX) + { + WIDTH = ROOT_NODE.viewBox.animVal.width; + HEIGHT = ROOT_NODE.viewBox.animVal.height; + } + else + { + HEIGHT = parseFloat(ROOT_NODE.getAttribute("height")); + WIDTH = parseFloat(ROOT_NODE.getAttribute("width")); + ROOT_NODE.setAttribute("viewBox", "0 0 " + WIDTH + " " + HEIGHT); + } + + ROOT_NODE.setAttribute("width", "100%"); + ROOT_NODE.setAttribute("height", "100%"); + + // Setting the background color. + var namedViews = document.getElementsByTagNameNS(NSS["sodipodi"], "namedview"); + + for (var counter = 0; counter < namedViews.length; counter++) + { + if (namedViews[counter].hasAttribute("id") && namedViews[counter].hasAttribute("pagecolor")) + { + if (namedViews[counter].getAttribute("id") == "base") + { + BACKGROUND_COLOR = namedViews[counter].getAttribute("pagecolor"); + var newAttribute = "background-color:" + BACKGROUND_COLOR + ";"; + + if (ROOT_NODE.hasAttribute("style")) + newAttribute += ROOT_NODE.getAttribute("style"); + + ROOT_NODE.setAttribute("style", newAttribute); + } + } + } + + // Defining clip-path. + var defsNodes = document.getElementsByTagNameNS(NSS["svg"], "defs"); + + if (defsNodes.length > 0) + { + var existingClipPath = document.getElementById("jessyInkSlideClipPath"); + + if (!existingClipPath) + { + var rectNode = document.createElementNS(NSS["svg"], "rect"); + var clipPath = document.createElementNS(NSS["svg"], "clipPath"); + + rectNode.setAttribute("x", 0); + rectNode.setAttribute("y", 0); + rectNode.setAttribute("width", WIDTH); + rectNode.setAttribute("height", HEIGHT); + + clipPath.setAttribute("id", "jessyInkSlideClipPath"); + clipPath.setAttribute("clipPathUnits", "userSpaceOnUse"); + + clipPath.appendChild(rectNode); + defsNodes[0].appendChild(clipPath); + } + } + + // Making a list of the slide and finding the master slide. + var nodes = document.getElementsByTagNameNS(NSS["svg"], "g"); + var tempSlides = new Array(); + var existingJessyInkPresentationLayer = null; + + for (var counter = 0; counter < nodes.length; counter++) + { + if (nodes[counter].getAttributeNS(NSS["inkscape"], "groupmode") && (nodes[counter].getAttributeNS(NSS["inkscape"], "groupmode") == "layer")) + { + if (nodes[counter].getAttributeNS(NSS["inkscape"], "label") && nodes[counter].getAttributeNS(NSS["jessyink"], "masterSlide") == "masterSlide") + masterSlide = nodes[counter]; + else if (nodes[counter].getAttributeNS(NSS["inkscape"], "label") && nodes[counter].getAttributeNS(NSS["jessyink"], "presentationLayer") == "presentationLayer") + existingJessyInkPresentationLayer = nodes[counter]; + else + tempSlides.push(nodes[counter].getAttribute("id")); + } + else if (nodes[counter].getAttributeNS(NSS['jessyink'], 'element')) + { + handleElement(nodes[counter]); + } + } + + // Hide master slide set default transitions. + if (masterSlide) + { + masterSlide.style.display = "none"; + + if (masterSlide.hasAttributeNS(NSS["jessyink"], "transitionIn")) + defaultTransitionInDict = propStrToDict(masterSlide.getAttributeNS(NSS["jessyink"], "transitionIn")); + + if (masterSlide.hasAttributeNS(NSS["jessyink"], "transitionOut")) + defaultTransitionOutDict = propStrToDict(masterSlide.getAttributeNS(NSS["jessyink"], "transitionOut")); + } + + if (existingJessyInkPresentationLayer != null) + { + existingJessyInkPresentationLayer.parentNode.removeChild(existingJessyInkPresentationLayer); + } + + // Set start slide. + var hashObj = new LocationHash(window.location.hash); + + activeSlide = hashObj.slideNumber; + activeEffect = hashObj.effectNumber; + + if (activeSlide < 0) + activeSlide = 0; + else if (activeSlide >= tempSlides.length) + activeSlide = tempSlides.length - 1; + + var originalNode = document.getElementById(tempSlides[counter]); + + var JessyInkPresentationLayer = document.createElementNS(NSS["svg"], "g"); + JessyInkPresentationLayer.setAttributeNS(NSS["inkscape"], "groupmode", "layer"); + JessyInkPresentationLayer.setAttributeNS(NSS["inkscape"], "label", "JessyInk Presentation Layer"); + JessyInkPresentationLayer.setAttributeNS(NSS["jessyink"], "presentationLayer", "presentationLayer"); + JessyInkPresentationLayer.setAttribute("id", "jessyink_presentation_layer"); + JessyInkPresentationLayer.style.display = "inherit"; + ROOT_NODE.appendChild(JessyInkPresentationLayer); + + // Gathering all the information about the transitions and effects of the slides, set the background + // from the master slide and substitute the auto-texts. + for (var counter = 0; counter < tempSlides.length; counter++) + { + var originalNode = document.getElementById(tempSlides[counter]); + originalNode.style.display = "none"; + var node = suffixNodeIds(originalNode.cloneNode(true), "_" + counter); + JessyInkPresentationLayer.appendChild(node); + slides[counter] = new Object(); + slides[counter]["original_element"] = originalNode; + slides[counter]["element"] = node; + + // Set build in transition. + slides[counter]["transitionIn"] = new Object(); + + var dict; + + if (node.hasAttributeNS(NSS["jessyink"], "transitionIn")) + dict = propStrToDict(node.getAttributeNS(NSS["jessyink"], "transitionIn")); + else + dict = defaultTransitionInDict; + + slides[counter]["transitionIn"]["name"] = dict["name"]; + slides[counter]["transitionIn"]["options"] = new Object(); + + for (key in dict) + if (key != "name") + slides[counter]["transitionIn"]["options"][key] = dict[key]; + + // Set build out transition. + slides[counter]["transitionOut"] = new Object(); + + if (node.hasAttributeNS(NSS["jessyink"], "transitionOut")) + dict = propStrToDict(node.getAttributeNS(NSS["jessyink"], "transitionOut")); + else + dict = defaultTransitionOutDict; + + slides[counter]["transitionOut"]["name"] = dict["name"]; + slides[counter]["transitionOut"]["options"] = new Object(); + + for (key in dict) + if (key != "name") + slides[counter]["transitionOut"]["options"][key] = dict[key]; + + // Copy master slide content. + if (masterSlide) + { + var clonedNode = suffixNodeIds(masterSlide.cloneNode(true), "_" + counter); + clonedNode.removeAttributeNS(NSS["inkscape"], "groupmode"); + clonedNode.removeAttributeNS(NSS["inkscape"], "label"); + clonedNode.style.display = "inherit"; + + node.insertBefore(clonedNode, node.firstChild); + } + + // Setting clip path. + node.setAttribute("clip-path", "url(#jessyInkSlideClipPath)"); + + // Substitute auto texts. + substituteAutoTexts(node, node.getAttributeNS(NSS["inkscape"], "label"), counter + 1, tempSlides.length); + + node.removeAttributeNS(NSS["inkscape"], "groupmode"); + node.removeAttributeNS(NSS["inkscape"], "label"); + + // Set effects. + var tempEffects = new Array(); + var groups = new Object(); + + for (var IOCounter = 0; IOCounter <= 1; IOCounter++) + { + var propName = ""; + var dir = 0; + + if (IOCounter == 0) + { + propName = "effectIn"; + dir = 1; + } + else if (IOCounter == 1) + { + propName = "effectOut"; + dir = -1; + } + + var effects = getElementsByPropertyNS(node, NSS["jessyink"], propName); + + for (var effectCounter = 0; effectCounter < effects.length; effectCounter++) + { + var element = document.getElementById(effects[effectCounter]); + var dict = propStrToDict(element.getAttributeNS(NSS["jessyink"], propName)); + + // Put every element that has an effect associated with it, into its own group. + // Unless of course, we already put it into its own group. + if (!(groups[element.id])) + { + var newGroup = document.createElementNS(NSS["svg"], "g"); + + element.parentNode.insertBefore(newGroup, element); + newGroup.appendChild(element.parentNode.removeChild(element)); + groups[element.id] = newGroup; + } + + var effectDict = new Object(); + + effectDict["effect"] = dict["name"]; + effectDict["dir"] = dir; + effectDict["element"] = groups[element.id]; + + for (var option in dict) + { + if ((option != "name") && (option != "order")) + { + if (!effectDict["options"]) + effectDict["options"] = new Object(); + + effectDict["options"][option] = dict[option]; + } + } + + if (!tempEffects[dict["order"]]) + tempEffects[dict["order"]] = new Array(); + + tempEffects[dict["order"]][tempEffects[dict["order"]].length] = effectDict; + } + } + + // Make invisible, but keep in rendering tree to ensure that bounding box can be calculated. + node.setAttribute("opacity",0); + node.style.display = "inherit"; + + // Create a transform group. + var transformGroup = document.createElementNS(NSS["svg"], "g"); + + // Add content to transform group. + while (node.firstChild) + transformGroup.appendChild(node.firstChild); + + // Transfer the transform attribute from the node to the transform group. + if (node.getAttribute("transform")) + { + transformGroup.setAttribute("transform", node.getAttribute("transform")); + node.removeAttribute("transform"); + } + + // Create a view group. + var viewGroup = document.createElementNS(NSS["svg"], "g"); + + viewGroup.appendChild(transformGroup); + slides[counter]["viewGroup"] = node.appendChild(viewGroup); + + // Insert background. + if (BACKGROUND_COLOR != null) + { + var rectNode = document.createElementNS(NSS["svg"], "rect"); + + rectNode.setAttribute("x", 0); + rectNode.setAttribute("y", 0); + rectNode.setAttribute("width", WIDTH); + rectNode.setAttribute("height", HEIGHT); + rectNode.setAttribute("id", "jessyInkBackground" + counter); + rectNode.setAttribute("fill", BACKGROUND_COLOR); + + slides[counter]["viewGroup"].insertBefore(rectNode, slides[counter]["viewGroup"].firstChild); + } + + // Set views. + var tempViews = new Array(); + var views = getElementsByPropertyNS(node, NSS["jessyink"], "view"); + var matrixOld = (new matrixSVG()).fromElements(1, 0, 0, 0, 1, 0, 0, 0, 1); + + // Set initial view even if there are no other views. + slides[counter]["viewGroup"].setAttribute("transform", matrixOld.toAttribute()); + slides[counter].initialView = matrixOld.toAttribute(); + + for (var viewCounter = 0; viewCounter < views.length; viewCounter++) + { + var element = document.getElementById(views[viewCounter]); + var dict = propStrToDict(element.getAttributeNS(NSS["jessyink"], "view")); + + if (dict["order"] == 0) + { + matrixOld = pointMatrixToTransformation(rectToMatrix(element)).mult((new matrixSVG()).fromSVGMatrix(slides[counter].viewGroup.getScreenCTM()).inv().mult((new matrixSVG()).fromSVGMatrix(element.parentNode.getScreenCTM())).inv()); + slides[counter].initialView = matrixOld.toAttribute(); + } + else + { + var effectDict = new Object(); + + effectDict["effect"] = dict["name"]; + effectDict["dir"] = 1; + effectDict["element"] = slides[counter]["viewGroup"]; + effectDict["order"] = dict["order"]; + + for (var option in dict) + { + if ((option != "name") && (option != "order")) + { + if (!effectDict["options"]) + effectDict["options"] = new Object(); + + effectDict["options"][option] = dict[option]; + } + } + + effectDict["options"]["matrixNew"] = pointMatrixToTransformation(rectToMatrix(element)).mult((new matrixSVG()).fromSVGMatrix(slides[counter].viewGroup.getScreenCTM()).inv().mult((new matrixSVG()).fromSVGMatrix(element.parentNode.getScreenCTM())).inv()); + + tempViews[dict["order"]] = effectDict; + } + + // Remove element. + element.parentNode.removeChild(element); + } + + // Consolidate view array and append it to the effect array. + if (tempViews.length > 0) + { + for (var viewCounter = 0; viewCounter < tempViews.length; viewCounter++) + { + if (tempViews[viewCounter]) + { + tempViews[viewCounter]["options"]["matrixOld"] = matrixOld; + matrixOld = tempViews[viewCounter]["options"]["matrixNew"]; + + if (!tempEffects[tempViews[viewCounter]["order"]]) + tempEffects[tempViews[viewCounter]["order"]] = new Array(); + + tempEffects[tempViews[viewCounter]["order"]][tempEffects[tempViews[viewCounter]["order"]].length] = tempViews[viewCounter]; + } + } + } + + // Set consolidated effect array. + if (tempEffects.length > 0) + { + slides[counter]["effects"] = new Array(); + + for (var effectCounter = 0; effectCounter < tempEffects.length; effectCounter++) + { + if (tempEffects[effectCounter]) + slides[counter]["effects"][slides[counter]["effects"].length] = tempEffects[effectCounter]; + } + } + + node.setAttribute("onmouseover", "if ((currentMode == INDEX_MODE) && ( activeSlide != " + counter + ")) { indexSetActiveSlide(" + counter + "); };"); + + // Set visibility for initial state. + if (counter == activeSlide) + { + node.style.display = "inherit"; + node.setAttribute("opacity",1); + } + else + { + node.style.display = "none"; + node.setAttribute("opacity",0); + } + } + + // Set key handler. + var jessyInkObjects = document.getElementsByTagNameNS(NSS["svg"], "g"); + + for (var counter = 0; counter < jessyInkObjects.length; counter++) + { + var elem = jessyInkObjects[counter]; + + if (elem.getAttributeNS(NSS["jessyink"], "customKeyBindings")) + { + if (elem.getCustomKeyBindings != undefined) + keyCodeDictionary = elem.getCustomKeyBindings(); + + if (elem.getCustomCharBindings != undefined) + charCodeDictionary = elem.getCustomCharBindings(); + } + } + + // Set mouse handler. + var jessyInkMouseHandler = document.getElementsByTagNameNS(NSS["jessyink"], "mousehandler"); + + for (var counter = 0; counter < jessyInkMouseHandler.length; counter++) + { + var elem = jessyInkMouseHandler[counter]; + + if (elem.getMouseHandler != undefined) + { + var tempDict = elem.getMouseHandler(); + + for (mode in tempDict) + { + if (!mouseHandlerDictionary[mode]) + mouseHandlerDictionary[mode] = new Object(); + + for (handler in tempDict[mode]) + mouseHandlerDictionary[mode][handler] = tempDict[mode][handler]; + } + } + } + + // Check effect number. + if ((activeEffect < 0) || (!slides[activeSlide].effects)) + { + activeEffect = 0; + } + else if (activeEffect > slides[activeSlide].effects.length) + { + activeEffect = slides[activeSlide].effects.length; + } + + createProgressBar(JessyInkPresentationLayer); + hideProgressBar(); + setProgressBarValue(activeSlide); + setTimeIndicatorValue(0); + setInterval("updateTimer()", 1000); + setSlideToState(activeSlide, activeEffect); + jessyInkInitialised = true; +} + +/** Function to subtitute the auto-texts. + * + * @param node the node + * @param slideName name of the slide the node is on + * @param slideNumber number of the slide the node is on + * @param numberOfSlides number of slides in the presentation + */ +function substituteAutoTexts(node, slideName, slideNumber, numberOfSlides) +{ + var texts = node.getElementsByTagNameNS(NSS["svg"], "tspan"); + + for (var textCounter = 0; textCounter < texts.length; textCounter++) + { + if (texts[textCounter].getAttributeNS(NSS["jessyink"], "autoText") == "slideNumber") + texts[textCounter].firstChild.nodeValue = slideNumber; + else if (texts[textCounter].getAttributeNS(NSS["jessyink"], "autoText") == "numberOfSlides") + texts[textCounter].firstChild.nodeValue = numberOfSlides; + else if (texts[textCounter].getAttributeNS(NSS["jessyink"], "autoText") == "slideTitle") + texts[textCounter].firstChild.nodeValue = slideName; + } +} + +/** Convenience function to get an element depending on whether it has a property with a particular name. + * This function emulates some dearly missed XPath functionality. + * + * @param node the node + * @param namespace namespace of the attribute + * @param name attribute name + */ +function getElementsByPropertyNS(node, namespace, name) +{ + var elems = new Array(); + + if (node.getAttributeNS(namespace, name)) + elems.push(node.getAttribute("id")); + + for (var counter = 0; counter < node.childNodes.length; counter++) + { + if (node.childNodes[counter].nodeType == 1) + elems = elems.concat(getElementsByPropertyNS(node.childNodes[counter], namespace, name)); + } + + return elems; +} + +/** Function to dispatch the next effect, if there is none left, change the slide. + * + * @param dir direction of the change (1 = forwards, -1 = backwards) + */ +function dispatchEffects(dir) +{ + if (slides[activeSlide]["effects"] && (((dir == 1) && (activeEffect < slides[activeSlide]["effects"].length)) || ((dir == -1) && (activeEffect > 0)))) + { + processingEffect = true; + + if (dir == 1) + { + effectArray = slides[activeSlide]["effects"][activeEffect]; + activeEffect += dir; + } + else if (dir == -1) + { + activeEffect += dir; + effectArray = slides[activeSlide]["effects"][activeEffect]; + } + + transCounter = 0; + startTime = (new Date()).getTime(); + lastFrameTime = null; + effect(dir); + } + else if (((dir == 1) && (activeSlide < (slides.length - 1))) || (((dir == -1) && (activeSlide > 0)))) + { + changeSlide(dir); + } +} + +/** Function to skip effects and directly either put the slide into start or end state or change slides. + * + * @param dir direction of the change (1 = forwards, -1 = backwards) + */ +function skipEffects(dir) +{ + if (slides[activeSlide]["effects"] && (((dir == 1) && (activeEffect < slides[activeSlide]["effects"].length)) || ((dir == -1) && (activeEffect > 0)))) + { + processingEffect = true; + + if (slides[activeSlide]["effects"] && (dir == 1)) + activeEffect = slides[activeSlide]["effects"].length; + else + activeEffect = 0; + + if (dir == 1) + setSlideToState(activeSlide, STATE_END); + else + setSlideToState(activeSlide, STATE_START); + + processingEffect = false; + } + else if (((dir == 1) && (activeSlide < (slides.length - 1))) || (((dir == -1) && (activeSlide > 0)))) + { + changeSlide(dir); + } +} + +/** Function to change between slides. + * + * @param dir direction (1 = forwards, -1 = backwards) + */ +function changeSlide(dir) +{ + processingEffect = true; + effectArray = new Array(); + + effectArray[0] = new Object(); + if (dir == 1) + { + effectArray[0]["effect"] = slides[activeSlide]["transitionOut"]["name"]; + effectArray[0]["options"] = slides[activeSlide]["transitionOut"]["options"]; + effectArray[0]["dir"] = -1; + } + else if (dir == -1) + { + effectArray[0]["effect"] = slides[activeSlide]["transitionIn"]["name"]; + effectArray[0]["options"] = slides[activeSlide]["transitionIn"]["options"]; + effectArray[0]["dir"] = 1; + } + effectArray[0]["element"] = slides[activeSlide]["element"]; + + activeSlide += dir; + setProgressBarValue(activeSlide); + + effectArray[1] = new Object(); + + if (dir == 1) + { + effectArray[1]["effect"] = slides[activeSlide]["transitionIn"]["name"]; + effectArray[1]["options"] = slides[activeSlide]["transitionIn"]["options"]; + effectArray[1]["dir"] = 1; + } + else if (dir == -1) + { + effectArray[1]["effect"] = slides[activeSlide]["transitionOut"]["name"]; + effectArray[1]["options"] = slides[activeSlide]["transitionOut"]["options"]; + effectArray[1]["dir"] = -1; + } + + effectArray[1]["element"] = slides[activeSlide]["element"]; + + if (slides[activeSlide]["effects"] && (dir == -1)) + activeEffect = slides[activeSlide]["effects"].length; + else + activeEffect = 0; + + if (dir == -1) + setSlideToState(activeSlide, STATE_END); + else + setSlideToState(activeSlide, STATE_START); + + transCounter = 0; + startTime = (new Date()).getTime(); + lastFrameTime = null; + effect(dir); +} + +/** Function to toggle between index and slide mode. +*/ +function toggleSlideIndex() +{ + var suspendHandle = ROOT_NODE.suspendRedraw(500); + + if (currentMode == SLIDE_MODE) + { + hideProgressBar(); + INDEX_OFFSET = -1; + indexSetPageSlide(activeSlide); + currentMode = INDEX_MODE; + } + else if (currentMode == INDEX_MODE) + { + for (var counter = 0; counter < slides.length; counter++) + { + slides[counter]["element"].setAttribute("transform","scale(1)"); + + if (counter == activeSlide) + { + slides[counter]["element"].style.display = "inherit"; + slides[counter]["element"].setAttribute("opacity",1); + activeEffect = 0; + } + else + { + slides[counter]["element"].setAttribute("opacity",0); + slides[counter]["element"].style.display = "none"; + } + } + currentMode = SLIDE_MODE; + setSlideToState(activeSlide, STATE_START); + setProgressBarValue(activeSlide); + + if (progress_bar_visible) + { + showProgressBar(); + } + } + + ROOT_NODE.unsuspendRedraw(suspendHandle); + ROOT_NODE.forceRedraw(); +} + +/** Function to run an effect. + * + * @param dir direction in which to play the effect (1 = forwards, -1 = backwards) + */ +function effect(dir) +{ + var done = true; + + var suspendHandle = ROOT_NODE.suspendRedraw(200); + + for (var counter = 0; counter < effectArray.length; counter++) + { + if (effectArray[counter]["effect"] == "fade") + done &= fade(parseInt(effectArray[counter]["dir"]) * dir, effectArray[counter]["element"], transCounter, effectArray[counter]["options"]); + else if (effectArray[counter]["effect"] == "appear") + done &= appear(parseInt(effectArray[counter]["dir"]) * dir, effectArray[counter]["element"], transCounter, effectArray[counter]["options"]); + else if (effectArray[counter]["effect"] == "pop") + done &= pop(parseInt(effectArray[counter]["dir"]) * dir, effectArray[counter]["element"], transCounter, effectArray[counter]["options"]); + else if (effectArray[counter]["effect"] == "view") + done &= view(parseInt(effectArray[counter]["dir"]) * dir, effectArray[counter]["element"], transCounter, effectArray[counter]["options"]); + } + + ROOT_NODE.unsuspendRedraw(suspendHandle); + ROOT_NODE.forceRedraw(); + + if (!done) + { + var currentTime = (new Date()).getTime(); + var timeDiff = 1; + + transCounter = currentTime - startTime; + + if (lastFrameTime != null) + { + timeDiff = timeStep - (currentTime - lastFrameTime); + + if (timeDiff <= 0) + timeDiff = 1; + } + + lastFrameTime = currentTime; + + window.setTimeout("effect(" + dir + ")", timeDiff); + } + else + { + window.location.hash = (activeSlide + 1) + '_' + activeEffect; + processingEffect = false; + } +} + +/** Function to display the index sheet. + * + * @param offsetNumber offset number + */ +function displayIndex(offsetNumber) +{ + var offsetX = 0; + var offsetY = 0; + + if (offsetNumber < 0) + offsetNumber = 0; + else if (offsetNumber >= slides.length) + offsetNumber = slides.length - 1; + + for (var counter = 0; counter < slides.length; counter++) + { + if ((counter < offsetNumber) || (counter > offsetNumber + INDEX_COLUMNS * INDEX_COLUMNS - 1)) + { + slides[counter]["element"].setAttribute("opacity",0); + slides[counter]["element"].style.display = "none"; + } + else + { + offsetX = ((counter - offsetNumber) % INDEX_COLUMNS) * WIDTH; + offsetY = Math.floor((counter - offsetNumber) / INDEX_COLUMNS) * HEIGHT; + + slides[counter]["element"].setAttribute("transform","scale("+1/INDEX_COLUMNS+") translate("+offsetX+","+offsetY+")"); + slides[counter]["element"].style.display = "inherit"; + slides[counter]["element"].setAttribute("opacity",0.5); + } + + setSlideToState(counter, STATE_END); + } + + //do we need to save the current offset? + if (INDEX_OFFSET != offsetNumber) + INDEX_OFFSET = offsetNumber; +} + +/** Function to set the active slide in the slide view. + * + * @param nbr index of the active slide + */ +function slideSetActiveSlide(nbr) +{ + if (nbr >= slides.length) + nbr = slides.length - 1; + else if (nbr < 0) + nbr = 0; + + slides[activeSlide]["element"].setAttribute("opacity",0); + slides[activeSlide]["element"].style.display = "none"; + + activeSlide = parseInt(nbr); + + setSlideToState(activeSlide, STATE_START); + slides[activeSlide]["element"].style.display = "inherit"; + slides[activeSlide]["element"].setAttribute("opacity",1); + + activeEffect = 0; + setProgressBarValue(nbr); +} + +/** Function to set the active slide in the index view. + * + * @param nbr index of the active slide + */ +function indexSetActiveSlide(nbr) +{ + if (nbr >= slides.length) + nbr = slides.length - 1; + else if (nbr < 0) + nbr = 0; + + slides[activeSlide]["element"].setAttribute("opacity",0.5); + + activeSlide = parseInt(nbr); + window.location.hash = (activeSlide + 1) + '_0'; + + slides[activeSlide]["element"].setAttribute("opacity",1); +} + +/** Function to set the page and active slide in index view. + * + * @param nbr index of the active slide + * + * NOTE: To force a redraw, + * set INDEX_OFFSET to -1 before calling indexSetPageSlide(). + * + * This is necessary for zooming (otherwise the index might not + * get redrawn) and when switching to index mode. + * + * INDEX_OFFSET = -1 + * indexSetPageSlide(activeSlide); + */ +function indexSetPageSlide(nbr) +{ + if (nbr >= slides.length) + nbr = slides.length - 1; + else if (nbr < 0) + nbr = 0; + + //calculate the offset + var offset = nbr - nbr % (INDEX_COLUMNS * INDEX_COLUMNS); + + if (offset < 0) + offset = 0; + + //if different from kept offset, then record and change the page + if (offset != INDEX_OFFSET) + { + INDEX_OFFSET = offset; + displayIndex(INDEX_OFFSET); + } + + //set the active slide + indexSetActiveSlide(nbr); +} + +/** Event handler for key press. + * + * @param e the event + */ +function keydown(e) +{ + if (!e) + e = window.event; + + code = e.keyCode || e.charCode; + + if (!processingEffect && keyCodeDictionary[currentMode] && keyCodeDictionary[currentMode][code]) + return keyCodeDictionary[currentMode][code](); + else + document.onkeypress = keypress; +} +// Set event handler for key down. +document.onkeydown = keydown; + +/** Event handler for key press. + * + * @param e the event + */ +function keypress(e) +{ + document.onkeypress = null; + + if (!e) + e = window.event; + + str = String.fromCharCode(e.keyCode || e.charCode); + + if (!processingEffect && charCodeDictionary[currentMode] && charCodeDictionary[currentMode][str]) + return charCodeDictionary[currentMode][str](); +} + +/** Function to supply the default char code dictionary. + * + * @returns default char code dictionary + */ +function getDefaultCharCodeDictionary() +{ + var charCodeDict = new Object(); + + charCodeDict[SLIDE_MODE] = new Object(); + charCodeDict[INDEX_MODE] = new Object(); + charCodeDict[DRAWING_MODE] = new Object(); + + charCodeDict[SLIDE_MODE]["i"] = function () { return toggleSlideIndex(); }; + charCodeDict[SLIDE_MODE]["d"] = function () { return slideSwitchToDrawingMode(); }; + charCodeDict[SLIDE_MODE]["D"] = function () { return slideQueryDuration(); }; + charCodeDict[SLIDE_MODE]["n"] = function () { return slideAddSlide(activeSlide); }; + charCodeDict[SLIDE_MODE]["p"] = function () { return slideToggleProgressBarVisibility(); }; + charCodeDict[SLIDE_MODE]["t"] = function () { return slideResetTimer(); }; + charCodeDict[SLIDE_MODE]["e"] = function () { return slideUpdateExportLayer(); }; + + charCodeDict[DRAWING_MODE]["d"] = function () { return drawingSwitchToSlideMode(); }; + charCodeDict[DRAWING_MODE]["0"] = function () { return drawingResetPathWidth(); }; + charCodeDict[DRAWING_MODE]["1"] = function () { return drawingSetPathWidth(1.0); }; + charCodeDict[DRAWING_MODE]["3"] = function () { return drawingSetPathWidth(3.0); }; + charCodeDict[DRAWING_MODE]["5"] = function () { return drawingSetPathWidth(5.0); }; + charCodeDict[DRAWING_MODE]["7"] = function () { return drawingSetPathWidth(7.0); }; + charCodeDict[DRAWING_MODE]["9"] = function () { return drawingSetPathWidth(9.0); }; + charCodeDict[DRAWING_MODE]["b"] = function () { return drawingSetPathColour("blue"); }; + charCodeDict[DRAWING_MODE]["c"] = function () { return drawingSetPathColour("cyan"); }; + charCodeDict[DRAWING_MODE]["g"] = function () { return drawingSetPathColour("green"); }; + charCodeDict[DRAWING_MODE]["k"] = function () { return drawingSetPathColour("black"); }; + charCodeDict[DRAWING_MODE]["m"] = function () { return drawingSetPathColour("magenta"); }; + charCodeDict[DRAWING_MODE]["o"] = function () { return drawingSetPathColour("orange"); }; + charCodeDict[DRAWING_MODE]["r"] = function () { return drawingSetPathColour("red"); }; + charCodeDict[DRAWING_MODE]["w"] = function () { return drawingSetPathColour("white"); }; + charCodeDict[DRAWING_MODE]["y"] = function () { return drawingSetPathColour("yellow"); }; + charCodeDict[DRAWING_MODE]["z"] = function () { return drawingUndo(); }; + + charCodeDict[INDEX_MODE]["i"] = function () { return toggleSlideIndex(); }; + charCodeDict[INDEX_MODE]["-"] = function () { return indexDecreaseNumberOfColumns(); }; + charCodeDict[INDEX_MODE]["="] = function () { return indexIncreaseNumberOfColumns(); }; + charCodeDict[INDEX_MODE]["+"] = function () { return indexIncreaseNumberOfColumns(); }; + charCodeDict[INDEX_MODE]["0"] = function () { return indexResetNumberOfColumns(); }; + + return charCodeDict; +} + +/** Function to supply the default key code dictionary. + * + * @returns default key code dictionary + */ +function getDefaultKeyCodeDictionary() +{ + var keyCodeDict = new Object(); + + keyCodeDict[SLIDE_MODE] = new Object(); + keyCodeDict[INDEX_MODE] = new Object(); + keyCodeDict[DRAWING_MODE] = new Object(); + + keyCodeDict[SLIDE_MODE][LEFT_KEY] = function() { return dispatchEffects(-1); }; + keyCodeDict[SLIDE_MODE][RIGHT_KEY] = function() { return dispatchEffects(1); }; + keyCodeDict[SLIDE_MODE][UP_KEY] = function() { return skipEffects(-1); }; + keyCodeDict[SLIDE_MODE][DOWN_KEY] = function() { return skipEffects(1); }; + keyCodeDict[SLIDE_MODE][PAGE_UP_KEY] = function() { return dispatchEffects(-1); }; + keyCodeDict[SLIDE_MODE][PAGE_DOWN_KEY] = function() { return dispatchEffects(1); }; + keyCodeDict[SLIDE_MODE][HOME_KEY] = function() { return slideSetActiveSlide(0); }; + keyCodeDict[SLIDE_MODE][END_KEY] = function() { return slideSetActiveSlide(slides.length - 1); }; + keyCodeDict[SLIDE_MODE][SPACE_KEY] = function() { return dispatchEffects(1); }; + + keyCodeDict[INDEX_MODE][LEFT_KEY] = function() { return indexSetPageSlide(activeSlide - 1); }; + keyCodeDict[INDEX_MODE][RIGHT_KEY] = function() { return indexSetPageSlide(activeSlide + 1); }; + keyCodeDict[INDEX_MODE][UP_KEY] = function() { return indexSetPageSlide(activeSlide - INDEX_COLUMNS); }; + keyCodeDict[INDEX_MODE][DOWN_KEY] = function() { return indexSetPageSlide(activeSlide + INDEX_COLUMNS); }; + keyCodeDict[INDEX_MODE][PAGE_UP_KEY] = function() { return indexSetPageSlide(activeSlide - INDEX_COLUMNS * INDEX_COLUMNS); }; + keyCodeDict[INDEX_MODE][PAGE_DOWN_KEY] = function() { return indexSetPageSlide(activeSlide + INDEX_COLUMNS * INDEX_COLUMNS); }; + keyCodeDict[INDEX_MODE][HOME_KEY] = function() { return indexSetPageSlide(0); }; + keyCodeDict[INDEX_MODE][END_KEY] = function() { return indexSetPageSlide(slides.length - 1); }; + keyCodeDict[INDEX_MODE][ENTER_KEY] = function() { return toggleSlideIndex(); }; + + keyCodeDict[DRAWING_MODE][ESCAPE_KEY] = function () { return drawingSwitchToSlideMode(); }; + + return keyCodeDict; +} + +/** Function to handle all mouse events. + * + * @param evnt event + * @param action type of event (e.g. mouse up, mouse wheel) + */ +function mouseHandlerDispatch(evnt, action) +{ + if (!evnt) + evnt = window.event; + + var retVal = true; + + if (!processingEffect && mouseHandlerDictionary[currentMode] && mouseHandlerDictionary[currentMode][action]) + { + var subRetVal = mouseHandlerDictionary[currentMode][action](evnt); + + if (subRetVal != null && subRetVal != undefined) + retVal = subRetVal; + } + + if (evnt.preventDefault && !retVal) + evnt.preventDefault(); + + evnt.returnValue = retVal; + + return retVal; +} + +// Set mouse event handler. +document.onmousedown = function(e) { return mouseHandlerDispatch(e, MOUSE_DOWN); }; +document.onmouseup = function(e) { return mouseHandlerDispatch(e, MOUSE_UP); }; +document.onmousemove = function(e) { return mouseHandlerDispatch(e, MOUSE_MOVE); }; + +// Moz +if (window.addEventListener) +{ + window.addEventListener('DOMMouseScroll', function(e) { return mouseHandlerDispatch(e, MOUSE_WHEEL); }, false); +} + +// Opera Safari OK - may not work in IE +window.onmousewheel = function(e) { return mouseHandlerDispatch(e, MOUSE_WHEEL); }; + +/** Function to supply the default mouse handler dictionary. + * + * @returns default mouse handler dictionary + */ +function getDefaultMouseHandlerDictionary() +{ + var mouseHandlerDict = new Object(); + + mouseHandlerDict[SLIDE_MODE] = new Object(); + mouseHandlerDict[INDEX_MODE] = new Object(); + mouseHandlerDict[DRAWING_MODE] = new Object(); + + mouseHandlerDict[SLIDE_MODE][MOUSE_DOWN] = function(evnt) { return dispatchEffects(1); }; + mouseHandlerDict[SLIDE_MODE][MOUSE_WHEEL] = function(evnt) { return slideMousewheel(evnt); }; + + mouseHandlerDict[INDEX_MODE][MOUSE_DOWN] = function(evnt) { return toggleSlideIndex(); }; + + mouseHandlerDict[DRAWING_MODE][MOUSE_DOWN] = function(evnt) { return drawingMousedown(evnt); }; + mouseHandlerDict[DRAWING_MODE][MOUSE_UP] = function(evnt) { return drawingMouseup(evnt); }; + mouseHandlerDict[DRAWING_MODE][MOUSE_MOVE] = function(evnt) { return drawingMousemove(evnt); }; + + return mouseHandlerDict; +} + +/** Function to switch from slide mode to drawing mode. +*/ +function slideSwitchToDrawingMode() +{ + currentMode = DRAWING_MODE; + + var tempDict; + + if (ROOT_NODE.hasAttribute("style")) + tempDict = propStrToDict(ROOT_NODE.getAttribute("style")); + else + tempDict = new Object(); + + tempDict["cursor"] = "crosshair"; + ROOT_NODE.setAttribute("style", dictToPropStr(tempDict)); +} + +/** Function to switch from drawing mode to slide mode. +*/ +function drawingSwitchToSlideMode() +{ + currentMode = SLIDE_MODE; + + var tempDict; + + if (ROOT_NODE.hasAttribute("style")) + tempDict = propStrToDict(ROOT_NODE.getAttribute("style")); + else + tempDict = new Object(); + + tempDict["cursor"] = "auto"; + ROOT_NODE.setAttribute("style", dictToPropStr(tempDict)); +} + +/** Function to decrease the number of columns in index mode. +*/ +function indexDecreaseNumberOfColumns() +{ + if (INDEX_COLUMNS >= 3) + { + INDEX_COLUMNS -= 1; + INDEX_OFFSET = -1 + indexSetPageSlide(activeSlide); + } +} + +/** Function to increase the number of columns in index mode. +*/ +function indexIncreaseNumberOfColumns() +{ + if (INDEX_COLUMNS < 7) + { + INDEX_COLUMNS += 1; + INDEX_OFFSET = -1 + indexSetPageSlide(activeSlide); + } +} + +/** Function to reset the number of columns in index mode. +*/ +function indexResetNumberOfColumns() +{ + if (INDEX_COLUMNS != INDEX_COLUMNS_DEFAULT) + { + INDEX_COLUMNS = INDEX_COLUMNS_DEFAULT; + INDEX_OFFSET = -1 + indexSetPageSlide(activeSlide); + } +} + +/** Function to reset path width in drawing mode. +*/ +function drawingResetPathWidth() +{ + path_width = path_width_default; + set_path_paint_width(); +} + +/** Function to set path width in drawing mode. + * + * @param width new path width + */ +function drawingSetPathWidth(width) +{ + path_width = width; + set_path_paint_width(); +} + +/** Function to set path colour in drawing mode. + * + * @param colour new path colour + */ +function drawingSetPathColour(colour) +{ + path_colour = colour; +} + +/** Function to query the duration of the presentation from the user in slide mode. +*/ +function slideQueryDuration() +{ + var new_duration = prompt("Length of presentation in minutes?", timer_duration); + + if ((new_duration != null) && (new_duration != '')) + { + timer_duration = new_duration; + } + + updateTimer(); +} + +/** Function to add new slide in slide mode. + * + * @param afterSlide after which slide to insert the new one + */ +function slideAddSlide(afterSlide) +{ + addSlide(afterSlide); + slideSetActiveSlide(afterSlide + 1); + updateTimer(); +} + +/** Function to toggle the visibility of the progress bar in slide mode. +*/ +function slideToggleProgressBarVisibility() +{ + if (progress_bar_visible) + { + progress_bar_visible = false; + hideProgressBar(); + } + else + { + progress_bar_visible = true; + showProgressBar(); + } +} + +/** Function to reset the timer in slide mode. +*/ +function slideResetTimer() +{ + timer_start = timer_elapsed; + updateTimer(); +} + +/** Convenience function to pad a string with zero in front up to a certain length. + */ +function padString(str, len) +{ + var outStr = str; + + while (outStr.length < len) + { + outStr = '0' + outStr; + } + + return outStr; +} + +/** Function to update the export layer. + */ +function slideUpdateExportLayer() +{ + // Suspend redraw since we are going to mess with the slides. + var suspendHandle = ROOT_NODE.suspendRedraw(2000); + + var tmpActiveSlide = activeSlide; + var tmpActiveEffect = activeEffect; + var exportedLayers = new Array(); + + for (var counterSlides = 0; counterSlides < slides.length; counterSlides++) + { + var exportNode; + + setSlideToState(counterSlides, STATE_START); + + var maxEffect = 0; + + if (slides[counterSlides].effects) + { + maxEffect = slides[counterSlides].effects.length; + } + + exportNode = slides[counterSlides].element.cloneNode(true); + exportNode.setAttributeNS(NSS["inkscape"], "groupmode", "layer"); + exportNode.setAttributeNS(NSS["inkscape"], "label", "slide_" + padString((counterSlides + 1).toString(), slides.length.toString().length) + "_effect_" + padString("0", maxEffect.toString().length)); + + exportedLayers.push(exportNode); + + if (slides[counterSlides]["effects"]) + { + for (var counter = 0; counter < slides[counterSlides]["effects"].length; counter++) + { + for (var subCounter = 0; subCounter < slides[counterSlides]["effects"][counter].length; subCounter++) + { + var effect = slides[counterSlides]["effects"][counter][subCounter]; + if (effect["effect"] == "fade") + fade(parseInt(effect["dir"]), effect["element"], STATE_END, effect["options"]); + else if (effect["effect"] == "appear") + appear(parseInt(effect["dir"]), effect["element"], STATE_END, effect["options"]); + else if (effect["effect"] == "pop") + pop(parseInt(effect["dir"]), effect["element"], STATE_END, effect["options"]); + else if (effect["effect"] == "view") + view(parseInt(effect["dir"]), effect["element"], STATE_END, effect["options"]); + } + + var layerName = "slide_" + padString((counterSlides + 1).toString(), slides.length.toString().length) + "_effect_" + padString((counter + 1).toString(), maxEffect.toString().length); + exportNode = slides[counterSlides].element.cloneNode(true); + exportNode.setAttributeNS(NSS["inkscape"], "groupmode", "layer"); + exportNode.setAttributeNS(NSS["inkscape"], "label", layerName); + exportNode.setAttribute("id", layerName); + + exportedLayers.push(exportNode); + } + } + } + + activeSlide = tmpActiveSlide; + activeEffect = tmpActiveEffect; + setSlideToState(activeSlide, activeEffect); + + // Copy image. + var newDoc = document.documentElement.cloneNode(true); + + // Delete viewbox form new imag and set width and height. + newDoc.removeAttribute('viewbox'); + newDoc.setAttribute('width', WIDTH); + newDoc.setAttribute('height', HEIGHT); + + // Delete all layers and script elements. + var nodesToBeRemoved = new Array(); + + for (var childCounter = 0; childCounter < newDoc.childNodes.length; childCounter++) + { + var child = newDoc.childNodes[childCounter]; + + if (child.nodeType == 1) + { + if ((child.nodeName.toUpperCase() == 'G') || (child.nodeName.toUpperCase() == 'SCRIPT')) + { + nodesToBeRemoved.push(child); + } + } + } + + for (var ndCounter = 0; ndCounter < nodesToBeRemoved.length; ndCounter++) + { + var nd = nodesToBeRemoved[ndCounter]; + + // Before removing the node, check whether it contains any definitions. + var defs = nd.getElementsByTagNameNS(NSS["svg"], "defs"); + + for (var defsCounter = 0; defsCounter < defs.length; defsCounter++) + { + if (defs[defsCounter].id) + { + newDoc.appendChild(defs[defsCounter].cloneNode(true)); + } + } + + // Remove node. + nd.parentNode.removeChild(nd); + } + + // Set current layer. + if (exportedLayers[0]) + { + var namedView; + + for (var nodeCounter = 0; nodeCounter < newDoc.childNodes.length; nodeCounter++) + { + if ((newDoc.childNodes[nodeCounter].nodeType == 1) && (newDoc.childNodes[nodeCounter].getAttribute('id') == 'base')) + { + namedView = newDoc.childNodes[nodeCounter]; + } + } + + if (namedView) + { + namedView.setAttributeNS(NSS['inkscape'], 'current-layer', exportedLayers[0].getAttributeNS(NSS['inkscape'], 'label')); + } + } + + // Add exported layers. + while (exportedLayers.length > 0) + { + var nd = exportedLayers.pop(); + + nd.setAttribute("opacity",1); + nd.style.display = "inherit"; + + newDoc.appendChild(nd); + } + + // Serialise the new document. + var serializer = new XMLSerializer(); + var strm = + { + content : "", + close : function() {}, + flush : function() {}, + write : function(str, count) { this.content += str; } + }; + + var xml = serializer.serializeToStream(newDoc, strm, 'UTF-8'); + + window.location = 'data:application/svg+xml;base64;charset=utf-8,' + window.btoa(strm.content); + + // Unsuspend redraw. + ROOT_NODE.unsuspendRedraw(suspendHandle); + ROOT_NODE.forceRedraw(); +} + +/** Function to undo last drawing operation. +*/ +function drawingUndo() +{ + mouse_presentation_path = null; + mouse_original_path = null; + + if (history_presentation_elements.length > 0) + { + var p = history_presentation_elements.pop(); + var parent = p.parentNode.removeChild(p); + + p = history_original_elements.pop(); + parent = p.parentNode.removeChild(p); + } +} + +/** Event handler for mouse down in drawing mode. + * + * @param e the event + */ +function drawingMousedown(e) +{ + var value = 0; + + if (e.button) + value = e.button; + else if (e.which) + value = e.which; + + if (value == 1) + { + history_counter++; + + var p = calcCoord(e); + + mouse_last_x = e.clientX; + mouse_last_y = e.clientY; + mouse_original_path = document.createElementNS(NSS["svg"], "path"); + mouse_original_path.setAttribute("stroke", path_colour); + mouse_original_path.setAttribute("stroke-width", path_paint_width); + mouse_original_path.setAttribute("fill", "none"); + mouse_original_path.setAttribute("id", "path " + Date()); + mouse_original_path.setAttribute("d", "M" + p.x + "," + p.y); + slides[activeSlide]["original_element"].appendChild(mouse_original_path); + history_original_elements.push(mouse_original_path); + + mouse_presentation_path = document.createElementNS(NSS["svg"], "path"); + mouse_presentation_path.setAttribute("stroke", path_colour); + mouse_presentation_path.setAttribute("stroke-width", path_paint_width); + mouse_presentation_path.setAttribute("fill", "none"); + mouse_presentation_path.setAttribute("id", "path " + Date() + " presentation copy"); + mouse_presentation_path.setAttribute("d", "M" + p.x + "," + p.y); + + if (slides[activeSlide]["viewGroup"]) + slides[activeSlide]["viewGroup"].appendChild(mouse_presentation_path); + else + slides[activeSlide]["element"].appendChild(mouse_presentation_path); + + history_presentation_elements.push(mouse_presentation_path); + + return false; + } + + return true; +} + +/** Event handler for mouse up in drawing mode. + * + * @param e the event + */ +function drawingMouseup(e) +{ + if(!e) + e = window.event; + + if (mouse_presentation_path != null) + { + var p = calcCoord(e); + var d = mouse_presentation_path.getAttribute("d"); + d += " L" + p.x + "," + p.y; + mouse_presentation_path.setAttribute("d", d); + mouse_presentation_path = null; + mouse_original_path.setAttribute("d", d); + mouse_original_path = null; + + return false; + } + + return true; +} + +/** Event handler for mouse move in drawing mode. + * + * @param e the event + */ +function drawingMousemove(e) +{ + if(!e) + e = window.event; + + var dist = (mouse_last_x - e.clientX) * (mouse_last_x - e.clientX) + (mouse_last_y - e.clientY) * (mouse_last_y - e.clientY); + + if (mouse_presentation_path == null) + { + return true; + } + + if (dist >= mouse_min_dist_sqr) + { + var p = calcCoord(e); + var d = mouse_presentation_path.getAttribute("d"); + d += " L" + p.x + "," + p.y; + mouse_presentation_path.setAttribute("d", d); + mouse_original_path.setAttribute("d", d); + mouse_last_x = e.clientX; + mouse_last_y = e.clientY; + } + + return false; +} + +/** Event handler for mouse wheel events in slide mode. + * based on http://adomas.org/javascript-mouse-wheel/ + * + * @param e the event + */ +function slideMousewheel(e) +{ + var delta = 0; + + if (!e) + e = window.event; + + if (e.wheelDelta) + { // IE Opera + delta = e.wheelDelta/120; + } + else if (e.detail) + { // MOZ + delta = -e.detail/3; + } + + if (delta > 0) + skipEffects(-1); + else if (delta < 0) + skipEffects(1); + + if (e.preventDefault) + e.preventDefault(); + + e.returnValue = false; +} + +/** Event handler for mouse wheel events in index mode. + * based on http://adomas.org/javascript-mouse-wheel/ + * + * @param e the event + */ +function indexMousewheel(e) +{ + var delta = 0; + + if (!e) + e = window.event; + + if (e.wheelDelta) + { // IE Opera + delta = e.wheelDelta/120; + } + else if (e.detail) + { // MOZ + delta = -e.detail/3; + } + + if (delta > 0) + indexSetPageSlide(activeSlide - INDEX_COLUMNS * INDEX_COLUMNS); + else if (delta < 0) + indexSetPageSlide(activeSlide + INDEX_COLUMNS * INDEX_COLUMNS); + + if (e.preventDefault) + e.preventDefault(); + + e.returnValue = false; +} + +/** Function to set the path paint width. +*/ +function set_path_paint_width() +{ + var svgPoint1 = document.documentElement.createSVGPoint(); + var svgPoint2 = document.documentElement.createSVGPoint(); + + svgPoint1.x = 0.0; + svgPoint1.y = 0.0; + svgPoint2.x = 1.0; + svgPoint2.y = 0.0; + + var matrix = slides[activeSlide]["element"].getTransformToElement(ROOT_NODE); + + if (slides[activeSlide]["viewGroup"]) + matrix = slides[activeSlide]["viewGroup"].getTransformToElement(ROOT_NODE); + + svgPoint1 = svgPoint1.matrixTransform(matrix); + svgPoint2 = svgPoint2.matrixTransform(matrix); + + path_paint_width = path_width / Math.sqrt((svgPoint2.x - svgPoint1.x) * (svgPoint2.x - svgPoint1.x) + (svgPoint2.y - svgPoint1.y) * (svgPoint2.y - svgPoint1.y)); +} + +/** The view effect. + * + * @param dir direction the effect should be played (1 = forwards, -1 = backwards) + * @param element the element the effect should be applied to + * @param time the time that has elapsed since the beginning of the effect + * @param options a dictionary with additional options (e.g. length of the effect); for the view effect the options need to contain the old and the new matrix. + */ +function view(dir, element, time, options) +{ + var length = 250; + var fraction; + + if (!options["matrixInitial"]) + { + var tempString = slides[activeSlide]["viewGroup"].getAttribute("transform"); + + if (tempString) + options["matrixInitial"] = (new matrixSVG()).fromAttribute(tempString); + else + options["matrixInitial"] = (new matrixSVG()).fromSVGElements(1, 0, 0, 1, 0, 0); + } + + if ((time == STATE_END) || (time == STATE_START)) + fraction = 1; + else + { + if (options && options["length"]) + length = options["length"]; + + fraction = time / length; + } + + if (dir == 1) + { + if (fraction <= 0) + { + element.setAttribute("transform", options["matrixInitial"].toAttribute()); + } + else if (fraction >= 1) + { + element.setAttribute("transform", options["matrixNew"].toAttribute()); + + set_path_paint_width(); + + options["matrixInitial"] = null; + return true; + } + else + { + element.setAttribute("transform", options["matrixInitial"].mix(options["matrixNew"], fraction).toAttribute()); + } + } + else if (dir == -1) + { + if (fraction <= 0) + { + element.setAttribute("transform", options["matrixInitial"].toAttribute()); + } + else if (fraction >= 1) + { + element.setAttribute("transform", options["matrixOld"].toAttribute()); + set_path_paint_width(); + + options["matrixInitial"] = null; + return true; + } + else + { + element.setAttribute("transform", options["matrixInitial"].mix(options["matrixOld"], fraction).toAttribute()); + } + } + + return false; +} + +/** The fade effect. + * + * @param dir direction the effect should be played (1 = forwards, -1 = backwards) + * @param element the element the effect should be applied to + * @param time the time that has elapsed since the beginning of the effect + * @param options a dictionary with additional options (e.g. length of the effect) + */ +function fade(dir, element, time, options) +{ + var length = 250; + var fraction; + + if ((time == STATE_END) || (time == STATE_START)) + fraction = 1; + else + { + if (options && options["length"]) + length = options["length"]; + + fraction = time / length; + } + + if (dir == 1) + { + if (fraction <= 0) + { + element.style.display = "none"; + element.setAttribute("opacity", 0); + } + else if (fraction >= 1) + { + element.style.display = "inherit"; + element.setAttribute("opacity", 1); + return true; + } + else + { + element.style.display = "inherit"; + element.setAttribute("opacity", fraction); + } + } + else if (dir == -1) + { + if (fraction <= 0) + { + element.style.display = "inherit"; + element.setAttribute("opacity", 1); + } + else if (fraction >= 1) + { + element.setAttribute("opacity", 0); + element.style.display = "none"; + return true; + } + else + { + element.style.display = "inherit"; + element.setAttribute("opacity", 1 - fraction); + } + } + return false; +} + +/** The appear effect. + * + * @param dir direction the effect should be played (1 = forwards, -1 = backwards) + * @param element the element the effect should be applied to + * @param time the time that has elapsed since the beginning of the effect + * @param options a dictionary with additional options (e.g. length of the effect) + */ +function appear(dir, element, time, options) +{ + if (dir == 1) + { + element.style.display = "inherit"; + element.setAttribute("opacity",1); + } + else if (dir == -1) + { + element.style.display = "none"; + element.setAttribute("opacity",0); + } + return true; +} + +/** The pop effect. + * + * @param dir direction the effect should be played (1 = forwards, -1 = backwards) + * @param element the element the effect should be applied to + * @param time the time that has elapsed since the beginning of the effect + * @param options a dictionary with additional options (e.g. length of the effect) + */ +function pop(dir, element, time, options) +{ + var length = 500; + var fraction; + + if ((time == STATE_END) || (time == STATE_START)) + fraction = 1; + else + { + if (options && options["length"]) + length = options["length"]; + + fraction = time / length; + } + + if (dir == 1) + { + if (fraction <= 0) + { + element.setAttribute("opacity", 0); + element.setAttribute("transform", "scale(0)"); + element.style.display = "none"; + } + else if (fraction >= 1) + { + element.setAttribute("opacity", 1); + element.removeAttribute("transform"); + element.style.display = "inherit"; + return true; + } + else + { + element.style.display = "inherit"; + var opacityFraction = fraction * 3; + if (opacityFraction > 1) + opacityFraction = 1; + element.setAttribute("opacity", opacityFraction); + var offsetX = WIDTH * (1.0 - fraction) / 2.0; + var offsetY = HEIGHT * (1.0 - fraction) / 2.0; + element.setAttribute("transform", "translate(" + offsetX + "," + offsetY + ") scale(" + fraction + ")"); + } + } + else if (dir == -1) + { + if (fraction <= 0) + { + element.setAttribute("opacity", 1); + element.setAttribute("transform", "scale(1)"); + element.style.display = "inherit"; + } + else if (fraction >= 1) + { + element.setAttribute("opacity", 0); + element.removeAttribute("transform"); + element.style.display = "none"; + return true; + } + else + { + element.setAttribute("opacity", 1 - fraction); + element.setAttribute("transform", "scale(" + 1 - fraction + ")"); + element.style.display = "inherit"; + } + } + return false; +} + +/** Function to set a slide either to the start or the end state. + * + * @param slide the slide to use + * @param state the state into which the slide should be set + */ +function setSlideToState(slide, state) +{ + slides[slide]["viewGroup"].setAttribute("transform", slides[slide].initialView); + + if (slides[slide]["effects"]) + { + if (state == STATE_END) + { + for (var counter = 0; counter < slides[slide]["effects"].length; counter++) + { + for (var subCounter = 0; subCounter < slides[slide]["effects"][counter].length; subCounter++) + { + var effect = slides[slide]["effects"][counter][subCounter]; + if (effect["effect"] == "fade") + fade(effect["dir"], effect["element"], STATE_END, effect["options"]); + else if (effect["effect"] == "appear") + appear(effect["dir"], effect["element"], STATE_END, effect["options"]); + else if (effect["effect"] == "pop") + pop(effect["dir"], effect["element"], STATE_END, effect["options"]); + else if (effect["effect"] == "view") + view(effect["dir"], effect["element"], STATE_END, effect["options"]); + } + } + } + else if (state == STATE_START) + { + for (var counter = slides[slide]["effects"].length - 1; counter >= 0; counter--) + { + for (var subCounter = 0; subCounter < slides[slide]["effects"][counter].length; subCounter++) + { + var effect = slides[slide]["effects"][counter][subCounter]; + if (effect["effect"] == "fade") + fade(parseInt(effect["dir"]) * -1, effect["element"], STATE_START, effect["options"]); + else if (effect["effect"] == "appear") + appear(parseInt(effect["dir"]) * -1, effect["element"], STATE_START, effect["options"]); + else if (effect["effect"] == "pop") + pop(parseInt(effect["dir"]) * -1, effect["element"], STATE_START, effect["options"]); + else if (effect["effect"] == "view") + view(parseInt(effect["dir"]) * -1, effect["element"], STATE_START, effect["options"]); + } + } + } + else + { + setSlideToState(slide, STATE_START); + + for (var counter = 0; counter < slides[slide]["effects"].length && counter < state; counter++) + { + for (var subCounter = 0; subCounter < slides[slide]["effects"][counter].length; subCounter++) + { + var effect = slides[slide]["effects"][counter][subCounter]; + if (effect["effect"] == "fade") + fade(effect["dir"], effect["element"], STATE_END, effect["options"]); + else if (effect["effect"] == "appear") + appear(effect["dir"], effect["element"], STATE_END, effect["options"]); + else if (effect["effect"] == "pop") + pop(effect["dir"], effect["element"], STATE_END, effect["options"]); + else if (effect["effect"] == "view") + view(effect["dir"], effect["element"], STATE_END, effect["options"]); + } + } + } + } + + window.location.hash = (activeSlide + 1) + '_' + activeEffect; +} + +/** Convenience function to translate a attribute string into a dictionary. + * + * @param str the attribute string + * @return a dictionary + * @see dictToPropStr + */ +function propStrToDict(str) +{ + var list = str.split(";"); + var obj = new Object(); + + for (var counter = 0; counter < list.length; counter++) + { + var subStr = list[counter]; + var subList = subStr.split(":"); + if (subList.length == 2) + { + obj[subList[0]] = subList[1]; + } + } + + return obj; +} + +/** Convenience function to translate a dictionary into a string that can be used as an attribute. + * + * @param dict the dictionary to convert + * @return a string that can be used as an attribute + * @see propStrToDict + */ +function dictToPropStr(dict) +{ + var str = ""; + + for (var key in dict) + { + str += key + ":" + dict[key] + ";"; + } + + return str; +} + +/** Sub-function to add a suffix to the ids of the node and all its children. + * + * @param node the node to change + * @param suffix the suffix to add + * @param replace dictionary of replaced ids + * @see suffixNodeIds + */ +function suffixNoneIds_sub(node, suffix, replace) +{ + if (node.nodeType == 1) + { + if (node.getAttribute("id")) + { + var id = node.getAttribute("id") + replace["#" + id] = id + suffix; + node.setAttribute("id", id + suffix); + } + + if ((node.nodeName == "use") && (node.getAttributeNS(NSS["xlink"], "href")) && (replace[node.getAttribute(NSS["xlink"], "href")])) + node.setAttribute(NSS["xlink"], "href", node.getAttribute(NSS["xlink"], "href") + suffix); + + if (node.childNodes) + { + for (var counter = 0; counter < node.childNodes.length; counter++) + suffixNoneIds_sub(node.childNodes[counter], suffix, replace); + } + } +} + +/** Function to add a suffix to the ids of the node and all its children. + * + * @param node the node to change + * @param suffix the suffix to add + * @return the changed node + * @see suffixNodeIds_sub + */ +function suffixNodeIds(node, suffix) +{ + var replace = new Object(); + + suffixNoneIds_sub(node, suffix, replace); + + return node; +} + +/** Function to build a progress bar. + * + * @param parent node to attach the progress bar to + */ +function createProgressBar(parent_node) +{ + var g = document.createElementNS(NSS["svg"], "g"); + g.setAttribute("clip-path", "url(#jessyInkSlideClipPath)"); + g.setAttribute("id", "layer_progress_bar"); + g.setAttribute("style", "display: none;"); + + var rect_progress_bar = document.createElementNS(NSS["svg"], "rect"); + rect_progress_bar.setAttribute("style", "marker: none; fill: rgb(128, 128, 128); stroke: none;"); + rect_progress_bar.setAttribute("id", "rect_progress_bar"); + rect_progress_bar.setAttribute("x", 0); + rect_progress_bar.setAttribute("y", 0.99 * HEIGHT); + rect_progress_bar.setAttribute("width", 0); + rect_progress_bar.setAttribute("height", 0.01 * HEIGHT); + g.appendChild(rect_progress_bar); + + var circle_timer_indicator = document.createElementNS(NSS["svg"], "circle"); + circle_timer_indicator.setAttribute("style", "marker: none; fill: rgb(255, 0, 0); stroke: none;"); + circle_timer_indicator.setAttribute("id", "circle_timer_indicator"); + circle_timer_indicator.setAttribute("cx", 0.005 * HEIGHT); + circle_timer_indicator.setAttribute("cy", 0.995 * HEIGHT); + circle_timer_indicator.setAttribute("r", 0.005 * HEIGHT); + g.appendChild(circle_timer_indicator); + + parent_node.appendChild(g); +} + +/** Function to hide the progress bar. + * + */ +function hideProgressBar() +{ + var progress_bar = document.getElementById("layer_progress_bar"); + + if (!progress_bar) + { + return; + } + + progress_bar.setAttribute("style", "display: none;"); +} + +/** Function to show the progress bar. + * + */ +function showProgressBar() +{ + var progress_bar = document.getElementById("layer_progress_bar"); + + if (!progress_bar) + { + return; + } + + progress_bar.setAttribute("style", "display: inherit;"); +} + +/** Set progress bar value. + * + * @param value the current slide number + * + */ +function setProgressBarValue(value) +{ + var rect_progress_bar = document.getElementById("rect_progress_bar"); + + if (!rect_progress_bar) + { + return; + } + + if (value < 1) + { + // First slide, assumed to be the title of the presentation + var x = 0; + var w = 0.01 * HEIGHT; + } + else if (value >= slides.length - 1) + { + // Last slide, assumed to be the end of the presentation + var x = WIDTH - 0.01 * HEIGHT; + var w = 0.01 * HEIGHT; + } + else + { + value -= 1; + value /= (slides.length - 2); + + var x = WIDTH * value; + var w = WIDTH / (slides.length - 2); + } + + rect_progress_bar.setAttribute("x", x); + rect_progress_bar.setAttribute("width", w); +} + +/** Set time indicator. + * + * @param value the percentage of time elapse so far between 0.0 and 1.0 + * + */ +function setTimeIndicatorValue(value) +{ + var circle_timer_indicator = document.getElementById("circle_timer_indicator"); + + if (!circle_timer_indicator) + { + return; + } + + if (value < 0.0) + { + value = 0.0; + } + + if (value > 1.0) + { + value = 1.0; + } + + var cx = (WIDTH - 0.01 * HEIGHT) * value + 0.005 * HEIGHT; + circle_timer_indicator.setAttribute("cx", cx); +} + +/** Update timer. + * + */ +function updateTimer() +{ + timer_elapsed += 1; + setTimeIndicatorValue((timer_elapsed - timer_start) / (60 * timer_duration)); +} + +/** Convert screen coordinates to document coordinates. + * + * @param e event with screen coordinates + * + * @return coordinates in SVG file coordinate system + */ +function calcCoord(e) +{ + var svgPoint = document.documentElement.createSVGPoint(); + svgPoint.x = e.clientX + window.pageXOffset; + svgPoint.y = e.clientY + window.pageYOffset; + + var matrix = slides[activeSlide]["element"].getScreenCTM(); + + if (slides[activeSlide]["viewGroup"]) + matrix = slides[activeSlide]["viewGroup"].getScreenCTM(); + + svgPoint = svgPoint.matrixTransform(matrix.inverse()); + return svgPoint; +} + +/** Add slide. + * + * @param after_slide after which slide the new slide should be inserted into the presentation + */ +function addSlide(after_slide) +{ + number_of_added_slides++; + + var g = document.createElementNS(NSS["svg"], "g"); + g.setAttribute("clip-path", "url(#jessyInkSlideClipPath)"); + g.setAttribute("id", "Whiteboard " + Date() + " presentation copy"); + g.setAttribute("style", "display: none;"); + + var new_slide = new Object(); + new_slide["element"] = g; + + // Set build in transition. + new_slide["transitionIn"] = new Object(); + var dict = defaultTransitionInDict; + new_slide["transitionIn"]["name"] = dict["name"]; + new_slide["transitionIn"]["options"] = new Object(); + + for (key in dict) + if (key != "name") + new_slide["transitionIn"]["options"][key] = dict[key]; + + // Set build out transition. + new_slide["transitionOut"] = new Object(); + dict = defaultTransitionOutDict; + new_slide["transitionOut"]["name"] = dict["name"]; + new_slide["transitionOut"]["options"] = new Object(); + + for (key in dict) + if (key != "name") + new_slide["transitionOut"]["options"][key] = dict[key]; + + // Copy master slide content. + if (masterSlide) + { + var clonedNode = suffixNodeIds(masterSlide.cloneNode(true), "_" + Date() + " presentation_copy"); + clonedNode.removeAttributeNS(NSS["inkscape"], "groupmode"); + clonedNode.removeAttributeNS(NSS["inkscape"], "label"); + clonedNode.style.display = "inherit"; + + g.appendChild(clonedNode); + } + + // Substitute auto texts. + substituteAutoTexts(g, "Whiteboard " + number_of_added_slides, "W" + number_of_added_slides, slides.length); + + g.setAttribute("onmouseover", "if ((currentMode == INDEX_MODE) && ( activeSlide != " + (after_slide + 1) + ")) { indexSetActiveSlide(" + (after_slide + 1) + "); };"); + + // Create a transform group. + var transformGroup = document.createElementNS(NSS["svg"], "g"); + + // Add content to transform group. + while (g.firstChild) + transformGroup.appendChild(g.firstChild); + + // Transfer the transform attribute from the node to the transform group. + if (g.getAttribute("transform")) + { + transformGroup.setAttribute("transform", g.getAttribute("transform")); + g.removeAttribute("transform"); + } + + // Create a view group. + var viewGroup = document.createElementNS(NSS["svg"], "g"); + + viewGroup.appendChild(transformGroup); + new_slide["viewGroup"] = g.appendChild(viewGroup); + + // Insert background. + if (BACKGROUND_COLOR != null) + { + var rectNode = document.createElementNS(NSS["svg"], "rect"); + + rectNode.setAttribute("x", 0); + rectNode.setAttribute("y", 0); + rectNode.setAttribute("width", WIDTH); + rectNode.setAttribute("height", HEIGHT); + rectNode.setAttribute("id", "jessyInkBackground" + Date()); + rectNode.setAttribute("fill", BACKGROUND_COLOR); + + new_slide["viewGroup"].insertBefore(rectNode, new_slide["viewGroup"].firstChild); + } + + // Set initial view even if there are no other views. + var matrixOld = (new matrixSVG()).fromElements(1, 0, 0, 0, 1, 0, 0, 0, 1); + + new_slide["viewGroup"].setAttribute("transform", matrixOld.toAttribute()); + new_slide.initialView = matrixOld.toAttribute(); + + // Insert slide + var node = slides[after_slide]["element"]; + var next_node = node.nextSibling; + var parent_node = node.parentNode; + + if (next_node) + { + parent_node.insertBefore(g, next_node); + } + else + { + parent_node.appendChild(g); + } + + g = document.createElementNS(NSS["svg"], "g"); + g.setAttributeNS(NSS["inkscape"], "groupmode", "layer"); + g.setAttributeNS(NSS["inkscape"], "label", "Whiteboard " + number_of_added_slides); + g.setAttribute("clip-path", "url(#jessyInkSlideClipPath)"); + g.setAttribute("id", "Whiteboard " + Date()); + g.setAttribute("style", "display: none;"); + + new_slide["original_element"] = g; + + node = slides[after_slide]["original_element"]; + next_node = node.nextSibling; + parent_node = node.parentNode; + + if (next_node) + { + parent_node.insertBefore(g, next_node); + } + else + { + parent_node.appendChild(g); + } + + before_new_slide = slides.slice(0, after_slide + 1); + after_new_slide = slides.slice(after_slide + 1); + slides = before_new_slide.concat(new_slide, after_new_slide); + + //resetting the counter attributes on the slides that follow the new slide... + for (var counter = after_slide+2; counter < slides.length; counter++) + { + slides[counter]["element"].setAttribute("onmouseover", "if ((currentMode == INDEX_MODE) && ( activeSlide != " + counter + ")) { indexSetActiveSlide(" + counter + "); };"); + } +} + +/** Convenience function to obtain a transformation matrix from a point matrix. + * + * @param mPoints Point matrix. + * @return A transformation matrix. + */ +function pointMatrixToTransformation(mPoints) +{ + mPointsOld = (new matrixSVG()).fromElements(0, WIDTH, WIDTH, 0, 0, HEIGHT, 1, 1, 1); + + return mPointsOld.mult(mPoints.inv()); +} + +/** Convenience function to obtain a matrix with three corners of a rectangle. + * + * @param rect an svg rectangle + * @return a matrixSVG containing three corners of the rectangle + */ +function rectToMatrix(rect) +{ + rectWidth = rect.getBBox().width; + rectHeight = rect.getBBox().height; + rectX = rect.getBBox().x; + rectY = rect.getBBox().y; + rectXcorr = 0; + rectYcorr = 0; + + scaleX = WIDTH / rectWidth; + scaleY = HEIGHT / rectHeight; + + if (scaleX > scaleY) + { + scaleX = scaleY; + rectXcorr -= (WIDTH / scaleX - rectWidth) / 2; + rectWidth = WIDTH / scaleX; + } + else + { + scaleY = scaleX; + rectYcorr -= (HEIGHT / scaleY - rectHeight) / 2; + rectHeight = HEIGHT / scaleY; + } + + if (rect.transform.baseVal.numberOfItems < 1) + { + mRectTrans = (new matrixSVG()).fromElements(1, 0, 0, 0, 1, 0, 0, 0, 1); + } + else + { + mRectTrans = (new matrixSVG()).fromSVGMatrix(rect.transform.baseVal.consolidate().matrix); + } + + newBasePoints = (new matrixSVG()).fromElements(rectX, rectX, rectX, rectY, rectY, rectY, 1, 1, 1); + newVectors = (new matrixSVG()).fromElements(rectXcorr, rectXcorr + rectWidth, rectXcorr + rectWidth, rectYcorr, rectYcorr, rectYcorr + rectHeight, 0, 0, 0); + + return mRectTrans.mult(newBasePoints.add(newVectors)); +} + +/** Function to handle JessyInk elements. + * + * @param node Element node. + */ +function handleElement(node) +{ + if (node.getAttributeNS(NSS['jessyink'], 'element') == 'core.video') + { + var url; + var width; + var height; + var x; + var y; + var transform; + + var tspans = node.getElementsByTagNameNS("http://www.w3.org/2000/svg", "tspan"); + + for (var tspanCounter = 0; tspanCounter < tspans.length; tspanCounter++) + { + if (tspans[tspanCounter].getAttributeNS("https://launchpad.net/jessyink", "video") == "url") + { + url = tspans[tspanCounter].firstChild.nodeValue; + } + } + + var rects = node.getElementsByTagNameNS("http://www.w3.org/2000/svg", "rect"); + + for (var rectCounter = 0; rectCounter < rects.length; rectCounter++) + { + if (rects[rectCounter].getAttributeNS("https://launchpad.net/jessyink", "video") == "rect") + { + x = rects[rectCounter].getAttribute("x"); + y = rects[rectCounter].getAttribute("y"); + width = rects[rectCounter].getAttribute("width"); + height = rects[rectCounter].getAttribute("height"); + transform = rects[rectCounter].getAttribute("transform"); + } + } + + for (var childCounter = 0; childCounter < node.childNodes.length; childCounter++) + { + if (node.childNodes[childCounter].nodeType == 1) + { + if (node.childNodes[childCounter].style) + { + node.childNodes[childCounter].style.display = 'none'; + } + else + { + node.childNodes[childCounter].setAttribute("style", "display: none;"); + } + } + } + + var foreignNode = document.createElementNS("http://www.w3.org/2000/svg", "foreignObject"); + foreignNode.setAttribute("x", x); + foreignNode.setAttribute("y", y); + foreignNode.setAttribute("width", width); + foreignNode.setAttribute("height", height); + foreignNode.setAttribute("transform", transform); + + var videoNode = document.createElementNS("http://www.w3.org/1999/xhtml", "video"); + videoNode.setAttribute("src", url); + + foreignNode.appendChild(videoNode); + node.appendChild(foreignNode); + } +} + +/** Class processing the location hash. + * + * @param str location hash + */ +function LocationHash(str) +{ + this.slideNumber = 0; + this.effectNumber = 0; + + str = str.substr(1, str.length - 1); + + var parts = str.split('_'); + + // Try to extract slide number. + if (parts.length >= 1) + { + try + { + var slideNumber = parseInt(parts[0]); + + if (!isNaN(slideNumber)) + { + this.slideNumber = slideNumber - 1; + } + } + catch (e) + { + } + } + + // Try to extract effect number. + if (parts.length >= 2) + { + try + { + var effectNumber = parseInt(parts[1]); + + if (!isNaN(effectNumber)) + { + this.effectNumber = effectNumber; + } + } + catch (e) + { + } + } +} + +/** Class representing an svg matrix. +*/ +function matrixSVG() +{ + this.e11 = 0; // a + this.e12 = 0; // c + this.e13 = 0; // e + this.e21 = 0; // b + this.e22 = 0; // d + this.e23 = 0; // f + this.e31 = 0; + this.e32 = 0; + this.e33 = 0; +} + +/** Constructor function. + * + * @param a element a (i.e. 1, 1) as described in the svg standard. + * @param b element b (i.e. 2, 1) as described in the svg standard. + * @param c element c (i.e. 1, 2) as described in the svg standard. + * @param d element d (i.e. 2, 2) as described in the svg standard. + * @param e element e (i.e. 1, 3) as described in the svg standard. + * @param f element f (i.e. 2, 3) as described in the svg standard. + */ +matrixSVG.prototype.fromSVGElements = function(a, b, c, d, e, f) +{ + this.e11 = a; + this.e12 = c; + this.e13 = e; + this.e21 = b; + this.e22 = d; + this.e23 = f; + this.e31 = 0; + this.e32 = 0; + this.e33 = 1; + + return this; +} + +/** Constructor function. + * + * @param matrix an svg matrix as described in the svg standard. + */ +matrixSVG.prototype.fromSVGMatrix = function(m) +{ + this.e11 = m.a; + this.e12 = m.c; + this.e13 = m.e; + this.e21 = m.b; + this.e22 = m.d; + this.e23 = m.f; + this.e31 = 0; + this.e32 = 0; + this.e33 = 1; + + return this; +} + +/** Constructor function. + * + * @param e11 element 1, 1 of the matrix. + * @param e12 element 1, 2 of the matrix. + * @param e13 element 1, 3 of the matrix. + * @param e21 element 2, 1 of the matrix. + * @param e22 element 2, 2 of the matrix. + * @param e23 element 2, 3 of the matrix. + * @param e31 element 3, 1 of the matrix. + * @param e32 element 3, 2 of the matrix. + * @param e33 element 3, 3 of the matrix. + */ +matrixSVG.prototype.fromElements = function(e11, e12, e13, e21, e22, e23, e31, e32, e33) +{ + this.e11 = e11; + this.e12 = e12; + this.e13 = e13; + this.e21 = e21; + this.e22 = e22; + this.e23 = e23; + this.e31 = e31; + this.e32 = e32; + this.e33 = e33; + + return this; +} + +/** Constructor function. + * + * @param attrString string value of the "transform" attribute (currently only "matrix" is accepted) + */ +matrixSVG.prototype.fromAttribute = function(attrString) +{ + str = attrString.substr(7, attrString.length - 8); + + str = str.trim(); + + strArray = str.split(","); + + // Opera does not use commas to separate the values of the matrix, only spaces. + if (strArray.length != 6) + strArray = str.split(" "); + + this.e11 = parseFloat(strArray[0]); + this.e21 = parseFloat(strArray[1]); + this.e31 = 0; + this.e12 = parseFloat(strArray[2]); + this.e22 = parseFloat(strArray[3]); + this.e32 = 0; + this.e13 = parseFloat(strArray[4]); + this.e23 = parseFloat(strArray[5]); + this.e33 = 1; + + return this; +} + +/** Output function + * + * @return a string that can be used as the "transform" attribute. + */ +matrixSVG.prototype.toAttribute = function() +{ + return "matrix(" + this.e11 + ", " + this.e21 + ", " + this.e12 + ", " + this.e22 + ", " + this.e13 + ", " + this.e23 + ")"; +} + +/** Matrix nversion. + * + * @return the inverse of the matrix + */ +matrixSVG.prototype.inv = function() +{ + out = new matrixSVG(); + + det = this.e11 * (this.e33 * this.e22 - this.e32 * this.e23) - this.e21 * (this.e33 * this.e12 - this.e32 * this.e13) + this.e31 * (this.e23 * this.e12 - this.e22 * this.e13); + + out.e11 = (this.e33 * this.e22 - this.e32 * this.e23) / det; + out.e12 = -(this.e33 * this.e12 - this.e32 * this.e13) / det; + out.e13 = (this.e23 * this.e12 - this.e22 * this.e13) / det; + out.e21 = -(this.e33 * this.e21 - this.e31 * this.e23) / det; + out.e22 = (this.e33 * this.e11 - this.e31 * this.e13) / det; + out.e23 = -(this.e23 * this.e11 - this.e21 * this.e13) / det; + out.e31 = (this.e32 * this.e21 - this.e31 * this.e22) / det; + out.e32 = -(this.e32 * this.e11 - this.e31 * this.e12) / det; + out.e33 = (this.e22 * this.e11 - this.e21 * this.e12) / det; + + return out; +} + +/** Matrix multiplication. + * + * @param op another svg matrix + * @return this * op + */ +matrixSVG.prototype.mult = function(op) +{ + out = new matrixSVG(); + + out.e11 = this.e11 * op.e11 + this.e12 * op.e21 + this.e13 * op.e31; + out.e12 = this.e11 * op.e12 + this.e12 * op.e22 + this.e13 * op.e32; + out.e13 = this.e11 * op.e13 + this.e12 * op.e23 + this.e13 * op.e33; + out.e21 = this.e21 * op.e11 + this.e22 * op.e21 + this.e23 * op.e31; + out.e22 = this.e21 * op.e12 + this.e22 * op.e22 + this.e23 * op.e32; + out.e23 = this.e21 * op.e13 + this.e22 * op.e23 + this.e23 * op.e33; + out.e31 = this.e31 * op.e11 + this.e32 * op.e21 + this.e33 * op.e31; + out.e32 = this.e31 * op.e12 + this.e32 * op.e22 + this.e33 * op.e32; + out.e33 = this.e31 * op.e13 + this.e32 * op.e23 + this.e33 * op.e33; + + return out; +} + +/** Matrix addition. + * + * @param op another svg matrix + * @return this + op + */ +matrixSVG.prototype.add = function(op) +{ + out = new matrixSVG(); + + out.e11 = this.e11 + op.e11; + out.e12 = this.e12 + op.e12; + out.e13 = this.e13 + op.e13; + out.e21 = this.e21 + op.e21; + out.e22 = this.e22 + op.e22; + out.e23 = this.e23 + op.e23; + out.e31 = this.e31 + op.e31; + out.e32 = this.e32 + op.e32; + out.e33 = this.e33 + op.e33; + + return out; +} + +/** Matrix mixing. + * + * @param op another svg matrix + * @parma contribOp contribution of the other matrix (0 <= contribOp <= 1) + * @return (1 - contribOp) * this + contribOp * op + */ +matrixSVG.prototype.mix = function(op, contribOp) +{ + contribThis = 1.0 - contribOp; + out = new matrixSVG(); + + out.e11 = contribThis * this.e11 + contribOp * op.e11; + out.e12 = contribThis * this.e12 + contribOp * op.e12; + out.e13 = contribThis * this.e13 + contribOp * op.e13; + out.e21 = contribThis * this.e21 + contribOp * op.e21; + out.e22 = contribThis * this.e22 + contribOp * op.e22; + out.e23 = contribThis * this.e23 + contribOp * op.e23; + out.e31 = contribThis * this.e31 + contribOp * op.e31; + out.e32 = contribThis * this.e32 + contribOp * op.e32; + out.e33 = contribThis * this.e33 + contribOp * op.e33; + + return out; +} + +/** Trimming function for strings. +*/ +String.prototype.trim = function() +{ + return this.replace(/^\s+|\s+$/g, ''); +} + +</script> + <ns1:mousehandler + ns1:subtype="jessyInk_core_mouseHandler_noclick"> + <script + id="script4951">// Copyright 2008, 2009 Hannes Hochreiner +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see http://www.gnu.org/licenses/. + +// Add event listener for initialisation. +document.addEventListener("DOMContentLoaded", jessyInk_core_mouseHandler_noclick_init, false); + +/** Initialisation function. + * + * This function looks for the objects of the appropriate sub-type and hands them to another function that will add the required methods. + */ +function jessyInk_core_mouseHandler_noclick_init() +{ + var elems = document.getElementsByTagNameNS("https://launchpad.net/jessyink", "mousehandler"); + + for (var counter = 0; counter < elems.length; counter++) + { + if (elems[counter].getAttributeNS("https://launchpad.net/jessyink", "subtype") == "jessyInk_core_mouseHandler_noclick") + jessyInk_core_mouseHandler_noclick(elems[counter]); + } +} + +/** Function to initialise an object. + * + * @param obj Object to be initialised. + */ +function jessyInk_core_mouseHandler_noclick(obj) +{ + /** Function supplying a custom mouse handler. + * + * @returns A dictionary containing the new mouse handler functions. + */ + obj.getMouseHandler = function () + { + var handlerDictio = new Object(); + + handlerDictio[SLIDE_MODE] = new Object(); + handlerDictio[SLIDE_MODE][MOUSE_DOWN] = null; + + return handlerDictio; + } +} + +</script> + </ns1:mousehandler> +</svg> diff --git a/Doc/Sda1/xmlintro.xml b/Doc/Sda1/xmlintro.xml index 483244dff..0251b3e80 100644 --- a/Doc/Sda1/xmlintro.xml +++ b/Doc/Sda1/xmlintro.xml @@ -35,7 +35,7 @@ <mediaobject> <imageobject> - <imagedata fileref="Ref/Fig/xhtml.fig"/> + <imagedata fileref="Ref/Fig/xhtml.svg"/> </imageobject> </mediaobject> </figure> diff --git a/ws/Docbook/Extensions/Tdata/Components/intro.xml b/ws/Docbook/Extensions/Tdata/Components/intro.xml index 058b67e5e..61005eafe 100644 --- a/ws/Docbook/Extensions/Tdata/Components/intro.xml +++ b/ws/Docbook/Extensions/Tdata/Components/intro.xml @@ -100,7 +100,7 @@ <db:programlisting language="none">SELECT * FROM Table</db:programlisting> - <db:para>A <db:filename>.fig</db:filename> figure:</db:para> + <db:para>A <db:filename>Fig</db:filename> figure:</db:para> <db:figure xml:id="xslAxisDefinitions"> <db:title>XSL axis directions</db:title> @@ -113,6 +113,20 @@ </db:mediaobject> </db:figure> + <db:para>A <db:filename>Svg</db:filename> figure containing a + screenshot:</db:para> + + <db:figure xml:id="xhtmlRendering"> + <db:title>XSL axis directions</db:title> + + <db:mediaobject> + <db:imageobject> + <db:imagedata fileref="../../../../../Doc/Sda1/Ref/Fig/xhtml.svg" + scale="60"/> + </db:imageobject> + </db:mediaobject> + </db:figure> + <db:para>A <db:filename>.fig</db:filename> containing TeX based math:</db:para> diff --git a/ws/Docbook/Extensions/Tdata/fig.xml b/ws/Docbook/Extensions/Tdata/fig.xml index f0dbedc60..ba37c42db 100644 --- a/ws/Docbook/Extensions/Tdata/fig.xml +++ b/ws/Docbook/Extensions/Tdata/fig.xml @@ -89,42 +89,6 @@ <para>This is the end my friend.</para> </chapter> - <chapter xml:id="mixLectureSlides"> - <title>Mixing lecture notes and slides</title> - - <section xml:id="classintro"> - <title>Objects and classes</title> - - <annotation role="slide"> - <para>Ignore me, just here to supply a valid annotation content - model.</para> - </annotation> - - <para>To be continued accordingly ...</para> - - <section xml:id="objectsClassesBasics"> - <title>Classes in OO languages</title> - - <itemizedlist> - <listitem> - <para>Blueprints for objects</para> - </listitem> - - <listitem> - <para>Attributes and methods.</para> - </listitem> - </itemizedlist> - </section> - - <section xml:id="classVsInstance"> - <title>Classes and instances</title> - - <mediaobject> - <imageobject> - <imagedata fileref="Ref/Fig/class.svg"/> - </imageobject> - </mediaobject> - </section> - </section> - </chapter> + <xi:include href="Components/exampleSlides.xml" xpointer="element(/1)"/> + </book> -- GitLab