4 'modules/documentCanvas/canvas/utils'
 
   5 ], function($, _, utils) {
 
   8 /* global Node:false, document:false */
 
  10 // DocumentElement represents a text or an element node from WLXML document rendered inside Canvas
 
  11 var DocumentElement = function(wlxmlNode, canvas) {
 
  12     this.wlxmlNode = wlxmlNode;
 
  15     this.$element = this.createDOM();
 
  16     this.$element.data('canvas-element', this);
 
  19 $.extend(DocumentElement.prototype, {
 
  20     refreshPath: function() {
 
  21         this.parents().forEach(function(parent) {
 
  30         return $.contains(document.documentElement, this.dom()[0]);
 
  36         var parents = this.$element.parents('[document-node-element]');
 
  38             return this.canvas.getDocumentElement(parents[0]);
 
  45             parent = this.parent();
 
  48             parent = parent.parent();
 
  53     sameNode: function(other) {
 
  54         return other && (typeof other === typeof this) && other.dom()[0] === this.dom()[0];
 
  57     getPreviousTextElement: function(includeInvisible) {
 
  58         return this.getNearestTextElement('above', includeInvisible);
 
  61     getNextTextElement: function(includeInvisible) {
 
  62         return this.getNearestTextElement('below', includeInvisible);
 
  65     getNearestTextElement: function(direction, includeInvisible) {
 
  66         includeInvisible = includeInvisible !== undefined ? includeInvisible : false;
 
  67         var selector = '[document-text-element]' + (includeInvisible ? '' : ':visible');
 
  68         return this.canvas.getDocumentElement(utils.nearestInDocumentOrder(selector, direction, this.dom()[0]));
 
  72         //this.canvas.bus.trigger()
 
  79 // DocumentNodeElement represents an element node from WLXML document rendered inside Canvas
 
  80 var DocumentNodeElement = function(wlxmlNode, canvas) {
 
  81     DocumentElement.call(this, wlxmlNode, canvas);
 
  82     wlxmlNode.setData('canvasElement', this);
 
  83     this.init(this.$element);
 
  87 var manipulate = function(e, params, action) {
 
  89     if(params instanceof DocumentElement) {
 
  92         element = e.canvas.createElement(params);
 
  94     e.dom()[action](element.dom());
 
  99 DocumentNodeElement.prototype = Object.create(DocumentElement.prototype);
 
 102 $.extend(DocumentNodeElement.prototype, {
 
 103     defaultDisplayStyle: 'block',
 
 104     addWidget: function(widget) {
 
 105         this.$element.children('.canvas-widgets').append(widget.DOM ? widget.DOM : widget);
 
 107     clearWidgets: function() {
 
 108         this.$element.children('.canvas-widgets').empty();
 
 110     handle: function(event) {
 
 111         var method = 'on' + event.type[0].toUpperCase() + event.type.substr(1);
 
 116     createDOM: function() {
 
 117         var wrapper = $('<div>').attr('document-node-element', ''),
 
 118             widgetsContainer = $('<div>')
 
 119                 .addClass('canvas-widgets')
 
 120                 .attr('contenteditable', false),
 
 121             contentContainer = $('<div>')
 
 122                 .attr('document-element-content', '');
 
 124         wrapper.append(widgetsContainer, contentContainer);
 
 125         widgetsContainer.find('*').add(widgetsContainer).attr('tabindex', -1);
 
 128     _container: function() {
 
 129         return this.dom().children('[document-element-content]');
 
 132         var parents = this.parents();
 
 136             parents[0].refreshPath();
 
 140     before: function(params) {
 
 141         return manipulate(this, params, 'before');
 
 144     after: function(params) {
 
 145         return manipulate(this, params, 'after');
 
 148     toggleLabel: function(toggle) {
 
 149         var displayCss = toggle ? 'inline-block' : 'none';
 
 150         var label = this.dom().children('.canvas-widgets').find('.canvas-widget-label');
 
 151         label.css('display', displayCss);
 
 152         this.toggleHighlight(toggle);
 
 155     toggleHighlight: function(toggle) {
 
 156         this._container().toggleClass('highlighted-element', toggle);
 
 159     isBlock: function() {
 
 160         return this.dom().css('display') === 'block';
 
 163     displayAsBlock: function() {
 
 164         this.dom().css('display', 'block');
 
 165         this._container().css('display', 'block');
 
 167     displayInline: function() {
 
 168         this.dom().css('display', 'inline');
 
 169         this._container().css('display', 'inline');
 
 171     displayAs: function(what) {
 
 172         // [this.dom(), this._container()].forEach(e) {
 
 173         //     var isBlock = window.getComputedStyle(e).display === 'block';
 
 174         //     if(!isBlock && what === 'block') {
 
 175         //         e.css('display', what);
 
 176         //     } else if(isBlock && what === 'inline') {
 
 180         this.dom().css('display', what);
 
 181         this._container().css('display', what);
 
 186 // DocumentNodeElement represents a text node from WLXML document rendered inside Canvas
 
 187 var DocumentTextElement = function(wlxmlTextNode, canvas) {
 
 188     DocumentElement.call(this, wlxmlTextNode, canvas);
 
 191 $.extend(DocumentTextElement, {
 
 192     isContentContainer: function(htmlElement) {
 
 193         return htmlElement.nodeType === Node.TEXT_NODE && $(htmlElement).parent().is('[document-text-element]');
 
 197 DocumentTextElement.prototype = Object.create(DocumentElement.prototype);
 
 199 $.extend(DocumentTextElement.prototype, {
 
 200     createDOM: function() {
 
 202             .attr('document-text-element', '')
 
 203             .text(this.wlxmlNode.getText() || utils.unicode.ZWS);
 
 211     setText: function(text) {
 
 212         this.dom().contents()[0].data = text;
 
 214     getText: function(options) {
 
 215         options = _.extend({raw: false}, options || {});
 
 216         var toret = this.dom().text();
 
 218             toret = toret.replace(utils.unicode.ZWS, '');
 
 222     isEmpty: function() {
 
 223         // Having at least Zero Width Space is guaranteed be Content Observer
 
 224         return this.dom().contents()[0].data === utils.unicode.ZWS;
 
 226     after: function(params) {
 
 227         if(params instanceof DocumentTextElement || params.text) {
 
 231         if(params instanceof DocumentNodeElement) {
 
 234             element = this.canvas.createElement(params);
 
 236         this.dom().wrap('<div>');
 
 237         this.dom().parent().after(element.dom());
 
 242     before: function(params) {
 
 243         if(params instanceof DocumentTextElement || params.text) {
 
 247         if(params instanceof DocumentNodeElement) {
 
 250             element = this.canvas.createElement(params);
 
 252         this.dom().wrap('<div>');
 
 253         this.dom().parent().before(element.dom());
 
 259     toggleHighlight: function() {
 
 260         // do nothing for now
 
 262     children: function() {
 
 268 var SpanElement = function() {
 
 269     DocumentNodeElement.apply(this, Array.prototype.slice.call(arguments, 0));
 
 271 SpanElement.prototype = $.extend(Object.create(DocumentNodeElement.prototype), {
 
 272     defaultDisplayStyle: 'inline',
 
 274         if(this.containsBlock()) {
 
 275             this.displayAsBlock();
 
 277             this.displayInline();
 
 280     refresh: function() {
 
 291     DocumentElement: DocumentElement,
 
 292     DocumentNodeElement: DocumentNodeElement,
 
 293     DocumentTextElement: DocumentTextElement, //,
 
 294     factoryForTag: function(tagName) {
 
 295         return elements[tagName] || DocumentNodeElement;