Upstream version 10.38.222.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / xml / XMLViewer.js
1 /*
2  * Copyright (C) 2011 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above
12  * copyright notice, this list of conditions and the following disclaimer
13  * in the documentation and/or other materials provided with the
14  * distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. AND ITS CONTRIBUTORS
17  * “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC.
20  * OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 var nodeParentPairs = [];
30
31 // Script entry point.
32
33 var tree;
34
35 function prepareWebKitXMLViewer(noStyleMessage)
36 {
37     var html = createHTMLElement('html');
38     var head = createHTMLElement('head');
39     html.appendChild(head);
40     var style = createHTMLElement('style');
41     style.id = 'xml-viewer-style';
42     head.appendChild(style);
43     var body = createHTMLElement('body');
44     html.appendChild(body);
45     var sourceXML = createHTMLElement('div');
46     sourceXML.id = 'webkit-xml-viewer-source-xml';
47     body.appendChild(sourceXML);
48
49     var child;
50     while (child = document.firstChild) {
51         document.removeChild(child);
52         if (child.nodeType != Node.DOCUMENT_TYPE_NODE)
53             sourceXML.appendChild(child);
54     }
55     document.appendChild(html);
56
57     var header = createHTMLElement('div');
58     body.appendChild(header);
59     header.classList.add('header');
60     var headerSpan = createHTMLElement('span');
61     header.appendChild(headerSpan);
62     headerSpan.textContent = noStyleMessage;
63     header.appendChild(createHTMLElement('br'));
64
65     tree = createHTMLElement('div');
66     body.appendChild(tree);
67     tree.classList.add('pretty-print');
68     window.onload = sourceXMLLoaded;
69 }
70
71 function sourceXMLLoaded()
72 {
73     var sourceXML = document.getElementById('webkit-xml-viewer-source-xml');
74     if (!sourceXML)
75         return; // Stop if some XML tree extension is already processing this document
76
77     for (var child = sourceXML.firstChild; child; child = child.nextSibling)
78         nodeParentPairs.push({parentElement: tree, node: child});
79
80     for (var i = 0; i < nodeParentPairs.length; i++)
81         processNode(nodeParentPairs[i].parentElement, nodeParentPairs[i].node);
82
83     drawArrows();
84     initButtons();
85
86     if (typeof(onAfterWebkitXMLViewerLoaded) == 'function')
87       onAfterWebkitXMLViewerLoaded();
88 }
89
90 // Tree processing.
91
92 function processNode(parentElement, node)
93 {
94     if (!processNode.processorsMap) {
95         processNode.processorsMap = {};
96         processNode.processorsMap[Node.PROCESSING_INSTRUCTION_NODE] = processProcessingInstruction;
97         processNode.processorsMap[Node.ELEMENT_NODE] = processElement;
98         processNode.processorsMap[Node.COMMENT_NODE] = processComment;
99         processNode.processorsMap[Node.TEXT_NODE] = processText;
100         processNode.processorsMap[Node.CDATA_SECTION_NODE] = processCDATA;
101     }
102     if (processNode.processorsMap[node.nodeType])
103         processNode.processorsMap[node.nodeType].call(this, parentElement, node);
104 }
105
106 function processElement(parentElement, node)
107 {
108     if (!node.firstChild)
109         processEmptyElement(parentElement, node);
110     else {
111         var child = node.firstChild;
112         if (child.nodeType == Node.TEXT_NODE && isShort(child.nodeValue) && !child.nextSibling)
113             processShortTextOnlyElement(parentElement, node);
114         else
115             processComplexElement(parentElement, node);
116     }
117 }
118
119 function processEmptyElement(parentElement, node)
120 {
121     var line = createLine();
122     line.appendChild(createTag(node, false, true));
123     parentElement.appendChild(line);
124 }
125
126 function processShortTextOnlyElement(parentElement, node)
127 {
128     var line = createLine();
129     line.appendChild(createTag(node, false, false));
130     for (var child = node.firstChild; child; child = child.nextSibling)
131         line.appendChild(createText(child.nodeValue));
132     line.appendChild(createTag(node, true, false));
133     parentElement.appendChild(line);
134 }
135
136 function processComplexElement(parentElement, node)
137 {
138     var collapsible = createCollapsible();
139
140     collapsible.expanded.start.appendChild(createTag(node, false, false));
141     for (var child = node.firstChild; child; child = child.nextSibling)
142         nodeParentPairs.push({parentElement: collapsible.expanded.content, node: child});
143     collapsible.expanded.end.appendChild(createTag(node, true, false));
144
145     collapsible.collapsed.content.appendChild(createTag(node, false, false));
146     collapsible.collapsed.content.appendChild(createText('...'));
147     collapsible.collapsed.content.appendChild(createTag(node, true, false));
148     parentElement.appendChild(collapsible);
149 }
150
151 function processComment(parentElement, node)
152 {
153     if (isShort(node.nodeValue)) {
154         var line = createLine();
155         line.appendChild(createComment('<!-- ' + node.nodeValue + ' -->'));
156         parentElement.appendChild(line);
157     } else {
158         var collapsible = createCollapsible();
159
160         collapsible.expanded.start.appendChild(createComment('<!--'));
161         collapsible.expanded.content.appendChild(createComment(node.nodeValue));
162         collapsible.expanded.end.appendChild(createComment('-->'));
163
164         collapsible.collapsed.content.appendChild(createComment('<!--'));
165         collapsible.collapsed.content.appendChild(createComment('...'));
166         collapsible.collapsed.content.appendChild(createComment('-->'));
167         parentElement.appendChild(collapsible);
168     }
169 }
170
171 function processCDATA(parentElement, node)
172 {
173     if (isShort(node.nodeValue)) {
174         var line = createLine();
175         line.appendChild(createText('<![CDATA[ ' + node.nodeValue + ' ]]>'));
176         parentElement.appendChild(line);
177     } else {
178         var collapsible = createCollapsible();
179
180         collapsible.expanded.start.appendChild(createText('<![CDATA['));
181         collapsible.expanded.content.appendChild(createText(node.nodeValue));
182         collapsible.expanded.end.appendChild(createText(']]>'));
183
184         collapsible.collapsed.content.appendChild(createText('<![CDATA['));
185         collapsible.collapsed.content.appendChild(createText('...'));
186         collapsible.collapsed.content.appendChild(createText(']]>'));
187         parentElement.appendChild(collapsible);
188     }
189 }
190
191 function processProcessingInstruction(parentElement, node)
192 {
193     if (isShort(node.nodeValue)) {
194         var line = createLine();
195         line.appendChild(createComment('<?' + node.nodeName + ' ' + node.nodeValue + '?>'));
196         parentElement.appendChild(line);
197     } else {
198         var collapsible = createCollapsible();
199
200         collapsible.expanded.start.appendChild(createComment('<?' + node.nodeName));
201         collapsible.expanded.content.appendChild(createComment(node.nodeValue));
202         collapsible.expanded.end.appendChild(createComment('?>'));
203
204         collapsible.collapsed.content.appendChild(createComment('<?' + node.nodeName));
205         collapsible.collapsed.content.appendChild(createComment('...'));
206         collapsible.collapsed.content.appendChild(createComment('?>'));
207         parentElement.appendChild(collapsible);
208     }
209 }
210
211 function processText(parentElement, node)
212 {
213     parentElement.appendChild(createText(node.nodeValue));
214 }
215
216 // Processing utils.
217
218 function trim(value)
219 {
220     return value.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
221 }
222
223 function isShort(value)
224 {
225     return trim(value).length <= 50;
226 }
227
228 // Tree rendering.
229
230 function createHTMLElement(elementName)
231 {
232     return document.createElementNS('http://www.w3.org/1999/xhtml', elementName)
233 }
234
235 function createCollapsible()
236 {
237     var collapsible = createHTMLElement('div');
238     collapsible.classList.add('collapsible');
239     collapsible.expanded = createHTMLElement('div');
240     collapsible.expanded.classList.add('expanded');
241     collapsible.appendChild(collapsible.expanded);
242
243     collapsible.expanded.start = createLine();
244     collapsible.expanded.start.appendChild(createCollapseButton());
245     collapsible.expanded.appendChild(collapsible.expanded.start);
246
247     collapsible.expanded.content = createHTMLElement('div');
248     collapsible.expanded.content.classList.add('collapsible-content');
249     collapsible.expanded.appendChild(collapsible.expanded.content);
250
251     collapsible.expanded.end = createLine();
252     collapsible.expanded.appendChild(collapsible.expanded.end);
253
254     collapsible.collapsed = createHTMLElement('div');
255     collapsible.collapsed.classList.add('collapsed');
256     collapsible.collapsed.classList.add('hidden');
257     collapsible.appendChild(collapsible.collapsed);
258     collapsible.collapsed.content = createLine();
259     collapsible.collapsed.content.appendChild(createExpandButton());
260     collapsible.collapsed.appendChild(collapsible.collapsed.content);
261
262     return collapsible;
263 }
264
265 function createButton()
266 {
267     var button = createHTMLElement('span');
268     button.classList.add('button');
269     return button;
270 }
271
272 function createCollapseButton(str)
273 {
274     var button = createButton();
275     button.classList.add('collapse-button');
276     return button;
277 }
278
279 function createExpandButton(str)
280 {
281     var button = createButton();
282     button.classList.add('expand-button');
283     return button;
284 }
285
286 function createComment(commentString)
287 {
288     var comment = createHTMLElement('span');
289     comment.classList.add('comment');
290     comment.classList.add('webkit-html-comment');
291     comment.textContent = commentString;
292     return comment;
293 }
294
295 function createText(value)
296 {
297     var text = createHTMLElement('span');
298     text.textContent = trim(value);
299     text.classList.add('text');
300     return text;
301 }
302
303 function createLine()
304 {
305     var line = createHTMLElement('div');
306     line.classList.add('line');
307     return line;
308 }
309
310 function createTag(node, isClosing, isEmpty)
311 {
312     var tag = createHTMLElement('span');
313     tag.classList.add('webkit-html-tag');
314
315     var stringBeforeAttrs = '<';
316     if (isClosing)
317         stringBeforeAttrs += '/';
318     stringBeforeAttrs += node.nodeName;
319     var textBeforeAttrs = document.createTextNode(stringBeforeAttrs);
320     tag.appendChild(textBeforeAttrs);
321
322     if (!isClosing) {
323         for (var i = 0; i < node.attributes.length; i++)
324             tag.appendChild(createAttribute(node.attributes[i]));
325     }
326
327     var stringAfterAttrs = '';
328     if (isEmpty)
329         stringAfterAttrs += '/';
330     stringAfterAttrs += '>';
331     var textAfterAttrs = document.createTextNode(stringAfterAttrs);
332     tag.appendChild(textAfterAttrs);
333
334     return tag;
335 }
336
337 function createAttribute(attributeNode)
338 {
339     var attribute = createHTMLElement('span');
340     attribute.classList.add('webkit-html-attribute');
341
342     var attributeName = createHTMLElement('span');
343     attributeName.classList.add('webkit-html-attribute-name');
344     attributeName.textContent = attributeNode.name;
345
346     var textBefore = document.createTextNode(' ');
347     var textBetween = document.createTextNode('="');
348
349     var attributeValue = createHTMLElement('span');
350     attributeValue.classList.add('webkit-html-attribute-value');
351     attributeValue.textContent = attributeNode.value;
352
353     var textAfter = document.createTextNode('"');
354
355     attribute.appendChild(textBefore);
356     attribute.appendChild(attributeName);
357     attribute.appendChild(textBetween);
358     attribute.appendChild(attributeValue);
359     attribute.appendChild(textAfter);
360     return attribute;
361 }
362
363 // Tree behaviour.
364
365 function drawArrows()
366 {
367     var ctx = document.getCSSCanvasContext("2d", "arrowRight", 10, 11);
368
369     ctx.fillStyle = "rgb(90,90,90)";
370     ctx.beginPath();
371     ctx.moveTo(0, 0);
372     ctx.lineTo(0, 8);
373     ctx.lineTo(7, 4);
374     ctx.lineTo(0, 0);
375     ctx.fill();
376     ctx.closePath();
377
378     var ctx = document.getCSSCanvasContext("2d", "arrowDown", 10, 10);
379
380     ctx.fillStyle = "rgb(90,90,90)";
381     ctx.beginPath();
382     ctx.moveTo(0, 0);
383     ctx.lineTo(8, 0);
384     ctx.lineTo(4, 7);
385     ctx.lineTo(0, 0);
386     ctx.fill();
387     ctx.closePath();
388 }
389
390 function expandFunction(sectionId)
391 {
392     return function()
393     {
394         document.querySelector('#' + sectionId + ' > .expanded').className = 'expanded';
395         document.querySelector('#' + sectionId + ' > .collapsed').className = 'collapsed hidden';
396     };
397 }
398
399 function collapseFunction(sectionId)
400 {
401     return function()
402     {
403         document.querySelector('#' + sectionId + ' > .expanded').className = 'expanded hidden';
404         document.querySelector('#' + sectionId + ' > .collapsed').className = 'collapsed';
405     };
406 }
407
408 function initButtons()
409 {
410     var sections = document.querySelectorAll('.collapsible');
411     for (var i = 0; i < sections.length; i++) {
412         var sectionId = 'collapsible' + i;
413         sections[i].id = sectionId;
414
415         var expandedPart = sections[i].querySelector('#' + sectionId + ' > .expanded');
416         var collapseButton = expandedPart.querySelector('.collapse-button');
417         collapseButton.onclick = collapseFunction(sectionId);
418         collapseButton.onmousedown = handleButtonMouseDown;
419
420         var collapsedPart = sections[i].querySelector('#' + sectionId + ' > .collapsed');
421         var expandButton = collapsedPart.querySelector('.expand-button');
422         expandButton.onclick = expandFunction(sectionId);
423         expandButton.onmousedown = handleButtonMouseDown;
424     }
425
426 }
427
428 function handleButtonMouseDown(e)
429 {
430    // To prevent selection on double click
431    e.preventDefault();
432 }