$.fn.markItUp   F
last analyzed

Complexity

Conditions 14
Paths 64

Size

Total Lines 47
Code Lines 37

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 37
dl 0
loc 47
rs 3.6
c 0
b 0
f 0
cc 14
nc 64
nop 1

How to fix   Complexity   

Complexity

Complex classes like $.fn.markItUp 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
// markItUp! Universal MarkUp Engine, JQuery plugin
3
// v 1.1.x
4
// Dual licensed under the MIT and GPL licenses.
5
// ----------------------------------------------------------------------------
6
// Copyright (C) 2007-2010 Jay Salvat
7
// http://markitup.jaysalvat.com/
8
// ----------------------------------------------------------------------------
9
// Permission is hereby granted, free of charge, to any person obtaining a copy
10
// of this software and associated documentation files (the "Software"), to deal
11
// in the Software without restriction, including without limitation the rights
12
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
// copies of the Software, and to permit persons to whom the Software is
14
// furnished to do so, subject to the following conditions:
15
//
16
// The above copyright notice and this permission notice shall be included in
17
// all copies or substantial portions of the Software.
18
//
19
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25
// THE SOFTWARE.
26
// ----------------------------------------------------------------------------
27
(function($) {
28
	$.fn.markItUp = function(settings, extraSettings) {
29
		var options, ctrlKey, shiftKey, altKey;
30
		ctrlKey = shiftKey = altKey = false;
31
32
		options = {	id:						'',
33
					nameSpace:				'',
34
					root:					'',
35
					previewInWindow:		'', // 'width=800, height=600, resizable=yes, scrollbars=yes'
36
					previewAutoRefresh:		true,
37
					previewPosition:		'after',
38
					previewTemplatePath:	'~/templates/preview.html',
39
					previewParserPath:		'',
40
					previewParserVar:		'data',
41
					resizeHandle:			true,
42
					beforeInsert:			'',
43
					afterInsert:			'',
44
					onEnter:				{},
45
					onShiftEnter:			{},
46
					onCtrlEnter:			{},
47
					onTab:					{},
48
					markupSet:			[	{ /* set */ } ]
49
				};
50
		$.extend(options, settings, extraSettings);
51
52
		// compute markItUp! path
53
		if (!options.root) {
54
			$('script').each(function(a, tag) {
55
				miuScript = $(tag).get(0).src.match(/(.*)jquery\.markitup(\.pack)?\.js/);
0 ignored issues
show
Bug introduced by
The variable miuScript seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.miuScript.
Loading history...
56
				if (miuScript !== null) {
57
					options.root = miuScript[1];
58
				}
59
			});
60
		}
61
62
		return this.each(function() {
63
			var $$, textarea, levels, scrollPosition, caretPosition, caretOffset,
64
				clicked, hash, header, footer, previewWindow, template, iFrame, abort;
65
			$$ = $(this);
66
			textarea = this;
67
			levels = [];
68
			abort = false;
69
			scrollPosition = caretPosition = 0;
70
			caretOffset = -1;
71
72
			options.previewParserPath = localize(options.previewParserPath);
73
			options.previewTemplatePath = localize(options.previewTemplatePath);
74
75
			// apply the computed path to ~/
76
			function localize(data, inText) {
77
				if (inText) {
78
					return 	data.replace(/("|')~\//g, "$1"+options.root);
79
				}
80
				return 	data.replace(/^~\//, options.root);
81
			}
82
83
			// init and build editor
84
			function init() {
85
				id = ''; nameSpace = '';
0 ignored issues
show
Bug introduced by
The variable id seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.id.
Loading history...
Bug introduced by
The variable nameSpace seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.nameSpace.
Loading history...
86
				if (options.id) {
87
					id = 'id="'+options.id+'"';
88
				} else if ($$.attr("id")) {
89
					id = 'id="markItUp'+($$.attr("id").substr(0, 1).toUpperCase())+($$.attr("id").substr(1))+'"';
90
91
				}
92
				if (options.nameSpace) {
93
					nameSpace = 'class="'+options.nameSpace+'"';
94
				}
95
				$$.wrap('<div '+nameSpace+'></div>');
96
				$$.wrap('<div '+id+' class="markItUp"></div>');
97
				$$.wrap('<div class="markItUpContainer"></div>');
98
				$$.addClass("markItUpEditor");
99
100
				// add the header before the textarea
101
				header = $('<div class="markItUpHeader"></div>').insertBefore($$);
102
				$(dropMenus(options.markupSet)).appendTo(header);
103
104
				// add the footer after the textarea
105
				footer = $('<div class="markItUpFooter"></div>').insertAfter($$);
106
107
				// add the resize handle after textarea
108
				if (options.resizeHandle === true) {
109
					resizeHandle = $('<div class="markItUpResizeHandle"></div>')
0 ignored issues
show
Bug introduced by
The variable resizeHandle seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.resizeHandle.
Loading history...
110
						.insertAfter($$)
111
						.bind("mousedown", function(e) {
112
							var h = $$.height(), y = e.clientY, mouseMove, mouseUp;
113
							mouseMove = function(e) {
114
								$$.css("height", Math.max(20, e.clientY+h-y)+"px");
115
								return false;
116
							};
117
							mouseUp = function(e) {
0 ignored issues
show
Unused Code introduced by
The parameter e is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
118
								$("html").unbind("mousemove", mouseMove).unbind("mouseup", mouseUp);
119
								return false;
120
							};
121
							$("html").bind("mousemove", mouseMove).bind("mouseup", mouseUp);
122
					});
123
					footer.append(resizeHandle);
124
				}
125
126
				// listen key events
127
				$$.keydown(keyPressed).keyup(keyPressed);
128
129
				// bind an event to catch external calls
130
				$$.bind("insertion", function(e, settings) {
131
					if (settings.target !== false) {
132
						get();
133
					}
134
					if (textarea === $.markItUp.focused) {
135
						markup(settings);
136
					}
137
				});
138
139
				// remember the last focus
140
				$$.focus(function() {
141
					$.markItUp.focused = this;
142
				});
143
			}
144
145
			// recursively build header with dropMenus from markupset
146
			function dropMenus(markupSet) {
147
				var ul = $('<ul></ul>'), i = 0;
148
				$('li:hover > ul', ul).css('display', 'block');
149
				$.each(markupSet, function() {
150
					var button = this, t = '', title, li, j;
151
					title = (button.key) ? (button.name||'')+' [Ctrl+'+button.key+']' : (button.name||'');
152
					key   = (button.key) ? 'accesskey="'+button.key+'"' : '';
0 ignored issues
show
Bug introduced by
The variable key seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.key.
Loading history...
153
					if (button.separator) {
154
						li = $('<li class="markItUpSeparator">'+(button.separator||'')+'</li>').appendTo(ul);
0 ignored issues
show
Unused Code introduced by
The assignment to variable li seems to be never used. Consider removing it.
Loading history...
155
					} else {
156
						i++;
157
						for (j = levels.length -1; j >= 0; j--) {
158
							t += levels[j]+"-";
159
						}
160
						li = $('<li class="markItUpButton markItUpButton'+t+(i)+' '+(button.className||'')+'"><a href="" '+key+' title="'+title+'">'+(button.name||'')+'</a></li>')
161
						.bind("contextmenu", function() { // prevent contextmenu on mac and allow ctrl+click
162
							return false;
163
						}).click(function() {
164
							return false;
165
						}).bind("focusin", function(){
166
                            $$.focus();
167
						}).mousedown(function() {
168
							if (button.call) {
169
								eval(button.call)();
0 ignored issues
show
Security Performance introduced by
Calls to eval are slow and potentially dangerous, especially on untrusted code. Please consider whether there is another way to achieve your goal.
Loading history...
170
							}
171
							setTimeout(function() { markup(button) },1);
172
							return false;
173
						}).hover(function() {
174
								$('> ul', this).show();
175
								$(document).one('click', function() { // close dropmenu if click outside
176
										$('ul ul', header).hide();
177
									}
178
								);
179
							}, function() {
180
								$('> ul', this).hide();
181
							}
182
						).appendTo(ul);
183
						if (button.dropMenu) {
184
							levels.push(i);
185
							$(li).addClass('markItUpDropMenu').append(dropMenus(button.dropMenu));
186
						}
187
					}
188
				});
189
				levels.pop();
190
				return ul;
191
			}
192
193
			// markItUp! markups
194
			function magicMarkups(string) {
195
				if (string) {
196
					string = string.toString();
197
					string = string.replace(/\(\!\(([\s\S]*?)\)\!\)/g,
198
						function(x, a) {
199
							var b = a.split('|!|');
200
							if (altKey === true) {
201
								return (b[1] !== undefined) ? b[1] : b[0];
202
							} else {
0 ignored issues
show
Comprehensibility introduced by
else is not necessary here since all if branches return, consider removing it to reduce nesting and make code more readable.
Loading history...
203
								return (b[1] === undefined) ? "" : b[0];
204
							}
205
						}
206
					);
207
					// [![prompt]!], [![prompt:!:value]!]
208
					string = string.replace(/\[\!\[([\s\S]*?)\]\!\]/g,
209
						function(x, a) {
210
							var b = a.split(':!:');
211
							if (abort === true) {
212
								return false;
213
							}
214
							value = prompt(b[0], (b[1]) ? b[1] : '');
0 ignored issues
show
Debugging Code Best Practice introduced by
The prompt 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 value seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.value.
Loading history...
215
							if (value === null) {
216
								abort = true;
217
							}
218
							return value;
219
						}
220
					);
221
					return string;
222
				}
223
				return "";
224
			}
225
226
			// prepare action
227
			function prepare(action) {
228
				if ($.isFunction(action)) {
229
					action = action(hash);
230
				}
231
				return magicMarkups(action);
232
			}
233
234
			// build block to insert
235
			function build(string) {
236
				var openWith 	= prepare(clicked.openWith);
237
				var placeHolder = prepare(clicked.placeHolder);
238
				var replaceWith = prepare(clicked.replaceWith);
239
				var closeWith 	= prepare(clicked.closeWith);
240
				if (replaceWith !== "") {
241
					block = openWith + replaceWith + closeWith;
0 ignored issues
show
Bug introduced by
The variable block seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.block.
Loading history...
242
				} else if (selection === '' && placeHolder !== '') {
0 ignored issues
show
Bug introduced by
The variable selection seems to be never declared. If this is a global, consider adding a /** global: selection */ 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...
243
					block = openWith + placeHolder + closeWith;
244
				} else {
245
					string = string || selection;
0 ignored issues
show
Best Practice introduced by
If you intend to check if the variable selection is declared in the current environment, consider using typeof selection === "undefined" instead. This is safe if the variable is not actually declared.
Loading history...
246
					if (string.match(/ $/)) {
247
						block = openWith + string.replace(/ $/, '') + closeWith + ' ';
248
					} else {
249
						block = openWith + string + closeWith;
250
					}
251
				}
252
				return {	block:block,
253
							openWith:openWith,
254
							replaceWith:replaceWith,
255
							placeHolder:placeHolder,
256
							closeWith:closeWith
257
					};
258
			}
259
260
			// define markup to insert
261
			function markup(button) {
262
				var len, j, n, i;
263
				hash = clicked = button;
264
				get();
265
266
				$.extend(hash, {	line:"",
267
						 			root:options.root,
268
									textarea:textarea,
269
									selection:(selection||''),
0 ignored issues
show
Best Practice introduced by
If you intend to check if the variable selection is declared in the current environment, consider using typeof selection === "undefined" instead. This is safe if the variable is not actually declared.
Loading history...
270
									caretPosition:caretPosition,
271
									ctrlKey:ctrlKey,
272
									shiftKey:shiftKey,
273
									altKey:altKey
274
								}
275
							);
276
				// callbacks before insertion
277
				prepare(options.beforeInsert);
278
				prepare(clicked.beforeInsert);
279
				if (ctrlKey === true && shiftKey === true) {
280
					prepare(clicked.beforeMultiInsert);
281
				}
282
				$.extend(hash, { line:1 });
283
284
				if (ctrlKey === true && shiftKey === true) {
285
					lines = selection.split(/\r?\n/);
0 ignored issues
show
Bug introduced by
The variable selection seems to not be initialized for all possible execution paths.
Loading history...
Bug introduced by
The variable lines seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.lines.
Loading history...
286
					for (j = 0, n = lines.length, i = 0; i < n; i++) {
287
						if ($.trim(lines[i]) !== '') {
288
							$.extend(hash, { line:++j, selection:lines[i] } );
289
							lines[i] = build(lines[i]).block;
290
						} else {
291
							lines[i] = "";
292
						}
293
					}
294
					string = { block:lines.join('\n')};
0 ignored issues
show
Bug introduced by
The variable string seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.string.
Loading history...
295
					start = caretPosition;
0 ignored issues
show
Bug introduced by
The variable start seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.start.
Loading history...
296
					len = string.block.length + ((false) ? n-1 : 0);
297
				} else if (ctrlKey === true) {
298
					string = build(selection);
299
					start = caretPosition + string.openWith.length;
300
					len = string.block.length - string.openWith.length - string.closeWith.length;
301
					len = len - (string.block.match(/ $/) ? 1 : 0);
302
					len -= fixIeBug(string.block);
303
				} else if (shiftKey === true) {
304
					string = build(selection);
305
					start = caretPosition;
306
					len = string.block.length;
307
					len -= fixIeBug(string.block);
308
				} else {
309
					string = build(selection);
310
					start = caretPosition + string.block.length ;
311
					len = 0;
312
					start -= fixIeBug(string.block);
313
				}
314
				if ((selection === '' && string.replaceWith === '')) {
315
					caretOffset += fixOperaBug(string.block);
316
317
					start = caretPosition + string.openWith.length;
318
					len = string.block.length - string.openWith.length - string.closeWith.length;
319
320
					caretOffset = $$.val().substring(caretPosition,  $$.val().length).length;
321
					caretOffset -= fixOperaBug($$.val().substring(0, caretPosition));
322
				}
323
				$.extend(hash, { caretPosition:caretPosition, scrollPosition:scrollPosition } );
324
325
				if (string.block !== selection && abort === false) {
326
					insert(string.block);
327
					set(start, len);
328
				} else {
329
					caretOffset = -1;
330
				}
331
				get();
332
333
				$.extend(hash, { line:'', selection:selection });
334
335
				// callbacks after insertion
336
				if (ctrlKey === true && shiftKey === true) {
337
					prepare(clicked.afterMultiInsert);
338
				}
339
				prepare(clicked.afterInsert);
340
				prepare(options.afterInsert);
341
342
				// refresh preview if opened
343
				if (previewWindow && options.previewAutoRefresh) {
344
					refreshPreview();
345
				}
346
347
				// reinit keyevent
348
				shiftKey = altKey = ctrlKey = abort = false;
349
			}
350
351
			// Substract linefeed in Opera
352
			function fixOperaBug(string) {
353
				if (false) {
354
					return string.length - string.replace(/\n*/g, '').length;
355
				}
356
				return 0;
357
			}
358
			// Substract linefeed in IE
359
			function fixIeBug(string) {
360
				if (false) {
361
					return string.length - string.replace(/\r/g, '').length;
362
				}
363
				return 0;
364
			}
365
366
			// add markup
367
			function insert(block) {
368
				if (document.selection) {
369
					var newSelection = document.selection.createRange();
370
					newSelection.text = block;
371
				} else {
372
					textarea.value =  textarea.value.substring(0, caretPosition)  + block + textarea.value.substring(caretPosition + selection.length, textarea.value.length);
0 ignored issues
show
Bug introduced by
The variable selection seems to be never declared. If this is a global, consider adding a /** global: selection */ 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...
373
				}
374
			}
375
376
			// set a selection
377
			function set(start, len) {
378
				if (textarea.createTextRange){
379
					// quick fix to make it work on Opera 9.5
380
					if (len == 0) {
0 ignored issues
show
Best Practice introduced by
Comparing len to 0 using the == operator is not safe. Consider using === instead.
Loading history...
381
						return false;
382
					}
383
					range = textarea.createTextRange();
0 ignored issues
show
Bug introduced by
The variable range seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.range.
Loading history...
384
					range.collapse(true);
385
					range.moveStart('character', start);
386
					range.moveEnd('character', len);
387
					range.select();
388
				} else if (textarea.setSelectionRange ){
389
					textarea.setSelectionRange(start, start + len);
390
				}
391
				textarea.scrollTop = scrollPosition;
392
				textarea.focus();
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
393
			}
394
395
			// get the selection
396
			function get() {
397
				textarea.focus();
398
399
				scrollPosition = textarea.scrollTop;
400
				if (document.selection) {
401
					selection = document.selection;
0 ignored issues
show
Bug introduced by
The variable selection seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.selection.
Loading history...
402
					if (false) { // ie
403
						var range = selection.createRange();
404
						var stored_range = range.duplicate();
405
						stored_range.moveToElementText(textarea);
406
						stored_range.setEndPoint('EndToEnd', range);
407
						var s = stored_range.text.length - range.text.length;
408
409
						caretPosition = s - (textarea.value.substr(0, s).length - textarea.value.substr(0, s).replace(/\r/g, '').length);
410
						selection = range.text;
411
					} else { // opera
412
						caretPosition = textarea.selectionStart;
413
					}
414
				} else { // gecko & webkit
415
					caretPosition = textarea.selectionStart;
416
					selection = textarea.value.substring(caretPosition, textarea.selectionEnd);
417
				}
418
				return selection;
419
			}
420
421
			// open preview window
422
			function preview() {
0 ignored issues
show
introduced by
The function preview does not seem to be used and can be removed.
Loading history...
423
				if (!previewWindow || previewWindow.closed) {
424
					if (options.previewInWindow) {
425
						previewWindow = window.open('', 'preview', options.previewInWindow);
426
						$(window).unload(function() {
427
							previewWindow.close();
428
						});
429
					} else {
430
						iFrame = $('<iframe class="markItUpPreviewFrame"></iframe>');
431
						if (options.previewPosition == 'after') {
432
							iFrame.insertAfter(footer);
433
						} else {
434
							iFrame.insertBefore(header);
435
						}
436
						previewWindow = iFrame[iFrame.length - 1].contentWindow || frame[iFrame.length - 1];
0 ignored issues
show
Bug introduced by
The variable frame seems to be never declared. If this is a global, consider adding a /** global: frame */ 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...
437
					}
438
				} else if (altKey === true) {
439
					if (iFrame) {
440
						iFrame.remove();
441
					} else {
442
						previewWindow.close();
443
					}
444
					previewWindow = iFrame = false;
445
				}
446
				if (!options.previewAutoRefresh) {
447
					refreshPreview();
448
				}
449
				if (options.previewInWindow) {
450
					previewWindow.focus();
451
				}
452
			}
453
454
			// refresh Preview window
455
			function refreshPreview() {
456
 				renderPreview();
457
			}
458
459
			function renderPreview() {
460
				var phtml;
0 ignored issues
show
Unused Code introduced by
The variable phtml seems to be never used. Consider removing it.
Loading history...
461
				if (options.previewParserPath !== '') {
462
					$.ajax({
463
						type: 'POST',
464
						dataType: 'text',
465
						global: false,
466
						url: options.previewParserPath,
467
						data: options.previewParserVar+'='+encodeURIComponent($$.val()),
468
						success: function(data) {
469
							writeInPreview( localize(data, 1) );
470
						}
471
					});
472
				} else {
473
					if (!template) {
0 ignored issues
show
Bug introduced by
The variable template seems to be never initialized.
Loading history...
474
						$.ajax({
475
							url: options.previewTemplatePath,
476
							dataType: 'text',
477
							global: false,
478
							success: function(data) {
479
								writeInPreview( localize(data, 1).replace(/<!-- content -->/g, $$.val()) );
480
							}
481
						});
482
					}
483
				}
484
				return false;
485
			}
486
487
			function writeInPreview(data) {
488
				if (previewWindow.document) {
489
					try {
490
						sp = previewWindow.document.documentElement.scrollTop
0 ignored issues
show
Bug introduced by
The variable sp seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.sp.
Loading history...
491
					} catch(e) {
492
						sp = 0;
493
					}
494
					previewWindow.document.open();
495
					previewWindow.document.write(data);
496
					previewWindow.document.close();
497
					previewWindow.document.documentElement.scrollTop = sp;
498
				}
499
			}
500
501
			// set keys pressed
502
			function keyPressed(e) {
503
				shiftKey = e.shiftKey;
504
				altKey = e.altKey;
505
				ctrlKey = (!(e.altKey && e.ctrlKey)) ? e.ctrlKey : false;
506
507
				if (e.type === 'keydown') {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if e.type === "keydown" is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
508
					if (ctrlKey === true) {
509
						li = $("a[accesskey="+String.fromCharCode(e.keyCode)+"]", header).parent('li');
0 ignored issues
show
Bug introduced by
The variable li seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.li.
Loading history...
510
						if (li.length !== 0) {
511
							ctrlKey = false;
512
							setTimeout(function() {
513
								li.triggerHandler('mousedown');
514
							},1);
515
							return false;
516
						}
517
					}
518
					if (e.keyCode === 13 || e.keyCode === 10) { // Enter key
519
						if (ctrlKey === true) {  // Enter + Ctrl
520
							ctrlKey = false;
521
							markup(options.onCtrlEnter);
522
							return options.onCtrlEnter.keepDefault;
523
						} else if (shiftKey === true) { // Enter + Shift
524
							shiftKey = false;
525
							markup(options.onShiftEnter);
526
							return options.onShiftEnter.keepDefault;
527
						} else { // only Enter
528
							markup(options.onEnter);
529
							return options.onEnter.keepDefault;
530
						}
531
					}
532
					if (e.keyCode === 9) { // Tab key
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if e.keyCode === 9 is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
533
						if (shiftKey == true || ctrlKey == true || altKey == true) {
0 ignored issues
show
Best Practice introduced by
Comparing shiftKey to true using the == operator is not safe. Consider using === instead.
Loading history...
Best Practice introduced by
Comparing altKey to true using the == operator is not safe. Consider using === instead.
Loading history...
Best Practice introduced by
Comparing ctrlKey to true using the == operator is not safe. Consider using === instead.
Loading history...
534
							return false;
535
						}
536
						if (caretOffset !== -1) {
537
							get();
538
							caretOffset = $$.val().length - caretOffset;
539
							set(caretOffset, 0);
540
							caretOffset = -1;
541
							return false;
542
						} else {
0 ignored issues
show
Comprehensibility introduced by
else is not necessary here since all if branches return, consider removing it to reduce nesting and make code more readable.
Loading history...
543
							markup(options.onTab);
544
							return options.onTab.keepDefault;
545
						}
546
					}
547
				}
548
			}
549
550
			init();
551
		});
552
	};
553
554
	$.fn.markItUpRemove = function() {
555
		return this.each(function() {
556
				var $$ = $(this).unbind().removeClass('markItUpEditor');
557
				$$.parent('div').parent('div.markItUp').parent('div').replaceWith($$);
558
			}
559
		);
560
	};
561
562
	$.markItUp = function(settings) {
563
		var options = { target:false };
564
		$.extend(options, settings);
565
		if (options.target) {
566
			return $(options.target).each(function() {
567
				$(this).focus();
568
				$(this).trigger('insertion', [options]);
569
			});
570
		} else {
0 ignored issues
show
Comprehensibility introduced by
else is not necessary here since all if branches return, consider removing it to reduce nesting and make code more readable.
Loading history...
571
			$('textarea').trigger('insertion', [options]);
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
572
		}
573
	};
574
})(jQuery);
575