Completed
Push — patch_1-1-4 ( 3f780f...826343 )
by Emanuele
25:17 queued 11:40
created

spellcheck.js ➔ spellCheck   F

Complexity

Conditions 17
Paths 84

Size

Total Lines 61

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 17
nc 84
nop 3
dl 0
loc 61
rs 1.8
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like spellcheck.js ➔ spellCheck 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
 * @name      ElkArte Forum
3
 * @copyright ElkArte Forum contributors
4
 * @license   BSD http://opensource.org/licenses/BSD-3-Clause
5
 *
6
 * This file contains code covered by:
7
 * copyright:	2011 Simple Machines (http://www.simplemachines.org)
8
 * license:		BSD, See included LICENSE.TXT for terms and conditions.
9
 *
10
 * @version 1.1
11
 */
12
13
/**
14
 * This file contains javascript associated with the spellchecking ((pspell)
15
 */
16
17
// These are variables the popup is going to want to access...
18
var spell_formname,
19
	spell_fieldname,
20
	spell_full,
21
	mispstr;
22
23
/**
24
 * Spell check the specified field in the specified form.
25
 *
26
 * @param {string|boolean} formName
27
 * @param {string} fieldName
28
 * @param {boolean} bFull
29
 */
30
function spellCheck(formName, fieldName, bFull)
31
{
32
	// Register the name of the editing form for future reference.
33
	spell_formname = formName;
34
	spell_fieldname = fieldName;
35
	spell_full = typeof(bFull) !== 'undefined' ? bFull : typeof($editor_data) !== 'undefined';
0 ignored issues
show
Bug introduced by
The variable $editor_data seems to be never declared. If this is a global, consider adding a /** global: $editor_data */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
36
37
	// This should match a word (most of the time).
38
	var regexpWordMatch = /(?:<[^>]+>)|(?:\[[^ ][^\]]*])|(?:&[^; ]+;)|(?:[^0-9\s\]\[{};:“"”\\|,<.>\/?`~!@#$%^&*()_+=]+)/g;
39
40
	// These characters can appear within words.
41
	var aWordCharacters = ['-', '\''];
42
43
	var aWords = [],
44
		aResult,
45
		sText = (spell_full) ? $editor_data[spell_fieldname].getText() : document.forms[spell_formname][spell_fieldname].value,
46
		bInCode = false,
47
		iOffset1,
48
		iOffset2;
49
50
	// Loop through all words.
51
	while ((aResult = regexpWordMatch.exec(sText)) && typeof (aResult) !== 'undefined')
52
	{
53
		iOffset1 = 0;
54
		iOffset2 = aResult[0].length - 1;
55
56
		// Strip the dashes and hyphens from the begin of the word.
57
		while (in_array(aResult[0].charAt(iOffset1), aWordCharacters) && iOffset1 < iOffset2)
58
			iOffset1++;
59
60
		// Strip the dashes and hyphens from the end of the word.
61
		while (in_array(aResult[0].charAt(iOffset2), aWordCharacters) && iOffset1 < iOffset2)
62
			iOffset2--;
63
64
		// I guess there's only dashes and hyphens in this word...
65
		if (iOffset1 === iOffset2)
66
			continue;
67
68
		// Ignore code blocks.
69
		if (aResult[0].substr(0, 5).toLowerCase() === '[code')
70
			bInCode = true;
71
		// Glad we're out of that code block!
72
		else if (bInCode && aResult[0].substr(0, 7).toLowerCase() === '[/code]')
73
			bInCode = false;
74
		// Now let's get to business.
75
		else if (!bInCode && !in_array(aResult[0].charAt(0), ['[', '<']) && aResult[0].toUpperCase() !== aResult[0])
76
			aWords[aWords.length] = aResult[0].substr(iOffset1, iOffset2 - iOffset1 + 1) + '|' + (iOffset1 + sText.substr(0, aResult.index).length) + '|' + (iOffset2 + sText.substr(0, aResult.index).length);
77
	}
78
79
	// Open the window...
80
	openSpellWin(640, 480);
81
82
	// Pass the data to a form...
83
	document.getElementById("spellstring").value = aWords.join('\n');
84
	document.getElementById("fulleditor").value = spell_full ? 'true' : 'false';
85
86
	// and go!
87
	document.getElementById("spell_form").submit();
88
89
	return true;
90
}
91
92
// Private functions -------------------------------
93
94
// Globals...
95
var wordindex = -1,
96
	offsetindex = 0,
97
	ignoredWords = [];
98
99
/**
100
 * A "misspelled word" object.
101
 *
102
 * @param {string} word
103
 * @param {type} start
104
 * @param {type} end
105
 * @param {type} suggestions
106
 */
107
function misp(word, start, end, suggestions)
108
{
109
	// The word, start index, end index, and array of suggestions.
110
	this.word = word;
111
	this.start = start;
112
	this.end = end;
113
	this.suggestions = suggestions;
114
}
115
116
/**
117
 * Replace the word in the misps array at the "wordindex" index.  The
118
 * misps array is generated by a PHP script after the string to be spell
119
 * checked is evaluated with pspell.
120
 */
121
function replaceWord()
122
{
123
	var strstart = "",
124
		strend;
125
126
	// If this isn't the beginning of the string then get all of the string
127
	// that is before the word we are replacing.
128
	if (misps[wordindex].start !== 0)
0 ignored issues
show
Bug introduced by
The variable misps seems to be never declared. If this is a global, consider adding a /** global: misps */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
129
		strstart = mispstr.slice(0, misps[wordindex].start + offsetindex);
130
131
	// Get the end of the string after the word we are replacing.
132
	strend = mispstr.slice(misps[wordindex].end + 1 + offsetindex);
133
134
	// Rebuild the string with the new word.
135
	mispstr = strstart + document.forms.spellingForm.changeto.value + strend;
136
137
	// Update offsetindex to compensate for replacing a word with a word
138
	// of a different length.
139
	offsetindex += document.forms.spellingForm.changeto.value.length - misps[wordindex].word.length;
140
141
	// Update the word so future replaceAll calls don't change it.
142
	misps[wordindex].word = document.forms.spellingForm.changeto.value;
143
144
	nextWord(false);
145
}
146
147
/**
148
 * Replaces all instances of currently selected word with contents chosen by user.
149
 * Note: currently only replaces words after highlighted word.  I think we can re-index
150
 * all words at replacement or ignore time to have it wrap to the beginning if we want to.
151
 */
152
function replaceAll()
153
{
154
	var strend,
155
		idx,
156
		origword,
157
		localoffsetindex = offsetindex;
158
159
	origword = misps[wordindex].word;
0 ignored issues
show
Bug introduced by
The variable misps seems to be never declared. If this is a global, consider adding a /** global: misps */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
160
161
	// Re-index everything past the current word.
162
	for (idx = wordindex; idx < misps.length; idx++)
163
	{
164
		misps[idx].start += localoffsetindex;
165
		misps[idx].end += localoffsetindex;
166
	}
167
168
	localoffsetindex = 0;
169
170
	for (idx = 0; idx < misps.length; idx++)
171
	{
172
		if (misps[idx].word === origword)
173
		{
174
			var strstart = "";
175
			if (misps[idx].start !== 0)
176
				strstart = mispstr.slice(0, misps[idx].start + localoffsetindex);
177
178
			// Get the end of the string after the word we are replacing.
179
			strend = mispstr.slice(misps[idx].end + 1 + localoffsetindex);
180
181
			// Rebuild the string with the new word.
182
			mispstr = strstart + document.forms.spellingForm.changeto.value + strend;
183
184
			// Update offsetindex to compensate for replacing a word with a word
185
			// of a different length.
186
			localoffsetindex += document.forms.spellingForm.changeto.value.length - misps[idx].word.length;
187
		}
188
189
		// We have to re-index everything after replacements.
190
		misps[idx].start += localoffsetindex;
191
		misps[idx].end += localoffsetindex;
192
	}
193
194
	// Add the word to the ignore array.
195
	ignoredWords[origword] = true;
196
197
	// Reset offsetindex since we re-indexed.
198
	offsetindex = 0;
199
200
	nextWord(false);
201
}
202
203
/**
204
 * Highlight the word that was selected using the nextWord function.
205
 */
206
function highlightWord()
207
{
208
	var strstart = "",
209
		strend;
210
211
	// If this isn't the beginning of the string then get all of the string
212
	// that is before the word we are replacing.
213
	if (misps[wordindex].start !== 0)
0 ignored issues
show
Bug introduced by
The variable misps seems to be never declared. If this is a global, consider adding a /** global: misps */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
214
		strstart = mispstr.slice(0, misps[wordindex].start + offsetindex);
215
216
	// Get the end of the string after the word we are replacing.
217
	strend = mispstr.slice(misps[wordindex].end + 1 + offsetindex);
218
219
	// Rebuild the string with a span wrapped around the misspelled word
220
	// so we can highlight it in the div the user is viewing the string in.
221
	var divptr, newValue;
222
	divptr = document.getElementById("spellview");
223
224
	newValue = htmlspecialchars(strstart) + '<span class="highlight" id="h1">' + misps[wordindex].word + '</span>' + htmlspecialchars(strend);
225
	divptr.innerHTML = newValue.replace(/_\|_/g, '<br />');
226
227
	// We could use scrollIntoView, but it's just not that great anyway.
228
	var myElement = document.getElementById('h1'),
229
		topPos = myElement.offsetTop;
230
231
	document.getElementById('spellview').scrollTop = topPos - 32;
232
}
233
234
/**
235
 * Display the next misspelled word to the user and populate the suggested spellings box.
236
 *
237
 * @param {string|boolean} ignoreall
238
 */
239
function nextWord(ignoreall)
240
{
241
	// Push ignored word onto ignoredWords array.
242
	if (ignoreall)
243
		ignoredWords[misps[wordindex].word] = true;
0 ignored issues
show
Bug introduced by
The variable misps seems to be never declared. If this is a global, consider adding a /** global: misps */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
244
245
	// Update the index of all words we have processed...
246
	// This must be done to accommodate the replaceAll function.
247
	if (wordindex >= 0)
248
	{
249
		misps[wordindex].start += offsetindex;
250
		misps[wordindex].end += offsetindex;
251
	}
252
253
	// Increment the counter for the array of misspelled words.
254
	wordindex++;
255
256
	// Draw it and quit if there are no more misspelled words to evaluate.
257
	if (misps.length <= wordindex)
258
	{
259
		var divptr;
260
		divptr = document.getElementById("spellview");
261
		divptr.innerHTML = htmlspecialchars(mispstr).replace(/_\|_/g, "<br />");
262
263
		while (document.forms.spellingForm.suggestions.options.length > 0)
264
			document.forms.spellingForm.suggestions.options[0] = null;
265
266
		alert(txt['done']);
0 ignored issues
show
Debugging Code Best Practice introduced by
The alert UI element is often considered obtrusive and is generally only used as a temporary measure. Consider replacing it with another UI element.
Loading history...
Bug introduced by
The variable txt seems to be never declared. If this is a global, consider adding a /** global: txt */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
Coding Style introduced by
['done'] could be written in dot notation.

You can rewrite this statement in dot notation:

var obj = { };
obj['foo'] = 'bar'; // Bad
obj.foo = 'bar'; // Good
Loading history...
267
		document.forms.spellingForm.change.disabled = true;
268
		document.forms.spellingForm.changeall.disabled = true;
269
		document.forms.spellingForm.ignore.disabled = true;
270
		document.forms.spellingForm.ignoreall.disabled = true;
271
272
		// Put line feeds back...
273
		mispstr = mispstr.replace(/_\|_/g, "\n");
274
275
		// Get a handle to the field we need to re-populate.
276
		if (spell_full)
277
			window.opener.spellCheckSetText(mispstr, spell_fieldname);
278
		else
279
		{
280
			window.opener.document.forms[spell_formname][spell_fieldname].value = mispstr;
281
			window.opener.document.forms[spell_formname][spell_fieldname].focus();
282
		}
283
284
		window.close();
285
		return true;
286
	}
287
288
	// Check to see if word is supposed to be ignored.
289
	if (typeof (ignoredWords[misps[wordindex].word]) !== "undefined")
290
	{
291
		nextWord(false);
292
		return false;
293
	}
294
295
	// Clear out the suggestions box!
296
	while (document.forms.spellingForm.suggestions.options.length > 0)
297
		document.forms.spellingForm.suggestions.options[0] = null;
298
299
	// Re-populate the suggestions box if there are any suggested spellings for the word.
300
	if (misps[wordindex].suggestions.length)
301
	{
302
		for (var sugidx = 0; sugidx < misps[wordindex].suggestions.length; sugidx++)
303
		{
304
			var newopt = new Option(misps[wordindex].suggestions[sugidx], misps[wordindex].suggestions[sugidx]);
0 ignored issues
show
Bug introduced by
The variable Option seems to be never declared. If this is a global, consider adding a /** global: Option */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
305
			document.forms.spellingForm.suggestions.options[sugidx] = newopt;
306
307
			if (sugidx === 0)
308
			{
309
				newopt.selected = true;
310
				document.forms.spellingForm.changeto.value = newopt.value;
311
				document.forms.spellingForm.changeto.select();
312
			}
313
		}
314
	}
315
316
	if (document.forms.spellingForm.suggestions.options.length === 0)
317
		document.forms.spellingForm.changeto.value = "";
318
319
	highlightWord();
320
321
	return false;
322
}
323
324
/**
325
 * Convert characters to HTML equivalents
326
 *
327
 * @param {string} thetext the text from the form that we will check
328
 */
329
function htmlspecialchars(thetext)
330
{
331
	thetext = thetext
332
		.replace(/</g, "&lt;")
333
		.replace(/>/g, "&gt;")
334
		.replace(/\n/g, "<br />")
335
		.replace(/  /g, "&nbsp; ");
336
337
	return thetext;
338
}
339
340
/**
341
 * Open a new window
342
 *
343
 * @param {int} width
344
 * @param {int} height
345
 */
346
function openSpellWin(width, height)
347
{
348
	window.open("", "spellWindow", "toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=yes,resizable=no,width=" + width + ",height=" + height);
349
}
350
351
/**
352
 * get the sceditor text
353
 *
354
 * @param {string} editorID
355
 */
356
function spellCheckGetText(editorID)
357
{
358
	return $editor_data[editorID].getText();
0 ignored issues
show
Bug introduced by
The variable $editor_data seems to be never declared. If this is a global, consider adding a /** global: $editor_data */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
359
}
360
361
/**
362
 * set the sceditor text
363
 *
364
 * @param {string} text
365
 * @param {string} editorID
366
 */
367
function spellCheckSetText(text, editorID)
368
{
369
	$editor_data[editorID].InsertText(text, true);
0 ignored issues
show
Bug introduced by
The variable $editor_data seems to be never declared. If this is a global, consider adding a /** global: $editor_data */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
370
371
	if (!$editor_data[editorID].inSourceMode)
372
		$editor_data[editorID].toggleSourceMode();
373
}
374
375
/**
376
 * Used to enable the spell check on the editor box, switch to text mode so the
377
 * spell check works
378
 */
379
function spellCheckStart()
380
{
381
	if (!spellCheck)
382
		return false;
383
384
	$editor_data[post_box_name].storeLastState();
0 ignored issues
show
Bug introduced by
The variable $editor_data seems to be never declared. If this is a global, consider adding a /** global: $editor_data */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
Bug introduced by
The variable post_box_name seems to be never declared. If this is a global, consider adding a /** global: post_box_name */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
385
386
	// If we're in HTML mode we need to get the non-HTML text.
387
	$editor_data[post_box_name].setTextMode();
388
389
	spellCheck(false, post_box_name, true);
390
391
	return true;
392
}