return false;
},
- asWLML: function(element)
+ asWLML: function(element, inner)
{
console.log("Source", element);
var doc = this.parser.parseFromString(this.serializer.serializeToString(element), 'text/xml');
}
console.log("Transformed", doc, " to: ", result.documentElement);
- return this.serializer.serializeToString(result.documentElement);
+ if(inner) {
+ var children = result.documentElement.childNodes;
+ var buf = '';
+
+ for(var i=0; i < children.length; i++)
+ buf += this.serializer.serializeToString(children.item(i));
+
+ return buf;
+ }
+
+ return this.serializer.serializeToString(result.documentElement);
+ },
+
+ innerAsWLML: function(elem)
+ {
+ return this.asWLML(elem, true);
+ },
+
+ updateInnerWithWLML: function($element, innerML)
+ {
+ var e = $element.clone().html('<span x-node="out-of-flow-text" x-content="%"></span>')[0];
+ var s = this.asWLML(e);
+ // hurray for dirty hacks :P
+ s = s.replace(/>%<\//, '>'+innerML+'</');
+ return this.updateWithWLML($element, s);
},
updateWithWLML: function($element, text)
{
// filter the string
text = text.replace(/\/\s+/g, '<br />');
- var chunk = this.parser.parseFromString("<chunk>"+text+"</chunk>", "text/xml");
-
- var errors = $('parsererror', chunk);
+ try {
+ var chunk = this.parser.parseFromString("<chunk>"+text+"</chunk>", "text/xml");
+ } catch(e) {
+ console.log('Caught parse exception.');
+ return "<p>Źle sformatowana zawartość:" + e.toString() + "</p>";
+ }
- // check if chunk is parsable
- if(errors.length > 0)
- throw {text: errors.text(), html: errors.html()};
+ var parseError = chunk.getElementsByTagName('parsererror');
+ console.log("Errors:", parseError);
- var result = this.htmlXSL.transformToFragment(chunk, document);
+ if(parseError.length > 0)
+ {
+ console.log("Parse errors.")
+ return this.serializer.serializeToString(parseError.item(0));
+ }
- console.log("RESULT", this.serializer.serializeToString(result));
+ console.log("Transforming to HTML");
+ var result = this.htmlXSL.transformToFragment(chunk, $element[0].ownerDocument).firstChild;
- if(!result)
- throw "WLML->HTML transformation failed.";
-
- $element.replaceWith(result);
- this.set('state', 'dirty');
+ if(!result) {
+ return "Błąd aplikacji - nie udało się wygenerować nowego widoku HTML.";
+ }
+
+ var errors = result.getElementsByTagName('error');
+ if(errors.length > 0)
+ {
+ var errorMessage = 'Wystąpiły błędy:<ul>';
+ for(var i=0; i < errors.length; i++)
+ {
+ var estr = this.serializer.serializeToString(errors.item(i));
+ console.log("XFRM error:", estr);
+ errorMessage += "<li>"+estr+"</li>";
+ }
+ errorMessage += "</ul>";
+ return errorMessage;
+ }
+
+ try {
+ $element.replaceWith(result);
+ this.set('state', 'dirty');
+ return false;
+ } catch(e) {
+ return "Błąd podczas wstawiania tekstu: '" + e.toString() + "'";
+ }
},
createXSLT: function(xslt_doc) {
if(this.wlmlXSL && this.htmlXSL && this.rawText)
this.loadSuccess();
} catch(e) {
- this.loadingFailed();
+ console.log(e);
+ this.set('error', e.toString() );
+ this.set('state', 'error');
}
},
if(this.wlmlXSL && this.htmlXSL && this.rawText)
this.loadSuccess();
} catch(e) {
- this.loadingFailed();
+ console.log(e);
+ this.set('error', e.toString() );
+ this.set('state', 'error');
}
},
this.$printLink = $('.htmlview-toolbar .html-print-link', this.element);
this.$docbase = $('.htmlview', this.element);
this.$addThemeButton = $('.htmlview-toolbar .html-add-motive', this.element);
-
- this.$debugButton = $('.htmlview-toolbar .html-serialize', this.element);
+ // this.$debugButton = $('.htmlview-toolbar .html-serialize', this.element);
this.updatePrintLink();
this.$docbase.bind('click', this.itemClicked.bind(this));
this.$addThemeButton.click( this.addTheme.bind(this) );
- this.$debugButton.click( this.serialized.bind(this) );
+ // this.$debugButton.click( this.serialized.bind(this) );
},
- serialized: function() {
+ /* serialized: function() {
this.model.set('state', 'dirty');
console.log( this.model.serializer.serializeToString(this.model.get('data')) );
- },
+ }, */
renderPart: function($e, html) {
// exceptions aren't good, but I don't have a better idea right now
* - this greatly simplifies the whole click check
*/
- if( $e.hasClass('theme-ref') )
+ if( $e.hasClass('motyw') )
{
console.log($e);
- this.selectTheme($e.attr('x-theme-class'));
+ this.selectTheme($e.attr('theme-class'));
return false;
}
/* other buttons */
try {
+ if($e.hasClass('delete-button'))
+ this.deleteElement( this.editableFor($e) );
+
if($e.hasClass('edit-button'))
this.openForEdit( this.editableFor($e) );
if($e.hasClass('reject-button'))
this.closeWithoutSave( this.editableFor($e) );
} catch(e) {
- messageCenter.addMessage('error', "wlsave", 'Błąd:' + e.text);
+ messageCenter.addMessage('error', "wlsave", 'Błąd:' + e.toString());
}
return false;
closeWithSave: function($e) {
var $edit = $e.data('edit-overlay');
var newText = $('textarea', $edit).val();
-
- this.model.updateWithWLML($e, newText);
- $edit.remove();
- this.currentOpen = null;
+ var errors = null;
+
+ errors = this.model.updateInnerWithWLML($e, newText);
+
+ if(errors)
+ messageCenter.addMessage('error', 'render', errors);
+ else {
+ $edit.remove();
+ this.currentOpen = null;
+ }
},
closeWithoutSave: function($e) {
// start edition on this node
var $overlay = $('<div class="html-editarea"><textarea></textarea></div>');
+
+ h = Math.max(h, 2*parseInt($box.css('line-height')));
$overlay.css({
position: 'absolute',
});
try {
- $('textarea', $overlay).val( this.model.asWLML($origin[0]) );
+ $('textarea', $overlay).val( this.model.innerAsWLML($origin[0]) );
if($origin.is(".annotation-inline-box"))
{
return false;
},
+
+ deleteElement: function($editable)
+ {
+ var relatedThemes = $("*[x-node='begin'], *[x-node='end']", $editable);
+
+ var themeMarks = relatedThemes.map(function() {
+ return $(".motyw[theme-class='"+$(this).attr('theme-class')+"']");
+ });
+
+ if($editable.is("*.motyw"))
+ {
+ console.log($editable);
+ var selector = "[theme-class='"+$editable.attr('theme-class')+"']";
+ relatedThemes = relatedThemes.add("*[x-node='begin']"+selector+", *[x-node='end']"+selector);
+ }
+
+ console.log(relatedThemes, themeMarks);
+
+ var del = confirm("Usunięcie elementu jest nieodwracalne.\n"
+ +" Czy na pewno chcesz usunąć ten element, wraz z zawartymi motywami ?\n");
+
+ if(del) {
+ relatedThemes.remove();
+ themeMarks.remove();
+ $editable.remove();
+ }
+ },
+
+ // Theme related stuff
+ verifyThemeInsertPoint: function(node) {
+
+ if(node.nodeType == 3) { // Text Node
+ node = node.parentNode;
+ }
+
+ if(node.nodeType != 1) return false;
+
+ console.log('Selection point:', node);
+
+ node = $(node);
+ var xtype = node.attr('x-node');
+
+ if(!xtype || (xtype.search(':') >= 0) ||
+ xtype == 'motyw' || xtype == 'begin' || xtype == 'end')
+ return false;
+
+ // this is hopefully redundant
+ //if(! node.is('*.utwor *') )
+ // return false;
+
+ // don't allow themes inside annotations
+ if( node.is('*[x-annotation-box] *') )
+ return false;
+
+ return true;
+ },
addTheme: function()
{
console.log("Range count:", n);
- if(n == 0)
+ if(n == 0) {
window.alert("Nie zaznaczono żadnego obszaru");
+ return false;
+ }
// for now allow only 1 range
- if(n > 1)
+ if(n > 1) {
window.alert("Zaznacz jeden obszar");
-
+ return false;
+ }
// from this point, we will assume that the ranges are disjoint
for(var i=0; i < n; i++)
{
var range = selection.getRangeAt(i);
console.log(i, range.startContainer, range.endContainer);
+
+ // verify if the start/end points make even sense -
+ // they must be inside a x-node (otherwise they will be discarded)
+ // and the x-node must be a main text
+ if(! this.verifyThemeInsertPoint(range.startContainer) ) {
+ window.alert("Motyw nie może się zaczynać w tym miejscu.");
+ return false;
+ }
+
+ if(! this.verifyThemeInsertPoint(range.endContainer) ) {
+ window.alert("Motyw nie może się kończyć w tym miejscu.");
+ return false;
+ }
+
+
var date = (new Date()).getTime();
var random = Math.floor(4000000000*Math.random());
var id = (''+date) + '-' + (''+random);
spoint.setStart(range.startContainer, range.startOffset);
epoint.setStart(range.endContainer, range.endOffset);
- // insert theme-ref
-
- var elem = $('<span x-editable="true" x-node="motyw" class="motyw">Nowy motyw</span>');
- elem.attr('x-attr-qname-'+id, 'id');
- elem.attr('x-attr-value-'+id, 'm'+id);
- spoint.insertNode(elem[0]);
+ var mtag, btag, etag, errors;
+
+ // insert theme-ref
+ mtag = $('<span></span>');
+ spoint.insertNode(mtag[0]);
+ errors = this.model.updateWithWLML(mtag, '<motyw id="m'+id+'">Nowy Motyw</motyw>');
+ if(errors) {
+ messageCenter.addMessage('error', null, 'Błąd przy dodawaniu motywu :' + errors);
+ return false;
+ }
// insert theme-begin
- elem = $('<span x-node="begin" class="begin"></span>');
- elem.attr('x-attr-qname-'+id, 'id');
- elem.attr('x-attr-value-'+id, 'b'+id);
- spoint.insertNode(elem[0]);
+ btag = $('<span></span>');
+ spoint.insertNode(btag[0]);
+ errors = this.model.updateWithWLML(btag, '<begin id="b'+id+'" />');
+ if(errors) {
+ mtag.remove();
+ messageCenter.addMessage('error', null, 'Błąd przy dodawaniu motywu :' + errors);
+ return false;
+ }
+
- elem = $('<span x-node="end" class="end"></span>');
- elem.attr('x-attr-qname-'+id, 'id');
- elem.attr('x-attr-value-'+id, 'e'+id);
- epoint.insertNode(elem[0]);
+ etag = $('<span></span>');
+ epoint.insertNode(etag[0]);
+ result = this.model.updateWithWLML(etag, '<end id="e'+id+'" />');
+ if(errors) {
+ btag.remove();
+ mtag.remove();
+ messageCenter.addMessage('error', null, 'Błąd przy dodawaniu motywu :' + errors);
+ return false;
+ }
}
- //selection.removeAllRanges();
+ selection.removeAllRanges();
},
selectTheme: function(themeId)
{
- var selection = document.getSelection();
+ var selection = window.getSelection();
// remove current selection
selection.removeAllRanges();
var range = document.createRange();
- var s = $('#m'+themeId)[0];
- var e = $('#e'+themeId)[0];
+ var s = $(".motyw[theme-class='"+themeId+"']")[0];
+ var e = $(".end[theme-class='"+themeId+"']")[0];
console.log('Selecting range:', themeId, range, s, e);
if(s && e) {
<!--
Dokument ten opisuje jednoznaczne przekształcenie WLML 0.1 -> XHTML.
-->
- <xsl:output method="xml" encoding="utf-8" indent="no" />
+ <xsl:output method="xml" encoding="utf-8" indent="no" omit-xml-declaration="yes" />
<xsl:template match="/">
<xsl:apply-templates select="chunk|utwor" />
<xsl:template match="begin">
<span>
<xsl:call-template name="standard-attributes" />
+ <xsl:attribute name="theme-class">
+ <xsl:value-of select="substring-after(@id, 'b')" />
+ </xsl:attribute>
</span>
</xsl:template>
<xsl:template match="motyw">
<span x-editable="true">
<xsl:call-template name="standard-attributes" />
+ <xsl:attribute name="theme-class">
+ <xsl:value-of select="substring-after(@id, 'm')" />
+ </xsl:attribute>
<xsl:call-template name="context-menu" />
<xsl:value-of select="." />
</span>
<xsl:template match="end">
<span>
- <xsl:call-template name="standard-attributes" />
+ <xsl:call-template name="standard-attributes" />
+ <xsl:attribute name="theme-class">
+ <xsl:value-of select="substring-after(@id, 'e')" />
+ </xsl:attribute>
</span>
</xsl:template>
</xsl:template>
<xsl:template match="*">
- <xsl:message terminate="no">
- Unmatched tag <xsl:value-of select="name()" />
- </xsl:message>
+ <error>Unknown tag: <xsl:value-of select="name()" /></error>
</xsl:template>
<xsl:template name="context-menu">
<span class="default-menu context-menu">
<span class="edit-button">Edit</span>
+ <span class="delete-button">Delete</span>
</span>
<span class="edit-menu context-menu">
- <span class="accept-button">OK</span>
- <span class="reject-button">Cancel</span>
+ <span class="accept-button">Accept</span>
+ <span class="reject-button">Close</span>
</span>
</xsl:template>