1 // Module that implements main WYSIWIG edit area
\r 
   4 'libs/underscore-min',
\r 
   5 './transformations', 
\r 
   7 'libs/text!./template.html'], function(_, transformations, wlxmlNode, template) {
\r 
  11 return function(sandbox) {
\r 
  14         node: $(_.template(template)()),
\r 
  16         shownAlready: false,
\r 
  20             this.node.find('#rng-module-documentCanvas-content').on('keyup', function() {
\r 
  22                 sandbox.publish('contentChanged');
\r 
  25             this.node.on('mouseover', '[wlxml-tag]', function(e) {
\r 
  26                 e.stopPropagation();
\r 
  27                 sandbox.publish('nodeHovered', new wlxmlNode.Node($(e.target)));
\r 
  29             this.node.on('mouseout', '[wlxml-tag]', function(e) {
\r 
  30                 e.stopPropagation();
\r 
  31                 sandbox.publish('nodeBlured', new wlxmlNode.Node($(e.target)));
\r 
  33             this.node.on('click', '[wlxml-tag]', function(e) {
\r 
  34                 e.stopPropagation();
\r 
  35                 console.log('clicked node type: '+e.target.nodeType);
\r 
  36                 view.selectNode(new wlxmlNode.Node($(e.target)));
\r 
  39             this.node.on('keyup', '#rng-module-documentCanvas-contentWrapper', function(e) {
\r 
  40                 var anchor = $(window.getSelection().anchorNode);
\r 
  41                 if(anchor[0].nodeType === Node.TEXT_NODE)
\r 
  42                     anchor = anchor.parent();
\r 
  43                 if(!anchor.is('[wlxml-tag]'))
\r 
  45                 view.selectNode(new wlxmlNode.Node(anchor));
\r 
  48             this.node.on('keydown', '#rng-module-documentCanvas-contentWrapper', function(e) {
\r 
  49                 if(e.which === 13) { 
\r 
  51                     view.insertNewNode(null, null);
\r 
  55             this.node.onShow = function() {
\r 
  56                 if(!view.shownAlready) {
\r 
  57                     view.shownAlready = true;
\r 
  58                     view.selectFirstNode();
\r 
  62             this.gridToggled = false;
\r 
  64         _createNode: function(wlxmlTag, wlxmlClass) {
\r 
  65             var toBlock = ['div', 'document', 'section', 'header'];
\r 
  66             var htmlTag = _.contains(toBlock, wlxmlTag) ? 'div' : 'span';
\r 
  67             var toret = $('<' + htmlTag + '>');
\r 
  68             toret.attr('wlxml-tag', wlxmlTag);
\r 
  70                 toret.attr('wlxml-class', wlxmlClass);
\r 
  71             toret.attr('id', 'xxxxxxxx-xxxx-xxxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {var r = Math.random()*16|0,v=c=='x'?r:r&0x3|0x8;return v.toString(16);}));
\r 
  74         insertNewNode: function(wlxmlTag, wlxmlClass) {
\r 
  75             //TODO: Insert inline
\r 
  76             var anchor = $(window.getSelection().anchorNode);
\r 
  77             var anchorOffset = window.getSelection().anchorOffset;
\r 
  78             if(anchor[0].nodeType === Node.TEXT_NODE)
\r 
  79                 anchor = anchor.parent();
\r 
  80             if(anchor.text() === '') {
\r 
  82                 anchor = anchor.parent();
\r 
  85             if(anchorOffset > 0 && anchorOffset < anchor.text().length) {
\r 
  86                 if(wlxmlTag === null && wlxmlClass === null) {
\r 
  87                     return this.splitWithNewNode(anchor);
\r 
  89                 return this.wrapSelectionWithNewNode(wlxmlTag, wlxmlClass);
\r 
  91             var newNode = this._createNode(wlxmlTag || anchor.attr('wlxml-tag'), wlxmlClass || anchor.attr('wlxml-class'));
\r 
  92             if(anchorOffset === 0)
\r 
  93                 anchor.before(newNode)
\r 
  95                 anchor.after(newNode);
\r 
  96             this.selectNode(new wlxmlNode.Node(newNode), {moveCarret: true});
\r 
  98             sandbox.publish('contentChanged');
\r 
 100         wrapSelectionWithNewNode: function(wlxmlTag, wlxmlClass) {
\r 
 101             var selection = window.getSelection();
\r 
 102             if(selection.anchorNode === selection.focusNode && selection.anchorNode.nodeType === Node.TEXT_NODE) {
\r 
 103                 var startOffset = selection.anchorOffset;
\r 
 104                 var endOffset = selection.focusOffset;
\r 
 105                 if(startOffset > endOffset) {
\r 
 106                     var tmp = startOffset;
\r 
 107                     startOffset = endOffset;
\r 
 110                 var node = selection.anchorNode;
\r 
 111                 var prefix = node.data.substr(0, startOffset);
\r 
 112                 var suffix = node.data.substr(endOffset);
\r 
 113                 var core = node.data.substr(startOffset, endOffset - startOffset);
\r 
 114                 var newNode = this._createNode(wlxmlTag, wlxmlClass);
\r 
 115                 newNode.text(core || 'test');
\r 
 116                 $(node).replaceWith(newNode);
\r 
 117                 newNode.before(prefix);
\r 
 118                 newNode.after(suffix);
\r 
 120                 this.selectNode(new wlxmlNode.Node(newNode), {moveCarret: true});
\r 
 122                 sandbox.publish('contentChanged');
\r 
 125         splitWithNewNode: function(node) {
\r 
 126             var selection = window.getSelection();
\r 
 127             if(selection.anchorNode === selection.focusNode && selection.anchorNode.nodeType === Node.TEXT_NODE) {
\r 
 128                 var startOffset = selection.anchorOffset;
\r 
 129                 var endOffset = selection.focusOffset;
\r 
 130                 if(startOffset > endOffset) {
\r 
 131                     var tmp = startOffset;
\r 
 132                     startOffset = endOffset;
\r 
 135                 var anchor = selection.anchorNode;
\r 
 136                 var prefix = anchor.data.substr(0, startOffset);
\r 
 137                 var suffix = anchor.data.substr(endOffset);
\r 
 138                 var prefixNode = this._createNode(node.attr('wlxml-tag'), node.attr('wlxml-class'));
\r 
 139                 var newNode = this._createNode(node.attr('wlxml-tag'), node.attr('wlxml-class'));
\r 
 140                 var suffixNode = this._createNode(node.attr('wlxml-tag'), node.attr('wlxml-class'));
\r 
 141                 prefixNode.text(prefix);
\r 
 142                 suffixNode.text(suffix);
\r 
 143                 node.replaceWith(newNode);
\r 
 144                 newNode.before(prefixNode);
\r 
 145                 newNode.after(suffixNode);
\r 
 147                 this.selectNode(new wlxmlNode.Node(newNode), {moveCarret: true});
\r 
 149                 sandbox.publish('contentChanged');
\r 
 152         setBody: function(HTMLTree) {
\r 
 153             this.node.find('#rng-module-documentCanvas-content').html(HTMLTree);
\r 
 155         getBody: function() {
\r 
 156             return this.node.find('#rng-module-documentCanvas-content').html();
\r 
 158         selectNode: function(wlxmlNode, options) {
\r 
 159             options = options || {};
\r 
 160             var nodeElement = this.getNodeElement(wlxmlNode)
\r 
 162             this.dimNode(wlxmlNode);
\r 
 164             this.node.find('.rng-module-documentCanvas-currentNode').removeClass('rng-module-documentCanvas-currentNode');
\r 
 165             nodeElement.addClass('rng-module-documentCanvas-currentNode');
\r 
 167             if(options.moveCarret) {
\r 
 168                 var range = document.createRange();
\r 
 169                 range.selectNodeContents(nodeElement[0]);
\r 
 170                 range.collapse(false);
\r 
 171                 var selection = document.getSelection();
\r 
 172                 selection.removeAllRanges()
\r 
 173                 selection.addRange(range);
\r 
 176             this.currentNode = wlxmlNode;
\r 
 177             sandbox.publish('nodeSelected', wlxmlNode);
\r 
 179         highlightNode: function(wlxmlNode) {
\r 
 180             var nodeElement = this.getNodeElement(wlxmlNode);
\r 
 181             if(!this.gridToggled) {
\r 
 182                 nodeElement.addClass('rng-common-hoveredNode');
\r 
 183                 var label = nodeElement.attr('wlxml-tag');
\r 
 184                 if(nodeElement.attr('wlxml-class'))
\r 
 185                     label += ' / ' + nodeElement.attr('wlxml-class');
\r 
 186                 var tag = $('<div>').addClass('rng-module-documentCanvas-hoveredNodeTag').text(label);
\r 
 187                 nodeElement.append(tag);
\r 
 190         dimNode: function(wlxmlNode) {
\r 
 191             var nodeElement = this.getNodeElement(wlxmlNode);
\r 
 192             if(!this.gridToggled) {
\r 
 193                 nodeElement.removeClass('rng-common-hoveredNode');
\r 
 194                 nodeElement.find('.rng-module-documentCanvas-hoveredNodeTag').remove();
\r 
 197         selectFirstNode: function() {
\r 
 198             var firstNodeWithText = this.node.find('[wlxml-tag]').filter(function() {
\r 
 199                 return $(this).clone().children().remove().end().text().trim() !== '';
\r 
 202             if(firstNodeWithText.length)
\r 
 203                 node = $(firstNodeWithText[0])
\r 
 205                 node = this.node.find('[wlxml-class|="p"]')
\r 
 207             this.selectNode(new wlxmlNode.Node(node), {moveCarret: true});
\r 
 209         toggleGrid: function(toggle) {
\r 
 210             this.node.find('[wlxml-tag]').toggleClass('rng-common-hoveredNode', toggle);
\r 
 211             this.gridToggled = toggle;
\r 
 213         getNodeElement: function(wlxmlNode) {
\r 
 214             return this.node.find('#'+wlxmlNode.id);
\r 
 222         start: function() { sandbox.publish('ready'); },
\r 
 223         getView: function() { return view.node; },
\r 
 224         setDocument: function(xml) {
\r 
 225             var transformed = transformations.fromXML.getDocumentDescription(xml);
\r 
 226             view.setBody(transformed.HTMLTree);
\r 
 227             sandbox.publish('documentSet');
\r 
 229         getDocument: function() {
\r 
 230             return transformations.toXML.getXML(view.getBody());
\r 
 232         modifyCurrentNode: function(attr, value) {
\r 
 233             if(view.currentNode) {
\r 
 234                 view.getNodeElement(view.currentNode).attr('wlxml-'+attr, value);
\r 
 235                 sandbox.publish('contentChanged');
\r 
 238         highlightNode: function(wlxmlNode) {
\r 
 239             view.highlightNode(wlxmlNode);
\r 
 241         dimNode: function(wlxmlNode) {
\r 
 242             view.dimNode(wlxmlNode);
\r 
 244         selectNode: function(wlxmlNode) {
\r 
 245             if(!wlxmlNode.is(view.currentNode))
\r 
 246                 view.selectNode(wlxmlNode, {moveCarret: true});
\r 
 248         toggleGrid: function(toggle) {
\r 
 249             view.toggleGrid(toggle);
\r 
 251         insertNewNode: function(wlxmlTag, wlxmlClass) {
\r 
 252             view.insertNewNode(wlxmlTag, wlxmlClass);
\r 
 254         wrapSelectionWithNewNode: function(wlxmlTag, wlxmlClass) {
\r 
 255             view.wrapSelectionWithNewNode(wlxmlTag, wlxmlClass);
\r