|
1 |
/**
|
|
2 |
* Copyright (C) 2011 KO GmbH - Tobias Hintze
|
|
3 |
* @licstart
|
|
4 |
* The JavaScript code in this page is free software: you can redistribute it
|
|
5 |
* and/or modify it under the terms of the GNU Affero General Public License
|
|
6 |
* (GNU AGPL) as published by the Free Software Foundation, either version 3 of
|
|
7 |
* the License, or (at your option) any later version. The code is distributed
|
|
8 |
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
9 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU AGPL for more details.
|
|
10 |
*
|
|
11 |
* As additional permission under GNU AGPL version 3 section 7, you
|
|
12 |
* may distribute non-source (e.g., minimized or compacted) forms of
|
|
13 |
* that code without the copy of the GNU GPL normally required by
|
|
14 |
* section 4, provided you include this license notice and a URL
|
|
15 |
* through which recipients can access the Corresponding Source.
|
|
16 |
*
|
|
17 |
* As a special exception to the AGPL, any HTML file which merely makes function
|
|
18 |
* calls to this code, and for that purpose includes it by reference shall be
|
|
19 |
* deemed a separate work for copyright law purposes. In addition, the copyright
|
|
20 |
* holders of this code give you permission to combine this code with free
|
|
21 |
* software libraries that are released under the GNU LGPL. You may copy and
|
|
22 |
* distribute such a system following the terms of the GNU AGPL for this code
|
|
23 |
* and the LGPL for the libraries. If you modify this code, you may extend this
|
|
24 |
* exception to your version of the code, but you are not obligated to do so.
|
|
25 |
* If you do not wish to do so, delete this exception statement from your
|
|
26 |
* version.
|
|
27 |
*
|
|
28 |
* This license applies to this entire compilation.
|
|
29 |
* @licend
|
|
30 |
* @source: http://www.webodf.org/
|
|
31 |
* @source: http://gitorious.org/odfkit/webodf/
|
|
32 |
*/
|
|
33 |
|
|
34 |
|
|
35 |
/*global runtime: true, gui: true, odf: true, XPathResult: true, core: true, document: true, window: true*/
|
|
36 |
|
|
37 |
gui.PresenterUI = (function () {
|
|
38 |
"use strict";
|
|
39 |
var s2css = new odf.Style2CSS(),
|
|
40 |
nsResolver = s2css.namespaceResolver;
|
|
41 |
|
|
42 |
return function PresenterUI(odf_element) {
|
|
43 |
var self = this;
|
|
44 |
|
|
45 |
self.setInitialSlideMode = function () {
|
|
46 |
self.startSlideMode('single');
|
|
47 |
};
|
|
48 |
|
|
49 |
self.keyDownHandler = function (ev) {
|
|
50 |
if (ev.target.isContentEditable) { return; }
|
|
51 |
if (ev.target.nodeName === 'input') { return; }
|
|
52 |
switch (ev.keyCode) {
|
|
53 |
case 84: // t - hide/show toolbar
|
|
54 |
self.toggleToolbar();
|
|
55 |
break;
|
|
56 |
case 37: // left
|
|
57 |
case 8: // left
|
|
58 |
self.prevSlide();
|
|
59 |
break;
|
|
60 |
case 39: // right
|
|
61 |
case 32: // space
|
|
62 |
self.nextSlide();
|
|
63 |
break;
|
|
64 |
case 36: // pos1
|
|
65 |
self.firstSlide();
|
|
66 |
break;
|
|
67 |
case 35: // end
|
|
68 |
self.lastSlide();
|
|
69 |
break;
|
|
70 |
}
|
|
71 |
};
|
|
72 |
|
|
73 |
self.root = function () { return self.odf_canvas.odfContainer().rootElement; };
|
|
74 |
|
|
75 |
self.firstSlide = function () { self.slideChange(function(old,pc) { return 0; }); };
|
|
76 |
self.lastSlide = function () { self.slideChange(function(old,pc) { return pc-1; }); };
|
|
77 |
|
|
78 |
self.nextSlide = function () {
|
|
79 |
self.slideChange(function(old,pc) { return old+1 < pc ? old+1 : -1; });
|
|
80 |
};
|
|
81 |
self.prevSlide = function () {
|
|
82 |
self.slideChange(function(old,pc) { return old<1 ? -1 : old-1; });
|
|
83 |
};
|
|
84 |
// indexChanger gets (idx,pagecount) as parameter and returns the new index
|
|
85 |
self.slideChange = function (indexChanger) {
|
|
86 |
var pages = self.getPages(self.odf_canvas.odfContainer().rootElement),
|
|
87 |
last = -1,
|
|
88 |
i = 0,
|
|
89 |
newidx, pagelist;
|
|
90 |
pages.forEach(function(tuple) {
|
|
91 |
var name = tuple[0],
|
|
92 |
node = tuple[1];
|
|
93 |
if (node.hasAttribute('slide_current')) {
|
|
94 |
last = i;
|
|
95 |
node.removeAttribute('slide_current');
|
|
96 |
}
|
|
97 |
i += 1;
|
|
98 |
});
|
|
99 |
newidx = indexChanger(last, pages.length);
|
|
100 |
if (newidx === -1) { newidx = last; }
|
|
101 |
pages[newidx][1].setAttribute('slide_current', '1');
|
|
102 |
pagelist = document.getElementById('pagelist');
|
|
103 |
pagelist.selectedIndex = newidx;
|
|
104 |
// FIXME this needs to become a sane callback/listener mechanism
|
|
105 |
// (and the mode probably a class/instance..)
|
|
106 |
if (self.slide_mode === 'cont') {
|
|
107 |
window.scrollBy(0,pages[newidx][1].getBoundingClientRect().top - 30);
|
|
108 |
}
|
|
109 |
};
|
|
110 |
|
|
111 |
self.selectSlide = function (idx) {
|
|
112 |
self.slideChange(function(old,pc) {
|
|
113 |
if (idx >= pc) { return -1; }
|
|
114 |
if (idx < 0) { return -1; }
|
|
115 |
return idx;
|
|
116 |
});
|
|
117 |
};
|
|
118 |
|
|
119 |
// make one specific slide visible in cont-mode
|
|
120 |
self.scrollIntoContView = function (idx) {
|
|
121 |
var pages = self.getPages(self.odf_canvas.odfContainer().rootElement);
|
|
122 |
if ( pages.length === 0 ) { return; }
|
|
123 |
/*
|
|
124 |
if (false) {
|
|
125 |
// works in chrome
|
|
126 |
pages[idx][1].scrollIntoView();
|
|
127 |
} else {
|
|
128 |
*/
|
|
129 |
// works in ff
|
|
130 |
window.scrollBy(0,pages[idx][1].getBoundingClientRect().top - 30);
|
|
131 |
/*}*/
|
|
132 |
};
|
|
133 |
|
|
134 |
// return a list of tuples (pagename, pagenode)
|
|
135 |
self.getPages = function (root) {
|
|
136 |
var pagenodes = root.getElementsByTagNameNS(nsResolver('draw'), 'page'),
|
|
137 |
pages = [],
|
|
138 |
i;
|
|
139 |
for (i=0 ; i < pagenodes.length ; i += 1) {
|
|
140 |
pages.push(
|
|
141 |
[
|
|
142 |
pagenodes[i].getAttribute('draw:name'),
|
|
143 |
pagenodes[i]
|
|
144 |
]);
|
|
145 |
}
|
|
146 |
return pages;
|
|
147 |
};
|
|
148 |
|
|
149 |
// fill a html-select with options, one option per page in odf (odp)
|
|
150 |
self.fillPageList = function (odfdom_root, html_select) {
|
|
151 |
var pages = self.getPages(odfdom_root),
|
|
152 |
i,
|
|
153 |
html_option,
|
|
154 |
res,
|
|
155 |
page_denom;
|
|
156 |
|
|
157 |
// empty the pagelist
|
|
158 |
while ( html_select.firstChild ) { html_select.removeChild(html_select.firstChild); }
|
|
159 |
|
|
160 |
// populate it
|
|
161 |
for (i=0 ; i< pages.length ; i += 1) {
|
|
162 |
html_option = document.createElement('option');
|
|
163 |
res = document.evaluate( './draw:frame[@presentation:class="title"]//draw:text-box/text:p',
|
|
164 |
pages[i][1], nsResolver, XPathResult.FIRST_ORDERED_NODE_TYPE , null);
|
|
165 |
page_denom = res.singleNodeValue ? res.singleNodeValue.textContent : pages[i][0];
|
|
166 |
html_option.textContent = (i+1)+": "+page_denom;
|
|
167 |
html_select.appendChild(html_option);
|
|
168 |
}
|
|
169 |
};
|
|
170 |
|
|
171 |
self.startSlideMode = function (mode) {
|
|
172 |
var pagelist = document.getElementById('pagelist'),
|
|
173 |
css = self.odf_canvas.slidevisibilitycss().sheet;
|
|
174 |
self.slide_mode=mode;
|
|
175 |
while (css.cssRules.length > 0) { css.deleteRule(0); }
|
|
176 |
// start on slide 0
|
|
177 |
self.selectSlide(0);
|
|
178 |
if (self.slide_mode === 'single') {
|
|
179 |
css.insertRule( "draw|page { position:fixed; left:0px;top:30px; z-index:1; }", 0);
|
|
180 |
css.insertRule( "draw|page[slide_current] { z-index:2;}", 1);
|
|
181 |
css.insertRule( "draw|page { -webkit-transform: scale(1);}", 2);
|
|
182 |
self.fitToWindow();
|
|
183 |
window.addEventListener('resize', self.fitToWindow, false);
|
|
184 |
|
|
185 |
} else if (self.slide_mode === 'cont') {
|
|
186 |
window.removeEventListener('resize', self.fitToWindow, false);
|
|
187 |
}
|
|
188 |
|
|
189 |
self.fillPageList(self.odf_canvas.odfContainer().rootElement, pagelist);
|
|
190 |
};
|
|
191 |
|
|
192 |
// toggle (show/hide) toolbar
|
|
193 |
self.toggleToolbar = function () {
|
|
194 |
var css, found, i;
|
|
195 |
css = self.odf_canvas.slidevisibilitycss().sheet;
|
|
196 |
found = -1;
|
|
197 |
for (i=0 ; i< css.cssRules.length ; i += 1) {
|
|
198 |
if (css.cssRules[i].cssText.substring(0,8) === ".toolbar") {
|
|
199 |
found = i;
|
|
200 |
break;
|
|
201 |
}
|
|
202 |
}
|
|
203 |
if (found > -1) {
|
|
204 |
css.deleteRule(found);
|
|
205 |
} else {
|
|
206 |
css.insertRule( ".toolbar { position:fixed; left:0px;top:-200px; z-index:0; }", 0);
|
|
207 |
}
|
|
208 |
};
|
|
209 |
|
|
210 |
// adapt css-transform to window-size
|
|
211 |
self.fitToWindow = function () {
|
|
212 |
function ruleByFactor(f) {
|
|
213 |
return "draw|page { \n" +
|
|
214 |
"-moz-transform: scale("+f+"); \n" +
|
|
215 |
"-moz-transform-origin: 0% 0%; "+
|
|
216 |
"-webkit-transform-origin: 0% 0%; -webkit-transform: scale("+f+"); " +
|
|
217 |
"-o-transform-origin: 0% 0%; -o-transform: scale("+f+"); " +
|
|
218 |
"-ms-transform-origin: 0% 0%; -ms-transform: scale("+f+"); " +
|
|
219 |
"}";
|
|
220 |
}
|
|
221 |
var pages = self.getPages(self.root()),
|
|
222 |
factorVert = ((window.innerHeight-40) / pages[0][1].clientHeight),
|
|
223 |
factorHoriz = ((window.innerWidth-10) / pages[0][1].clientWidth),
|
|
224 |
factor = factorVert < factorHoriz ? factorVert : factorHoriz,
|
|
225 |
css = self.odf_canvas.slidevisibilitycss().sheet;
|
|
226 |
css.deleteRule(2);
|
|
227 |
css.insertRule( ruleByFactor(factor), 2);
|
|
228 |
};
|
|
229 |
|
|
230 |
self.load = function (url) {
|
|
231 |
self.odf_canvas.load(url);
|
|
232 |
};
|
|
233 |
|
|
234 |
self.odf_element = odf_element;
|
|
235 |
self.odf_canvas = new odf.OdfCanvas(self.odf_element);
|
|
236 |
self.odf_canvas.addListener("statereadychange", self.setInitialSlideMode);
|
|
237 |
self.slide_mode = 'undefined';
|
|
238 |
document.addEventListener('keydown', self.keyDownHandler, false);
|
|
239 |
};
|
|
240 |
}());
|
|
241 |
|