Removed buggy html2wl XSLT - replaced with a Javascript HTML serializer.
[redakcja.git] / platforma / static / js / xslt.js
1 var MARGIN = {
2     dramat_wierszowany_l: 4,
3     dramat_wierszowany_lp: 4,
4     dramat_wspolczesny: 4,
5     wywiad: 4,
6     opowiadanie: 4,
7     powiesc: 4,
8     liryka_l: 4,
9     liryka_lp: 4,
10     naglowek_czesc: 4,
11     naglowek_akt: 4,
12     naglowek_rozdzial: 4,
13     naglowek_osoba: 4,
14     lista_osob: 4,
15     
16     akap: 3,
17     akap_cd: 3,
18     akap_dialog: 3,
19     strofa: 3,
20     motto: 3, 
21     miejsce_czas: 3,
22         
23     autor_utworu: 2,
24     nazwa_utworu: 2,
25     dzielo_nadrzedne: 2,
26     didaskalia: 2,
27     motto_podpis: 2,
28     naglowek_listy: 2,
29     
30     kwestia: 1,
31     lista_osoba: 1
32 }
33
34 MARGIN['rdf:RDF'] = 3;
35 MARGIN['rdf:Description'] = 2;
36
37 var blockTags = ['akap', 'akap_cd', 'akap_dialog', 'strofa', 'didaskalia', 'wers', 'wers_cd', 'wers_akap', 'wers_wciety', 'autor_utworu', 'nazwa_utworu', 'dzielo_nadrzedne', 'podpis'];
38 function elementType(element) {
39     if (blockTags.indexOf(element.tagName) != -1) {
40         return 'inline';
41     } else {
42         return 'block';
43     }
44 }
45
46 // Serializuje XML, wstawiając odpowiednie ilości białych znaków między elementami
47 function serialize(element, mode) {
48     if (!mode) {
49         mode = 'block';
50     }
51     
52     if (element.nodeType == 3) { // tekst
53         return [element.nodeValue];        
54     } else if (element.nodeType != 1) { // pomijamy węzły nie będące elementami XML ani tekstem
55         return [];
56     }
57     
58     var result = [];
59     var hasContent = false;
60     
61     
62     
63     if (MARGIN[element.tagName]) {
64         for (var i=0; i < MARGIN[element.tagName]; i++) {
65             result.push('\n');
66         };
67     } else if (element.tagName.indexOf('dc:') != -1) {
68         result.push('\n');
69     }
70     
71     result.push('<');
72     result.push(element.tagName);
73     
74     // Mozilla nie uważa deklaracji namespace za atrybuty | --lqc: bo nie są one atrybutami!
75     var ns = element.tagName.indexOf(':');
76     if (ns != -1 && $.browser.mozilla) {
77         result.push(' xmlns:');
78         result.push(element.tagName.substring(0, ns));
79         result.push('="');
80         result.push(element.namespaceURI);
81         result.push('"');
82     }
83     
84     if (element.attributes) {
85         for (var i=0; i < element.attributes.length; i++) {
86             var attr = element.attributes[i];
87             result.push(' ');
88             result.push(attr.name);
89             result.push('="');
90             result.push(attr.value);
91             result.push('"');
92             hasContent = true;
93         }
94     }
95     
96     if (element.childNodes.length == 0) {
97         result.push(' />');
98     } else {
99         result.push('>');
100
101         for (var i=0; i < element.childNodes.length; i++) {
102             result = result.concat(serialize(element.childNodes[i], 
103                 mode == 'inline' ? 'inline' : elementType(element.childNodes[i])));
104         }
105
106         result.push('</');
107         result.push(element.tagName);
108         result.push('>');
109     }
110     
111     return result;
112 };
113
114
115 function createXSLT(xsl) {
116     var p = new XSLTProcessor();
117     p.importStylesheet(xsl);
118     return p;
119 }
120
121
122 var xml2htmlStylesheet = null;
123 var html2xmlStylesheet = null;
124
125
126 // Wykonuje block z załadowanymi arkuszami stylów
127 function withStylesheets(block, onError) {
128     if (xml2htmlStylesheet && html2xmlStylesheet) {
129         block();
130         return;
131     }
132     $.blockUI({message: 'Ładowanie arkuszy stylów...'});
133     $.ajax({
134         url: STATIC_URL + 'xsl/wl2html_client.xsl',
135         dataType: 'xml',
136         success: function(data) {
137             xml2htmlStylesheet = createXSLT(data);
138             $.ajax({
139                 url: STATIC_URL + 'xsl/html2wl_client.xsl',
140                 dataType: 'xml',
141                 success: function(data) {
142                     html2xmlStylesheet = createXSLT(data);
143                     $.unblockUI();
144                     block();
145                 },
146                 error: onError
147             })
148         },
149         error: onError
150     })
151 }
152
153
154 function xml2html(options) {
155     withStylesheets(function() {
156         var xml = options.xml.replace(/\/\s+/g, '<br />');                              
157         var parser = new DOMParser();
158         var serializer = new XMLSerializer();
159         var doc = parser.parseFromString(xml, 'text/xml');              
160         var error = $('parsererror', doc);
161         
162         if (error.length == 0) {
163             doc = xml2htmlStylesheet.transformToDocument(doc);
164                         console.log(doc);
165             error = $('parsererror', doc);
166         }
167         
168         if (error.length > 0 && options.error) {
169             options.error(error.text());
170         } else {                        
171             options.success(document.importNode(doc.documentElement, true));
172         }
173     }, function() { options.error && options.error('Nie udało się załadować XSLT'); });
174 }
175
176 /* USEFULL CONSTANTS */
177 const ELEMENT_NODE                                       = 1;
178 const ATTRIBUTE_NODE                 = 2;
179 const TEXT_NODE                      = 3;
180 const CDATA_SECTION_NODE             = 4;
181 const ENTITY_REFERENCE_NODE          = 5;
182 const ENTITY_NODE                    = 6;
183 const PROCESSING_INSTRUCTION_NODE    = 7;
184 const COMMENT_NODE                   = 8;
185 const DOCUMENT_NODE                  = 9;
186 const DOCUMENT_TYPE_NODE             = 10;
187 const DOCUMENT_FRAGMENT_NODE         = 11;
188 const NOTATION_NODE                  = 12;
189 const XATTR_RE = /^x-attr-name-(.*)$/;
190
191 const ELEM_START = 1;
192 const ELEM_END = 2;
193
194 const NAMESPACES = {
195         undefined: "",
196         null: "",       
197         "": "",
198         "http://www.w3.org/1999/02/22-rdf-syntax-ns#": "rdf:",
199         "http://purl.org/dc/elements/1.1/": "dc:",
200         "http://www.w3.org/XML/1998/namespace": "xml:"
201 };
202
203 function html2text(rootElement) {
204         var stack = [];
205         var result = "";
206         
207         stack.push([ELEM_START, rootElement]);  
208         console.log("SERIALIZING")
209         
210         while( stack.length > 0) {
211                 var pair = stack.pop();
212                 
213                 var event = pair[0];
214                 var node = pair[1];
215                 
216                 // console.log("NODE", event, node);
217                 
218                 if(event == ELEM_END) {
219                         result += "</" + node + ">\n";
220                         continue;
221                 };
222                 
223                 switch(node.nodeType) {
224                         case ELEMENT_NODE:
225                                 if(!node.hasAttribute('x-node'))
226                                         break;
227                                         
228                                 var tag_name = NAMESPACES[node.getAttribute('x-ns')] + node.getAttribute('x-node');
229                                 // console.log("ELEMENT: ", tag_name);
230                                 
231                                 /* retrieve attributes */
232                                 var attr_ids = [];
233                                 for(var i=0; i < node.attributes.length; i++) {
234                                         var attr = node.attributes.item(i);
235                                         
236                                         // check if name starts with "x-attr-name"
237                                         var m = attr.name.match(XATTR_RE);
238                                         if(m !== null) 
239                                                 attr_ids.push(m[1]);                                            
240                                         
241                                 };
242                                 
243                                 result += '<' + tag_name;
244                                 
245                                 $.each(attr_ids, function() {                                                                           
246                                         result += ' ' + NAMESPACES[node.getAttribute('x-attr-ns-'+this)];
247                                         result += node.getAttribute('x-attr-name-'+this);
248                                         result += '="'+node.getAttribute('x-attr-value-'+this) +'"';
249                                 });                                                             
250                                 result += '>'
251                                 
252                                 stack.push([ELEM_END, tag_name]);
253                                 for(var i = node.childNodes.length-1; i >= 0; i--)
254                                         stack.push([ELEM_START, node.childNodes.item(i)]);                              
255                                 
256                                 break;                  
257                         case TEXT_NODE:
258                                 result += node.nodeValue;
259                                 break;
260                 }               
261         }
262         
263         return result;
264 }
265
266 function html2xml(options) {
267         try {
268                 return options.success(html2text(options.htmlElement));
269         } catch(e) {
270                 options.error("Nie udało się zserializować tekstu:" + e)
271         }    
272 };