X-Git-Url: https://git.mdrn.pl/redakcja.git/blobdiff_plain/3d61fc117d9e5274189d16be83d4489cd4b36d7f..5fa827a3cd9dcbfb587074f6046a66cbe1d5f5e4:/platforma/static/js/xslt.js
diff --git a/platforma/static/js/xslt.js b/platforma/static/js/xslt.js
index f164c5bd..f5af909b 100644
--- a/platforma/static/js/xslt.js
+++ b/platforma/static/js/xslt.js
@@ -1,4 +1,97 @@
-var MARGIN = {
+/*
+ *
+ * XSLT STUFF
+ *
+ */
+function createXSLT(xsl) {
+ var p = new XSLTProcessor();
+ p.importStylesheet(xsl);
+ return p;
+}
+
+var xml2htmlStylesheet = null;
+
+// Wykonuje block z zaÅadowanymi arkuszami stylów
+function withStylesheets(code_block, onError)
+{
+ if (!xml2htmlStylesheet) {
+ $.blockUI({message: 'Åadowanie arkuszy stylów...'});
+ $.ajax({
+ url: STATIC_URL + 'xsl/wl2html_client.xsl',
+ dataType: 'xml',
+ success: function(data) {
+ xml2htmlStylesheet = createXSLT(data);
+ $.unblockUI();
+ code_block();
+
+ },
+ error: onError
+ })
+ }
+ else {
+ code_block();
+ }
+}
+
+
+function xml2html(options) {
+ withStylesheets(function() {
+ var xml = options.xml.replace(/\/\s+/g, '
');
+ var parser = new DOMParser();
+ var serializer = new XMLSerializer();
+ var doc = parser.parseFromString(xml, 'text/xml');
+ var error = $('parsererror', doc);
+
+ if (error.length == 0) {
+ doc = xml2htmlStylesheet.transformToFragment(doc, document);
+ console.log(doc.firstChild);
+
+ if(doc.firstChild === null) {
+ options.error("BÅÄ
d w przetwarzaniu XML.");
+ return;
+ }
+
+ error = $('parsererror', doc);
+ }
+
+ if (error.length > 0 && options.error) {
+ options.error(error.text());
+ } else {
+ options.success(doc.firstChild);
+ }
+ }, function() { options.error && options.error('Nie udaÅo siÄ zaÅadowaÄ XSLT'); });
+}
+
+/* USEFULL CONSTANTS */
+const ELEMENT_NODE = 1;
+const ATTRIBUTE_NODE = 2;
+const TEXT_NODE = 3;
+const CDATA_SECTION_NODE = 4;
+const ENTITY_REFERENCE_NODE = 5;
+const ENTITY_NODE = 6;
+const PROCESSING_INSTRUCTION_NODE = 7;
+const COMMENT_NODE = 8;
+const DOCUMENT_NODE = 9;
+const DOCUMENT_TYPE_NODE = 10;
+const DOCUMENT_FRAGMENT_NODE = 11;
+const NOTATION_NODE = 12;
+const XATTR_RE = /^x-attr-name-(.*)$/;
+
+const ELEM_START = 1;
+const ELEM_END = 2;
+const NS_END = 3;
+
+const NAMESPACES = {
+ // namespaces not listed here will be assigned random names
+ "http://www.w3.org/1999/02/22-rdf-syntax-ns#": "rdf",
+ "http://purl.org/dc/elements/1.1/": "dc",
+ "http://www.w3.org/XML/1998/namespace": "xml"
+};
+
+/*
+ * PADDING for pretty-printing
+ */
+const PADDING = {
dramat_wierszowany_l: 4,
dramat_wierszowany_lp: 4,
dramat_wspolczesny: 4,
@@ -23,200 +116,258 @@ var MARGIN = {
autor_utworu: 2,
nazwa_utworu: 2,
dzielo_nadrzedne: 2,
+
didaskalia: 2,
motto_podpis: 2,
naglowek_listy: 2,
-
kwestia: 1,
- lista_osoba: 1
-}
+ lista_osoba: 1,
+
+ "podpis": 1,
+ "wers": 0,
+ "wers_cd": 0,
+ "wers_akap": 0,
+ "wers_wciety": 0,
+
+ "rdf:RDF": 3,
+ "rdf:Description": 1,
+};
-MARGIN['rdf:RDF'] = 3;
-MARGIN['rdf:Description'] = 2;
+function getPadding(name) {
+
+ if(name.match(/^dc:.*$/))
+ return -1;
+
+ if(PADDING[name])
+ return PADDING[name];
+
+ return 0;
+}
-function elementType(element) {
- if ($.inArray(element.tagName, ['akap', 'akap_cd', 'akap_dialog', 'strofa', 'didaskalia', 'wers', 'wers_cd', 'wers_akap', 'wers_wciety', 'autor_utworu', 'nazwa_utworu', 'dzielo_nadrzedne', 'podpis'])) {
- return 'inline';
- } else {
- return 'block';
- }
+function HTMLSerializer() {
+ // empty constructor
}
-// Serializuje XML, wstawiajÄ
c odpowiednie iloÅci biaÅych znaków miÄdzy elementami
-function serialize(element, mode) {
- if (!mode) {
- mode = 'block';
- }
-
- if (element.nodeType == 3) { // tekst
- if (mode == 'block') {
- return [$.trim(element.nodeValue)];
- } else {
- return [element.nodeValue];
- }
- } else if (element.nodeType != 1) { // pomijamy wÄzÅy nie bÄdÄ
ce elementami XML ani tekstem
- return [];
- }
-
- var result = [];
- var hasContent = false;
-
- if (MARGIN[element.tagName]) {
- for (var i=0; i < MARGIN[element.tagName]; i++) {
- result.push('\n');
- };
- } else if (element.tagName.indexOf('dc:') != -1) {
- result.push('\n');
- }
-
- result.push('<');
- result.push(element.tagName);
-
- // Mozilla nie uważa deklaracji namespace za atrybuty
- var ns = element.tagName.indexOf(':');
- if (ns != -1 && $.browser.mozilla) {
- result.push(' xmlns:');
- result.push(element.tagName.substring(0, ns));
- result.push('="');
- result.push(element.namespaceURI);
- result.push('"');
- }
-
- if (element.attributes) {
- for (var i=0; i < element.attributes.length; i++) {
- var attr = element.attributes[i];
- result.push(' ');
- result.push(attr.name);
- result.push('="');
- result.push(attr.value);
- result.push('"');
- hasContent = true;
- }
- }
-
- if (element.childNodes.length == 0) {
- result.push(' />');
- } else {
- result.push('>');
-
- for (var i=0; i < element.childNodes.length; i++) {
- result = result.concat(serialize(element.childNodes[i],
- mode == 'inline' ? 'inline' : elementType(element.childNodes[i])));
- }
- result.push('');
- result.push(element.tagName);
- result.push('>');
- }
-
- return result;
-};
+HTMLSerializer.prototype._prepare = function() {
+ this.stack = [];
+
+ // XML namespace is implicit
+ this.nsMap = {"http://www.w3.org/XML/1998/namespace": "xml"};
+
+ this.result = "";
+ this.nsCounter = 1;
+}
-function createXSLT(xsl) {
- var p = new XSLTProcessor();
- p.importStylesheet(xsl);
- return p;
+HTMLSerializer.prototype._pushElement = function(element) {
+ this.stack.push({
+ "type": ELEM_START,
+ "node": element
+ });
}
+HTMLSerializer.prototype._pushChildren = function(element) {
+ for(var i = element.childNodes.length-1; i >= 0; i--)
+ this._pushElement(element.childNodes.item(i));
+}
-var xml2htmlStylesheet = null;
-var html2xmlStylesheet = null;
+HTMLSerializer.prototype._pushTagEnd = function(tagName) {
+ this.stack.push({
+ "type": ELEM_END,
+ "tagName": tagName
+ });
+}
+HTMLSerializer.prototype._verseBefore = function(node) {
+ var prev = node.previousSibling;
+
+ while((prev !== null) && (prev.nodeType != ELEMENT_NODE)) {
+ prev = prev.previousSibling;
+ }
+
+ return (prev !== null) && prev.hasAttribute('x-verse');
+}
-// Wykonuje block z zaÅadowanymi arkuszami stylów
-function withStylesheets(block, onError) {
- if (xml2htmlStylesheet && html2xmlStylesheet) {
- block();
- return;
- }
- $.blockUI({message: 'Åadowanie arkuszy stylów...'});
- $.ajax({
- url: '/static/xsl/wl2html_client.xsl',
- dataType: 'xml',
- success: function(data) {
- xml2htmlStylesheet = createXSLT(data);
- $.ajax({
- url: '/static/xsl/html2wl_client.xsl',
- dataType: 'xml',
- success: function(data) {
- html2xmlStylesheet = createXSLT(data);
- $.unblockUI();
- block();
- },
- error: onError
- })
- },
- error: onError
- })
+HTMLSerializer.prototype.serialize = function(rootElement, stripOuter)
+{
+ var self = this;
+ self._prepare();
+
+ if(!stripOuter)
+ self._pushElement(rootElement);
+ else
+ self._pushChildren(rootElement);
+
+ while(self.stack.length > 0) {
+ var token = self.stack.pop();
+
+ if(token.type === ELEM_END) {
+ self.result += "" + token.tagName + ">";
+ for(var padding = getPadding(token.tagName); padding > 0; padding--) {
+ self.result += "\n";
+ }
+ continue;
+ };
+
+ if(token.type === NS_END) {
+ self._unassignNamespace(token.namespace);
+ continue;
+ }
+
+
+ switch(token.node.nodeType) {
+ case ELEMENT_NODE:
+ if(token.node.hasAttribute('x-pass-thru')) {
+ self._pushChildren(token.node);
+ break;
+ }
+
+ if(!token.node.hasAttribute('x-node'))
+ break;
+
+ var xnode = token.node.getAttribute('x-node');
+
+ if(xnode === 'wers') {
+ /* push children */
+ if(self._verseBefore(token.node))
+ self.result += '/\n';
+ self._pushChildren(token.node);
+ break;
+ };
+
+ if(token.node.hasAttribute('x-verse') && self._verseBefore(token.node)) {
+ self.result += '/\n';
+ };
+
+ self._serializeElement(token.node);
+ break;
+ case TEXT_NODE:
+ self.result += token.node.nodeValue;
+ break;
+ };
+ };
+
+ return this.result;
}
-function transform(editor) {
- $.blockUI({message: 'Åadowanie...'});
- withStylesheets(function() {
- setTimeout(function() {
- var doc = null;
- var parser = new DOMParser();
- var serializer = new XMLSerializer();
-
- doc = editor.getCode().replace(/\/\s+/g, '
');
- doc = parser.parseFromString(doc, 'text/xml');
- var error = $('parsererror', doc);
- console.log(error);
- if (error.length == 0) {
- doc = xml2htmlStylesheet.transformToFragment(doc, document);
- error = $('parsererror', doc);
- }
- console.log('xml', doc);
- if (error.length > 0) {
- console.log(error);
- $('#html-view').html('
WystÄ piÅ bÅÄ d:
' + error.text() + ''); - } else { - console.log('after transform', doc); - $('#html-view').html(doc.firstChild); - } - - $.unblockUI(); - }, 200); - }, function() { alert('Nie udaÅo siÄ zaÅadowaÄ XSLT!'); }); +/* + * TODO: this doesn't support prefix redefinitions + */ +HTMLSerializer.prototype._unassignNamespace = function(nsData) { + this.nsMap[nsData.uri] = undefined; +}; + +HTMLSerializer.prototype._assignNamespace = function(uri) { + if(uri === null) { + // default namespace + return ({"prefix": "", "uri": "", "fresh": false}); + } + + if(this.nsMap[uri] === undefined) { + // this prefix hasn't been defined yet in current context + var prefix = NAMESPACES[uri]; + + if (prefix === undefined) { // not predefined + prefix = "ns" + this.nsCounter; + this.nsCounter += 1; + } + + this.nsMap[uri] = prefix; + return ({ + "prefix": prefix, + "uri": uri, + "fresh": true + }); + } + + return ({"prefix": this.nsMap[uri], "uri": uri, "fresh": false}); }; +HTMLSerializer.prototype._join = function(prefix, name) { + if(!!prefix) + return prefix + ":" + name; + return name; +}; -function reverseTransform(editor) { - $.blockUI({message: 'Åadowanie...'}); - withStylesheets(function() { - setTimeout(function() { - var doc = null; - var parser = new DOMParser(); - var serializer = new XMLSerializer(); - - if ($('#html-view .error').length > 0) { - $('#source-editor').unblock(); - return; - } - - doc = serializer.serializeToString($('#html-view div').get(0)) - doc = parser.parseFromString(doc, 'text/xml'); - console.log('xml',doc, doc.documentElement); - // TODO: Sprawdzenie bÅÄdów - var error = $('parsererror', doc.documentElement); - console.log(error); - if (error.length == 0) { - doc = html2xmlStylesheet.transformToDocument(doc, document); - error = $('parsererror', doc.documentElement); - } - - if (error.length > 0) { - console.log(error); - $('#source-editor').html('
WystÄ piÅ bÅÄ d:
' + error.text()); - } else { - doc = serialize(doc.documentElement).join(''); - editor.setCode(doc); - } - - console.log('after transform', doc, doc.documentElement); - $.unblockUI(); - }, 200) - }, function() { alert('Nie udaÅo siÄ zaÅadowaÄ XSLT!')}); +HTMLSerializer.prototype._rjoin = function(prefix, name) { + if(!!name) + return prefix + ":" + name; + return prefix; +}; + +HTMLSerializer.prototype._serializeElement = function(node) { + var self = this; + + var ns = node.getAttribute('x-ns'); + var nsPrefix = null; + var newNamespaces = []; + + var nsData = self._assignNamespace(node.getAttribute('x-ns')); + + if(nsData.fresh) { + newNamespaces.push(nsData); + self.stack.push({ + "type": NS_END, + "namespace": nsData + }); + } + + var tagName = self._join(nsData.prefix, node.getAttribute('x-node')); + + /* retrieve attributes */ + var attributeIDs = []; + for (var i = 0; i < node.attributes.length; i++) { + var attr = node.attributes.item(i); + + // check if name starts with "x-attr-name" + var m = attr.name.match(XATTR_RE); + if (m !== null) + attributeIDs.push(m[1]); + }; + + /* print out */ + if (getPadding(tagName)) + self.result += '\n'; + + self.result += '<' + tagName; + + $.each(attributeIDs, function() { + var nsData = self._assignNamespace(node.getAttribute('x-attr-ns-'+this)); + + if(nsData.fresh) { + newNamespaces.push(nsData); + self.stack.push({ + "type": NS_END, + "namespace": nsData + }); + }; + + self.result += ' ' + self._join(nsData.prefix, node.getAttribute('x-attr-name-'+this)); + self.result += '="'+node.getAttribute('x-attr-value-'+this) +'"'; + }); + + /* print new namespace declarations */ + $.each(newNamespaces, function() { + self.result += " " + self._rjoin("xmlns", this.prefix); + self.result += '="' + this.uri + '"'; + }); + + if (node.childNodes.length > 0) { + self.result += ">"; + self._pushTagEnd(tagName); + self._pushChildren(node); + } + else { + self.result += "/>"; + }; }; +function html2text(params) { + try { + var s = new HTMLSerializer(); + params.success( s.serialize(params.element, params.stripOuter) ); + } catch(e) { + params.error("Nie udaÅo siÄ zserializowaÄ tekstu:" + e) + } +} \ No newline at end of file