Passed
Push — master ( 89a048...33966e )
by Alexey
04:58
created

JustifyCommand.exec   C

Complexity

Conditions 10
Paths 17

Size

Total Lines 49

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
nc 17
nop 1
dl 0
loc 49
rs 5.5471
c 0
b 0
f 0

How to fix   Complexity   

Complexity

Complex classes like JustifyCommand.exec often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
/**
2
 * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
3
 * For licensing, see LICENSE.md or http://ckeditor.com/license
4
 */
5
6
        /**
7
         * @fileOverview Justify commands.
8
         */
9
10
                (function () {
11
                  function getAlignment(element, useComputedState) {
12
                    useComputedState = useComputedState === undefined || useComputedState;
13
14
                    var align;
15
                    if (useComputedState)
16
                      align = element.getComputedStyle('text-align');
17
                    else {
18
                      while (!element.hasAttribute || !(element.hasAttribute('align') || element.getStyle('text-align'))) {
19
                        var parent = element.getParent();
20
                        if (!parent)
21
                          break;
22
                        element = parent;
23
                      }
24
                      align = element.getStyle('text-align') || element.getAttribute('align') || '';
25
                    }
26
27
                    // Sometimes computed values doesn't tell.
28
                    align && (align = align.replace(/(?:-(?:moz|webkit)-)?(?:start|auto)/i, ''));
29
30
                    !align && useComputedState && (align = element.getComputedStyle('direction') == 'rtl' ? 'right' : 'left');
31
32
                    return align;
33
                  }
34
35
                  function JustifyCommand(editor, name, value) {
36
                    this.editor = editor;
37
                    this.name = name;
38
                    this.value = value;
39
                    this.context = 'p';
40
41
                    var classes = editor.config.justifyClasses,
42
                            blockTag = editor.config.enterMode == CKEDITOR.ENTER_P ? 'p' : 'div';
43
44
                    if (classes) {
45
                      switch (value) {
46
                        case 'center':
47
                          this.cssClassName = classes[ 1 ];
48
                          break;
49
                        case 'right':
50
                          this.cssClassName = classes[ 2 ];
51
                          break;
52
                        case 'justify':
53
                          this.cssClassName = classes[ 3 ];
54
                          break;
55
                        case 'left':
56
                        default:
57
                          this.cssClassName = classes[ 0 ];
58
59
                      }
60
61
                      this.cssClassRegex = new RegExp('(?:^|\\s+)(?:' + classes.join('|') + ')(?=$|\\s)');
62
                      this.requiredContent = blockTag + '(' + this.cssClassName + ')';
63
                    } else {
64
                      this.requiredContent = blockTag + '{text-align}';
65
                    }
66
67
                    this.allowedContent = {
68
                      'caption div h1 h2 h3 h4 h5 h6 p pre td th li': {
69
                        // Do not add elements, but only text-align style if element is validated by other rule.
70
                        propertiesOnly: true,
71
                        styles: this.cssClassName ? null : 'text-align',
72
                        classes: this.cssClassName || null
73
                      }
74
                    };
75
76
                    // In enter mode BR we need to allow here for div, because when non other
77
                    // feature allows div justify is the only plugin that uses it.
78
                    if (editor.config.enterMode == CKEDITOR.ENTER_BR)
79
                      this.allowedContent.div = true;
80
                  }
81
82
                  function onDirChanged(e) {
83
                    var editor = e.editor;
84
85
                    var range = editor.createRange();
86
                    range.setStartBefore(e.data.node);
87
                    range.setEndAfter(e.data.node);
88
89
                    var walker = new CKEDITOR.dom.walker(range),
90
                            node;
91
92
                    while ((node = walker.next())) {
93
                      if (node.type == CKEDITOR.NODE_ELEMENT) {
94
                        // A child with the defined dir is to be ignored.
95
                        if (!node.equals(e.data.node) && node.getDirection()) {
96
                          range.setStartAfter(node);
97
                          walker = new CKEDITOR.dom.walker(range);
98
                          continue;
99
                        }
100
101
                        // Switch the alignment.
102
                        var classes = editor.config.justifyClasses;
103
                        if (classes) {
104
                          // The left align class.
105
                          if (node.hasClass(classes[ 0 ])) {
106
                            node.removeClass(classes[ 0 ]);
107
                            node.addClass(classes[ 2 ]);
108
                          }
109
                          // The right align class.
110
                          else if (node.hasClass(classes[ 2 ])) {
111
                            node.removeClass(classes[ 2 ]);
112
                            node.addClass(classes[ 0 ]);
113
                          }
114
                        }
115
116
                        // Always switch CSS margins.
117
                        var style = 'text-align';
118
                        var align = node.getStyle(style);
119
120
                        if (align == 'left')
121
                          node.setStyle(style, 'right');
122
                        else if (align == 'right')
123
                          node.setStyle(style, 'left');
124
                      }
125
                    }
126
                  }
127
128
                  JustifyCommand.prototype = {
129
                    exec: function (editor) {
130
                      var selection = editor.getSelection(),
131
                              enterMode = editor.config.enterMode;
132
133
                      if (!selection)
134
                        return;
135
136
                      var bookmarks = selection.createBookmarks(),
137
                              ranges = selection.getRanges();
138
139
                      var cssClassName = this.cssClassName,
140
                              iterator, block;
141
142
                      var useComputedState = editor.config.useComputedState;
143
                      useComputedState = useComputedState === undefined || useComputedState;
144
145
                      for (var i = ranges.length - 1; i >= 0; i--) {
146
                        iterator = ranges[ i ].createIterator();
147
                        iterator.enlargeBr = enterMode != CKEDITOR.ENTER_BR;
148
149
                        while ((block = iterator.getNextParagraph(enterMode == CKEDITOR.ENTER_P ? 'p' : 'div'))) {
150
                          if (block.isReadOnly())
151
                            continue;
152
153
                          block.removeAttribute('align');
154
                          block.removeStyle('text-align');
155
156
                          // Remove any of the alignment classes from the className.
157
                          var className = cssClassName && (block.$.className = CKEDITOR.tools.ltrim(block.$.className.replace(this.cssClassRegex, '')));
158
159
                          var apply = (this.state == CKEDITOR.TRISTATE_OFF) && (!useComputedState || (getAlignment(block, true) != this.value));
160
161
                          if (cssClassName) {
162
                            // Append the desired class name.
163
                            if (apply)
164
                              block.addClass(cssClassName);
165
                            else if (!className)
166
                              block.removeAttribute('class');
167
                          } else if (apply) {
168
                            block.setStyle('text-align', this.value);
169
                          }
170
                        }
171
172
                      }
173
174
                      editor.focus();
175
                      editor.forceNextSelectionCheck();
176
                      selection.selectBookmarks(bookmarks);
177
                    },
178
                    refresh: function (editor, path) {
179
                      var firstBlock = path.block || path.blockLimit;
180
181
                      this.setState(firstBlock.getName() != 'body' && getAlignment(firstBlock, this.editor.config.useComputedState) == this.value ? CKEDITOR.TRISTATE_ON : CKEDITOR.TRISTATE_OFF);
182
                    }
183
                  };
184
185
                  CKEDITOR.plugins.add('justify', {
186
                    // jscs:disable maximumLineLength
187
                    lang: 'af,ar,bg,bn,bs,ca,cs,cy,da,de,el,en,en-au,en-ca,en-gb,eo,es,et,eu,fa,fi,fo,fr,fr-ca,gl,gu,he,hi,hr,hu,id,is,it,ja,ka,km,ko,ku,lt,lv,mk,mn,ms,nb,nl,no,pl,pt,pt-br,ro,ru,si,sk,sl,sq,sr,sr-latn,sv,th,tr,tt,ug,uk,vi,zh,zh-cn', // %REMOVE_LINE_CORE%
188
                    // jscs:enable maximumLineLength
189
                    icons: 'justifyblock,justifycenter,justifyleft,justifyright', // %REMOVE_LINE_CORE%
190
                    hidpi: true, // %REMOVE_LINE_CORE%
191
                    init: function (editor) {
192
                      if (editor.blockless)
193
                        return;
194
195
                      var left = new JustifyCommand(editor, 'justifyleft', 'left'),
196
                              center = new JustifyCommand(editor, 'justifycenter', 'center'),
197
                              right = new JustifyCommand(editor, 'justifyright', 'right'),
198
                              justify = new JustifyCommand(editor, 'justifyblock', 'justify');
199
200
                      editor.addCommand('justifyleft', left);
201
                      editor.addCommand('justifycenter', center);
202
                      editor.addCommand('justifyright', right);
203
                      editor.addCommand('justifyblock', justify);
204
205
                      if (editor.ui.addButton) {
206
                        editor.ui.addButton('JustifyLeft', {
207
                          label: editor.lang.justify.left,
208
                          command: 'justifyleft',
209
                          toolbar: 'align,10'
210
                        });
211
                        editor.ui.addButton('JustifyCenter', {
212
                          label: editor.lang.justify.center,
213
                          command: 'justifycenter',
214
                          toolbar: 'align,20'
215
                        });
216
                        editor.ui.addButton('JustifyRight', {
217
                          label: editor.lang.justify.right,
218
                          command: 'justifyright',
219
                          toolbar: 'align,30'
220
                        });
221
                        editor.ui.addButton('JustifyBlock', {
222
                          label: editor.lang.justify.block,
223
                          command: 'justifyblock',
224
                          toolbar: 'align,40'
225
                        });
226
                      }
227
228
                      editor.on('dirChanged', onDirChanged);
229
                    }
230
                  });
231
                })();
232
233
        /**
234
         * List of classes to use for aligning the contents. If it's `null`, no classes will be used
235
         * and instead the corresponding CSS values will be used.
236
         *
237
         * The array should contain 4 members, in the following order: left, center, right, justify.
238
         *
239
         *		// Use the classes 'AlignLeft', 'AlignCenter', 'AlignRight', 'AlignJustify'
240
         *		config.justifyClasses = [ 'AlignLeft', 'AlignCenter', 'AlignRight', 'AlignJustify' ];
241
         *
242
         * @cfg {Array} [justifyClasses=null]
243
         * @member CKEDITOR.config
244
         */
245