text: ﻿/*
   Copyright (c) 2003-2011, CKSource - Frederico Knabben. All rights reserved.
   For licensing, see LICENSE.html or http://ckeditor.com/license
   */
  
  /**
   * @file Justify commands.
   */
  
  (function() {
    function getState(editor, path) {
      var firstBlock = path.block || path.blockLimit;
  
      if (!firstBlock || firstBlock.getName() == 'body')
        return CKEDITOR.TRISTATE_OFF;
  
      return ( getAlignment(firstBlock, editor.config.useComputedState) == this.value ) ?
          CKEDITOR.TRISTATE_ON :
          CKEDITOR.TRISTATE_OFF;
    }
  
    function getAlignment(element, useComputedState) {
      useComputedState = useComputedState === undefined || useComputedState;
  
      var align;
      if (useComputedState)
        align = element.getComputedStyle('text-align');
      else {
        while (!element.hasAttribute || !( element.hasAttribute('align') || element.getStyle('text-align') )) {
          var parent = element.getParent();
          if (!parent)
            break;
          element = parent;
        }
        align = element.getStyle('text-align') || element.getAttribute('align') || '';
      }
  
      align && ( align = align.replace(/-moz-|-webkit-|start|auto/i, '') );
  
      !align && useComputedState && ( align = element.getComputedStyle('direction') == 'rtl' ? 'right' : 'left' );
  
      return align;
    }
  
    function onSelectionChange(evt) {
      if (evt.editor.readOnly)
        return;
  
      var command = evt.editor.getCommand(this.name);
      command.state = getState.call(this, evt.editor, evt.data.path);
      command.fire('state');
    }
  
    function justifyCommand(editor, name, value) {
      this.name = name;
      this.value = value;
  
      var classes = editor.config.justifyClasses;
      if (classes) {
        switch (value) {
          case 'left' :
            this.cssClassName = classes[0];
            break;
          case 'center' :
            this.cssClassName = classes[1];
            break;
          case 'right' :
            this.cssClassName = classes[2];
            break;
          case 'justify' :
            this.cssClassName = classes[3];
            break;
        }
  
        this.cssClassRegex = new RegExp('(?:^|\\s+)(?:' + classes.join('|') + ')(?=$|\\s)');
      }
    }
  
    function onDirChanged(e) {
      var editor = e.editor;
  
      var range = new CKEDITOR.dom.range(editor.document);
      range.setStartBefore(e.data.node);
      range.setEndAfter(e.data.node);
  
      var walker = new CKEDITOR.dom.walker(range),
          node;
  
      while (( node = walker.next() )) {
        if (node.type == CKEDITOR.NODE_ELEMENT) {
          // A child with the defined dir is to be ignored.
          if (!node.equals(e.data.node) && node.getDirection()) {
            range.setStartAfter(node);
            walker = new CKEDITOR.dom.walker(range);
            continue;
          }
  
          // Switch the alignment.
          var classes = editor.config.justifyClasses;
          if (classes) {
            // The left align class.
            if (node.hasClass(classes[ 0 ])) {
              node.removeClass(classes[ 0 ]);
              node.addClass(classes[ 2 ]);
            }
            // The right align class.
            else if (node.hasClass(classes[ 2 ])) {
              node.removeClass(classes[ 2 ]);
              node.addClass(classes[ 0 ]);
            }
          }
  
          // Always switch CSS margins.
          var style = 'text-align';
          var align = node.getStyle(style);
  
          if (align == 'left')
            node.setStyle(style, 'right');
          else if (align == 'right')
            node.setStyle(style, 'left');
        }
      }
    }
  
    justifyCommand.prototype = {
      exec : function(editor) {
        var selection = editor.getSelection(),
            enterMode = editor.config.enterMode;
  
        if (!selection)
          return;
  
        var bookmarks = selection.createBookmarks(),
            ranges = selection.getRanges(true);
  
        var cssClassName = this.cssClassName,
            iterator,
            block;
  
        var useComputedState = editor.config.useComputedState;
        useComputedState = useComputedState === undefined || useComputedState;
  
        for (var i = ranges.length - 1; i >= 0; i--) {
          iterator = ranges[ i ].createIterator();
          iterator.enlargeBr = enterMode != CKEDITOR.ENTER_BR;
  
          while (( block = iterator.getNextParagraph(enterMode == CKEDITOR.ENTER_P ? 'p' : 'div') )) {
            block.removeAttribute('align');
            block.removeStyle('text-align');
  
            // Remove any of the alignment classes from the className.
            var className = cssClassName && ( block.$.className =
                CKEDITOR.tools.ltrim(block.$.className.replace(this.cssClassRegex, '')) );
  
            var apply =
                ( this.state == CKEDITOR.TRISTATE_OFF ) &&
                    ( !useComputedState || ( getAlignment(block, true) != this.value ) );
  
            if (cssClassName) {
              // Append the desired class name.
              if (apply)
                block.addClass(cssClassName);
              else if (!className)
                block.removeAttribute('class');
            }
            else if (apply)
              block.setStyle('text-align', this.value);
          }
  
        }
  
        editor.focus();
        editor.forceNextSelectionCheck();
        selection.selectBookmarks(bookmarks);
      }
    };
  
    CKEDITOR.plugins.add('justify',
        {
          init : function(editor) {
            var left = new justifyCommand(editor, 'justifyleft', 'left'),
                center = new justifyCommand(editor, 'justifycenter', 'center'),
                right = new justifyCommand(editor, 'justifyright', 'right'),
                justify = new justifyCommand(editor, 'justifyblock', 'justify');
  
            editor.addCommand('justifyleft', left);
            editor.addCommand('justifycenter', center);
            editor.addCommand('justifyright', right);
            editor.addCommand('justifyblock', justify);
  
            editor.ui.addButton('JustifyLeft',
                {
                  label : editor.lang.justify.left,
                  command : 'justifyleft'
                });
            editor.ui.addButton('JustifyCenter',
                {
                  label : editor.lang.justify.center,
                  command : 'justifycenter'
                });
            editor.ui.addButton('JustifyRight',
                {
                  label : editor.lang.justify.right,
                  command : 'justifyright'
                });
            editor.ui.addButton('JustifyBlock',
                {
                  label : editor.lang.justify.block,
                  command : 'justifyblock'
                });
  
            editor.on('selectionChange', CKEDITOR.tools.bind(onSelectionChange, left));
            editor.on('selectionChange', CKEDITOR.tools.bind(onSelectionChange, right));
            editor.on('selectionChange', CKEDITOR.tools.bind(onSelectionChange, center));
            editor.on('selectionChange', CKEDITOR.tools.bind(onSelectionChange, justify));
            editor.on('dirChanged', onDirChanged);
          },
  
          requires : [ 'domiterator' ]
        });
  })();
  
  /**
   * List of classes to use for aligning the contents. If it's null, no classes will be used
   * and instead the corresponding CSS values will be used. The array should contain 4 members, in the following order: left, center, right, justify.
   * @name CKEDITOR.config.justifyClasses
   * @type Array
   * @default null
   * @example
   * // Use the classes 'AlignLeft', 'AlignCenter', 'AlignRight', 'AlignJustify'
   * config.justifyClasses = [ 'AlignLeft', 'AlignCenter', 'AlignRight', 'AlignJustify' ];
   */
  