"use strict";
String.prototype.hashCode = function() {
var hash = 0, i = 0, l = this.length, c;
if( l > 0 ) {
while( i < l ) {
c = this.charCodeAt(i);
hash = ((hash<<5)-hash)+c;
hash |= 0;
i++;
}
}
return hash;
};
function getURLParameter( name ) {
return decodeURIComponent(
(new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)')
.exec(location.search)||[undefined,''])[1].replace(/\+/g, '%20')
)||'';
}
(function($, window, undefined) {
$.Editor = function( element, options ) {
var _this = this,
$this = $(element),
settings = $.extend( {}, $.Editor.defaults, options ),
dHash = $('ol').text().hashCode();
this.getCaretNode = function() {
var range, sel, container;
if (document.selection && document.selection.createRange) {
range = document.selection.createRange();
return range.parentElement();
}
if( window.getSelection ) {
sel = window.getSelection();
if( sel.getRangeAt ) {
if( sel.rangeCount > 0 ) {
range = sel.getRangeAt(0);
}
}
else {
range = document.createRange();
range.setStart(sel.anchorNode, sel.anchorOffset);
range.setEnd(sel.focusNode, sel.focusOffset);
if( range.collapsed !== sel.isCollapsed ) {
range.setStart(sel.focusNode, sel.focusOffset);
range.setEnd(sel.anchorNode, sel.anchorOffset);
}
}
if( range ) {
container = range.commonAncestorContainer;
return container.nodeType === 3 ? container.parentNode : container;
}
}
};
this.getCaretPosition = function( node ) {
node = node || _this.getCaretNode();
var caretOffset = 0,
doc = node.ownerDocument || node.document,
win = doc.defaultView || doc.parentWindow,
sel = doc.selection,
range,
preCaretRange;
if( typeof win.getSelection !== 'undefined' ) {
range = win.getSelection().getRangeAt(0);
preCaretRange = range.cloneRange();
preCaretRange.selectNodeContents(node);
preCaretRange.setEnd(range.endContainer, range.endOffset);
caretOffset = preCaretRange.toString().length;
}
else if( sel && sel.type !== 'Control' ) {
range = sel.createRange();
preCaretRange = doc.body.createTextRange();
preCaretRange.moveToElementText(node);
preCaretRange.setEndPoint('EndToEnd', range);
caretOffset = preCaretRange.text.length;
}
return caretOffset;
};
this.setCaretPositionEnd = function( node ) {
node = node || _this.getCaretNode();
var range, selection;
if( document.createRange ) {
range = document.createRange();
range.selectNodeContents(node);
range.collapse(false);
selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
}
else if( document.selection ) {
range = document.body.createTextRange();
range.moveToElementText(node);
range.collapse(false);
range.select();
}
};
this.normalize = function() {
var list = '<ol><li></li></ol>',
$node;
$('p,div').replaceWith( list );
$node = $('ol:gt(0)').remove().children('li').appendTo('ol:eq(0)');
if( $('ol').length === 0 ) {
$(document.body).prepend( list );
}
$('ol').nextAll().remove();
$('ol').prevAll().remove();
if( $('ol').children().length === 0 ) {
$node = $('<li></li>');
$('ol').append( $node );
}
if( $node.is( 'li' ) ) {
_this.setCaretPositionEnd( $node[0] );
}
$('li:empty').append( '\u200B' );
};
this.doNormalization = function() {
setTimeout( function() { _this.normalize(); }, 32 );
};
this.getStyle = function( n, p ) {
return n.currentStyle ?
n.currentStyle[p] : (
document.defaultView.getComputedStyle(n, null) ?
document.defaultView.getComputedStyle(n, null).getPropertyValue(p) :
""
);
};
this.toText = function( node ) {
var result = '',
i = 0,
j = node.childNodes.length,
d;
if( node.nodeType === 3 ) {
result = node.nodeValue.replace( /\s+/g, ' ' );
result = result.replace( /[\u200b]*/g, '' );
}
else {
while( i < j ) {
result += _this.toText( node.childNodes[i] );
i++;
}
d = _this.getStyle( node, 'display' );
if( node.tagName === 'BR' || node.tagName === 'HR' ||
d.match( /^block/ ) || d.match( /list/ ) || d.match( /row/ ) ) {
result += '\n';
}
}
return result;
};
this.paste = function() {
var t = _this.toText( document.body );
t = t.replace( /^\s*[\r\n]/gm, '' );
t = t.replace( /(\.) +/g, '$1\n' );
t = t.replace( /^\s\s*/gm, '' ).replace( /\s\s*$/gm, '' );
t = t.replace( /^\d+[\.\)]\s?([^\d])/gm, '$1' );
t = t.replace( /(.+)[\r\n]*/g, '<li>$1</li>\n' );
if( t.length === 0 ) {
t = '<li></li>';
}
$this.html( '<ol>' + t + '</ol>' );
};
this.initPasteHooks = function() {
$this.on( 'paste', function( e ) {
setTimeout( function() { _this.paste(); }, 64 );
});
};
this.initKeyboardHooks = function() {
$this.on( 'keydown', function( e ) {
var code = e.keyCode || e.which,
result = true,
$node = $(_this.getCaretNode());
if( code === 16 || code === 17 ) {
return result;
}
if( $node.is( 'html' ) || $node.is( 'body' ) ) {
_this.setCaretPositionEnd( $('li').first()[0] );
}
switch( code ) {
case 8:
case 46:
_this.doNormalization();
break;
case 116:
_this.save();
break;
case 13:
result = e.shiftKey ? false : _this.doNormalization();
break;
}
_this.maxItemLength();
return result;
});
};
this.initCursorPosition = function() {
var $node = $('li:first');
if( $node ) {
_this.setCaretPositionEnd( $node[0] );
$node.focus();
}
};
this.initTimerHooks = function() {
setInterval(
function() { _this.save(); },
settings.saveInterval * 1000
);
setInterval(
function() { _this.maxItemLength(); },
settings.maxItemLengthInterval * 1000
);
window.onbeforeunload = function() {
_this.save();
}
$this.on( 'focusout', function() {
_this.save();
});
};
this.hashText = function() {
return $(document.body).text().hashCode();
};
this.isDirty = function() {
return _this.hashText() !== _this.dHash;
};
this.clean = function() {
_this.dHash = _this.hashText();
};
this.save = function() {
if( _this.isDirty() ) {
_this.clean();
var s = $.trim( _this.toText( $('ol')[0] ) );
if( s.length > 1 ) {
$.post( settings.postPage, {
command: 'instruction-accept',
instructions_group_id: getURLParameter( 'id' ),
steps: s
});
}
}
};
this.maxItemLength = function() {
$( 'li' ).each( function() {
var l = $(this).text().length;
if( l > settings.maxItemLength ) {
$(this).addClass( 'maxLength' );
}
else {
$(this).removeClass();
}
});
};
this.maxItems = function() {};
this.itemListSplit = function() {};
this.initialize = function( element, options ) {
this.initKeyboardHooks();
this.initPasteHooks();
this.initTimerHooks();
this.initCursorPosition();
};
this.initialize( element, options );
};
$.fn.Editor = function( options ) {
return this.each( function() {
var editor = new $.Editor( this, options );
});
};
$.Editor.defaults = {
maxItemLength: 200,
maxItemLengthInterval: 0.5,
maxItems: 50,
saveInterval: 10,
postPage: 'index.php'
};
}(jQuery, window));
$(document).ready(function() {
$(document.body).Editor();
});