Add simple android client.
[odfkit:webodf.git] / android / assets / odf.js
1 /*global runtime XMLHttpRequest document core XPathResult XMLSerializer DOMParser odf*/
2 runtime.loadClass("odf.OdfContainer");
3 runtime.loadClass("odf.Style2CSS");
4
5 var xhtmlns = "http://www.w3.org/1999/xhtml";
6
7 /**
8  * A new styles.xml has been loaded. Update the live document with it.
9  **/
10 function handleStyles(odfelement) {
11     // update the css translation of the styles    
12     var stylesxmlcss = document.getElementById('stylesxmlcss'),
13             style2css = new odf.Style2CSS();
14     stylesxmlcss = /**@type{HTMLStyleElement}*/(stylesxmlcss);
15     try {
16         style2css.style2css(stylesxmlcss.sheet, odfelement.styles,
17                 odfelement.automaticStyles);
18     } catch (e) {
19         throw e;
20     }
21 }
22 var officens  = "urn:oasis:names:tc:opendocument:xmlns:office:1.0";
23 var drawns    = "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0";
24 var fons      = "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0";
25 var svgns     = "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0";
26 var textns    = "urn:oasis:names:tc:opendocument:xmlns:text:1.0";
27 var xlinkns   = "http://www.w3.org/1999/xlink";
28 var presentation = false;
29 var activeSlide = 1;
30 var slidecssindex = 0;
31 function setFramePosition(id, frame, stylesheet) {
32     frame.setAttribute('styleid', id);
33     var rule,
34         anchor = frame.getAttributeNS(textns, 'anchor-type'),
35         x = frame.getAttributeNS(svgns, 'x'),
36         y = frame.getAttributeNS(svgns, 'y'),
37         width = frame.getAttributeNS(svgns, 'width'),
38         height = frame.getAttributeNS(svgns, 'height'),
39         minheight = frame.getAttributeNS(fons, 'min-height'),
40         minwidth = frame.getAttributeNS(fons, 'min-width'); 
41     if (anchor === "as-char") {
42         rule = 'display: inline-block;';
43     } else if (anchor || x || y) {
44         rule = 'position: absolute;';
45     } else if (width || height || minheight || minwidth) {
46         rule = 'display: block;';
47     }
48     if (x) {
49         rule += 'left: ' + x + ';';
50     }
51     if (y) {
52         rule += 'top: ' + y + ';';
53     }
54     if (width) {
55         rule += 'width: ' + width + ';';
56     }
57     if (height) {
58         rule += 'height: ' + height + ';';
59     }
60     if (minheight) {
61         rule += 'min-height: ' + minheight + ';';
62     }
63     if (minwidth) {
64         rule += 'min-width: ' + minwidth + ';';
65     }
66     if (rule) {
67         rule = 'draw|' + frame.localName + '[styleid="' + id + '"] {' + rule +
68             '}';
69         stylesheet.insertRule(rule, stylesheet.cssRules.length);
70     }
71 }
72 function setImage(id, container, image, stylesheet) {
73     image.setAttribute('styleid', id);
74     var url = image.getAttributeNS(xlinkns, 'href'),
75         part;
76     function callback(url) {
77         var rule = "background-image: url(" + url + ");";
78         rule = 'draw|image[styleid="' + id + '"] {' + rule + '}';
79         stylesheet.insertRule(rule, stylesheet.cssRules.length);
80     }
81     try {
82         if (container.getPartUrl) {
83             url = container.getPartUrl(url);
84             callback(url);
85         } else {
86             part = container.getPart(url);
87             part.onchange = function (part) {
88                 callback(part.url);
89             };
90             part.load();
91         }
92     } catch (e) {
93         alert('slight problem');
94     }
95 }
96 function modifyImages(container, odfbody, stylesheet) {
97     var namespaces = {
98             draw: drawns,
99             fo: fons,
100             svg: svgns
101         },
102         doc = odfbody.ownerDocument,
103         drawiter,
104         node,
105         frames,
106         i,
107         images;
108     function namespaceResolver(prefix) {
109         return namespaces[prefix];
110     }
111     frames = [];
112     node = odfbody.firstChild;
113     while (node && node !== odfbody) {
114         if (node.namespaceURI === drawns) {
115             frames[frames.length] = node;
116   //  alert(frames.length + " " + node.localName);
117         }
118         if (node.firstChild) {
119             node = node.firstChild;
120         } else {
121             while (node !== odfbody && !node.nextSibling) {
122                 node = node.parentNode;
123             }
124             if (node.nextSibling) {
125                 node = node.nextSibling;
126             }
127         }
128     }
129 /*
130     drawiter = doc.evaluate("*"+"//draw:*" +
131             "[@svg:x|@svg:y|@svg:width|@svg:height|@fo:min-height|@fo:min-width]",
132             odfbody, namespaceResolver, 0, null);
133     node = drawiter.iterateNext();
134     while (node) {
135         frames[frames.length] = node;
136         node = drawiter.iterateNext();
137     }
138 */
139     for (i = 0; i < frames.length; i += 1) {
140         node = frames[i];
141         setFramePosition('frame' + i, node, stylesheet);
142     }
143     images = odfbody.getElementsByTagNameNS(drawns, 'image');
144     for (i = 0; i < images.length; i += 1) {
145         setImage('image' + i, container, images.item(i), stylesheet);
146     }
147 }
148 function clear(element) {
149     while (element.firstChild) {
150         element.removeChild(element.firstChild);
151     }
152 }
153 /**
154  * A new content.xml has been loaded. Update the live document with it.
155  **/
156 function handleContent(container, odfnode) {
157
158     var positioncss = /**@type{HTMLStyleElement}*/(document.getElementById('positioncss')),
159         css = positioncss.sheet;
160     modifyImages(container, odfnode.body, css);
161     slidecssindex = css.insertRule(
162             'office|presentation draw|page:nth-child(n) { display:block; }',
163             css.cssRules.length);    
164
165     // only append the content at the end
166     clear(document.body);
167     document.body.appendChild(odfnode);
168 }
169 function refreshOdf() {
170     var OdfContainer = odf.OdfContainer,
171         container,
172         odfnode;
173     if (runtime.getWindow().odfcontainer.state !== OdfContainer.DONE) {
174         return;
175     }
176
177     // synchronize the object a window.odfcontainer with the view
178     container = runtime.getWindow().odfcontainer;
179
180     clear(document.body);
181
182     odfnode = container.rootElement;
183     document.importNode(odfnode, true);
184     handleStyles(odfnode);
185     // do content last, because otherwise the document is constantly updated
186     // whenever the css changes
187     handleContent(container, odfnode);
188 }
189
190 function init() {
191     // if the url has a fragment (#...), try to load the file it represents
192     var location = String(document.location),
193         pos = location.indexOf('#'),
194         window = runtime.getWindow();
195     if (pos === -1 || !window) {
196         return;
197     }
198     location = location.substr(pos + 1);
199     // open the odf container
200     window.odfcontainer = odf.OdfContainer.getContainer(location);
201     window.odfcontainer.onstatereadychange = refreshOdf;
202 }
203
204 function getDirectChild(ns, name, node) {
205     node = (node) ? node.firstChild : null;
206     while (node) {
207         if (node.localName === name && node.namespaceURI === ns) {
208             return node;
209         }
210         node = node.nextSibling;
211     }
212 }
213
214 /** temporary function to make a presentation when 'f' is pressed **/
215 (function () {
216     // this code is only useful for applications with a window
217     if (!runtime.getWindow()) {
218         return;
219     }
220
221     var maxSlideRule = "{display: block;border: 0px;}";
222     function setSlideStyle(slide, style) {
223         var positioncss = /**@type{HTMLStyleElement}*/(document.getElementById('positioncss')),
224             css = positioncss.sheet,
225             r = css.cssRules,
226             div;
227         css.deleteRule(slidecssindex);
228         slidecssindex = css.insertRule('office|presentation draw|page:nth-child(' +
229             slide + ')' + style, css.cssRules.length);
230         div = document.getElementById('contentxml');
231         if (slide !== 'n') {
232             div.className = 'fullscreen';
233         } else {
234             div.className = null;
235         }
236     }
237     function nextSlide() {
238         activeSlide += 1;
239         if (activeSlide < 1) {
240             activeSlide = 1;
241         }
242         setSlideStyle(activeSlide, maxSlideRule);
243     }
244     function makePresentation() {
245         presentation = true;
246         activeSlide -= 1;
247         nextSlide();
248         var ppi = 98, // larger than 96 to avoid scaling problems
249             pagewidth = 11.02, // inches of hardcoded value
250             pageheight = 8.27, // inches of hardcoded value
251             window = runtime.getWindow(),
252             zoomlevelw = window.innerWidth / ppi / pagewidth,
253             zoomlevelh = window.innerHeight / ppi / pageheight,
254             zoomlevel = (zoomlevelw > zoomlevelh) ? zoomlevelh : zoomlevelw;
255         document.body.style.zoom = zoomlevel;
256         document.body.style.MozTransform = 'scale(' + zoomlevel + ')';
257     }
258     function unmakePresentation() {
259         presentation = false;
260         setSlideStyle('n', "{display: block;}");
261         var zoomlevel = 1.0;
262         document.body.style.zoom = zoomlevel;
263         document.body.style.MozTransform = 'scale(' + zoomlevel + ')';
264     }
265     function previousSlide() {
266         activeSlide -= 2;
267         nextSlide();
268     }
269     runtime.getWindow().onkeyup = function (e) {
270         if (e.keyCode === 70) { // f
271             if (presentation) {
272                 unmakePresentation();
273             } else {
274                 makePresentation();
275             }
276             return;
277         }
278         if (!presentation) {
279             return;
280         }
281         if (e.keyCode === 8) { // backspace
282             previousSlide();
283         } else {
284             nextSlide();
285         }
286     };
287     function fixOdf() {
288         var x = new XMLSerializer(), parser, dom;
289         x = x.serializeToString(document.body.firstChild);
290         parser = new DOMParser();
291         dom = parser.parseFromString(x, "text/xml");
292         dom = document.importNode(dom.documentElement, true);
293         document.body.removeChild(document.body.firstChild);
294         document.body.appendChild(dom);
295     }
296 }());