117
app/assets/javascripts/live-coder/editor.js.erb
Normal file
117
app/assets/javascripts/live-coder/editor.js.erb
Normal file
@ -0,0 +1,117 @@
|
||||
function updateResults(elem) {
|
||||
if ($(elem).length ===0){return false;}
|
||||
|
||||
var resultsContainer = $(elem).find('[data-id="results"]')[0];
|
||||
var codeHtml = $(elem).find('.code-html')[0].value.trim();
|
||||
var codeCss = $(elem).find('.code-css')[0].value.trim();
|
||||
var codeJs = $(elem).find('.code-js')[0].value.trim();
|
||||
|
||||
resultsContainer.innerHTML = "";
|
||||
var iDoc = document.createElement('html');
|
||||
var iHead = document.createElement('head');
|
||||
var iBody = document.createElement('body');
|
||||
|
||||
var codeFrame = document.createElement('iframe');
|
||||
codeFrame.setAttribute("width", "100%");
|
||||
codeFrame.setAttribute("height", "100%");
|
||||
resultsContainer.appendChild(codeFrame);
|
||||
|
||||
var jqueryNode = document.createElement("script");
|
||||
jqueryNode.setAttribute("type", "text/javascript");
|
||||
jqueryNode.setAttribute("src", "<%= "//#{ENV['full_app_url']}#{javascript_path "jquery"}" %>");
|
||||
iHead.appendChild(jqueryNode);
|
||||
|
||||
var codeStyle = document.createElement("style");
|
||||
codeStyle.setAttribute("type", "text/css");
|
||||
var rulesNode = document.createTextNode(codeCss);
|
||||
codeStyle.appendChild(rulesNode);
|
||||
iHead.appendChild(codeStyle);
|
||||
|
||||
iDoc.appendChild(iHead);
|
||||
iBody.innerHTML = codeHtml;
|
||||
iDoc.appendChild(iBody);
|
||||
|
||||
var codeScript = document.createElement("script");
|
||||
codeScript.setAttribute("type", "text/javascript");
|
||||
var scriptNode = document.createTextNode("setTimeout(function(){ " + codeJs + "}, 800);");
|
||||
codeScript.appendChild(scriptNode);
|
||||
iDoc.appendChild(codeScript);
|
||||
|
||||
codeFrame.contentWindow.document.open();
|
||||
codeFrame.contentWindow.document.appendChild(iDoc);
|
||||
codeFrame.contentWindow.document.close();
|
||||
}
|
||||
|
||||
function indentSelection(e){
|
||||
if(e.keyCode === 9){
|
||||
e.preventDefault();
|
||||
|
||||
var indent = " ";
|
||||
var cursor = e.target.selectionStart;
|
||||
var val = e.target.value;
|
||||
var valStart = val.substring(0, e.target.selectionStart);
|
||||
var valEnd = val.substring(e.target.selectionEnd, val.length);
|
||||
var selected = val.substring(e.target.selectionStart, e.target.selectionEnd);
|
||||
|
||||
var resetCursor = function(start, end){
|
||||
e.target.selectionStart = start;
|
||||
e.target.selectionEnd = end;
|
||||
};
|
||||
|
||||
var indented;
|
||||
if(e.shiftKey){ //de-indent
|
||||
if(selected.length > 0 && (/\n/.test(selected))){ //multi line
|
||||
indented = selected.split(/\n/).map(function(line){
|
||||
if(line.length > 0 && line.substring(0, indent.length) === indent){
|
||||
line = line.substring(indent.length, line.length);
|
||||
}
|
||||
return line;
|
||||
}).join("\n");
|
||||
e.target.value = valStart + indented + val.substring(e.target.selectionEnd, val.length);
|
||||
resetCursor(cursor, cursor + indented.length);
|
||||
} else {
|
||||
if(valStart.substring(valStart.length - indent.length) === indent){
|
||||
e.target.value = valStart.substring(0, valStart.length - indent.length) + valEnd;
|
||||
resetCursor(cursor, cursor - indent.length);
|
||||
} else if(valEnd.substring(0, indent.length) === indent) {
|
||||
e.target.value = valStart + valEnd.substring(indent.length, valEnd.length);
|
||||
resetCursor(cursor, cursor);
|
||||
}
|
||||
}
|
||||
} else { //indent
|
||||
if(selected.length > 0 && (/\n/.test(selected))){ //multi line
|
||||
indented = selected.split(/\n/).map(function(line){
|
||||
if(line.length > 0){ line = indent + line; }
|
||||
return line;
|
||||
}).join("\n");
|
||||
e.target.value = valStart + indented + val.substring(e.target.selectionEnd, val.length);
|
||||
resetCursor(cursor, cursor + indented.length);
|
||||
} else {
|
||||
e.target.value = valStart + indent + selected + valEnd;
|
||||
resetCursor(cursor + indent.length, cursor + indent.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var timer = 0;
|
||||
$(function(){
|
||||
// wait a half second before updating results
|
||||
// restart the timer if they resume typing
|
||||
$('html').on('keyup', '.code-input textarea', function(){
|
||||
var elem = $(this).closest("[data-id=live-coder-answer]");
|
||||
if (timer) { clearTimeout(timer); }
|
||||
timer = setTimeout(updateResults(elem), 500);
|
||||
});
|
||||
|
||||
$("[data-id=live-coder-answer]").each(function(){
|
||||
updateResults(this);
|
||||
});
|
||||
|
||||
$("html").on('keydown', "textarea[data-id^=code-]", function(e){
|
||||
indentSelection(e);
|
||||
});
|
||||
|
||||
$(".code-input textarea").linedtextarea();
|
||||
});
|
114
app/assets/javascripts/live-coder/linedtextarea.js
Normal file
114
app/assets/javascripts/live-coder/linedtextarea.js
Normal file
@ -0,0 +1,114 @@
|
||||
/**
|
||||
* NOTE: MARK MOSER EDITED COPY. DO NOT USE BOWER.
|
||||
*
|
||||
* jQuery Lined Textarea Plugin
|
||||
* http://alan.blog-city.com/jquerylinedtextarea.htm
|
||||
*
|
||||
* Copyright (c) 2010 Alan Williamson
|
||||
*
|
||||
* Version:
|
||||
* $Id: jquery-linedtextarea.js 464 2010-01-08 10:36:33Z alan $
|
||||
*
|
||||
* Released under the MIT License:
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
*
|
||||
* Usage:
|
||||
* Displays a line number count column to the left of the textarea
|
||||
*
|
||||
* Class up your textarea with a given class, or target it directly
|
||||
* with JQuery Selectors
|
||||
*
|
||||
* $(".lined").linedtextarea({
|
||||
* selectedLine: 10,
|
||||
* selectedClass: 'lineselect'
|
||||
* });
|
||||
*
|
||||
* History:
|
||||
* - 2010.01.08: Fixed a Google Chrome layout problem
|
||||
* - 2010.01.07: Refactored code for speed/readability; Fixed horizontal sizing
|
||||
* - 2010.01.06: Initial Release
|
||||
*
|
||||
*/
|
||||
(function($) {
|
||||
$.fn.linedtextarea = function(options) {
|
||||
|
||||
// Get the Options
|
||||
var opts = $.extend({}, $.fn.linedtextarea.defaults, options);
|
||||
|
||||
/*
|
||||
* Helper function to make sure the line numbers are always
|
||||
* kept up to the current system
|
||||
*/
|
||||
var fillOutLines = function(codeLines, h, lineNo){
|
||||
while ( (codeLines.height() - h ) <= 0 ){
|
||||
if ( lineNo == opts.selectedLine )
|
||||
codeLines.append("<div class='lineno lineselect'>" + lineNo + "</div>");
|
||||
else
|
||||
codeLines.append("<div class='lineno'>" + lineNo + "</div>");
|
||||
|
||||
lineNo++;
|
||||
}
|
||||
return lineNo;
|
||||
};
|
||||
|
||||
/*
|
||||
* Iterate through each of the elements are to be applied to
|
||||
*/
|
||||
return this.each(function() {
|
||||
var lineNo = 1;
|
||||
var textarea = $(this);
|
||||
|
||||
/* Turn off the wrapping of as we don't want to screw up the line numbers */
|
||||
textarea.attr("wrap", "off");
|
||||
textarea.css({resize:'none'});
|
||||
// var originalTextAreaWidth = textarea.outerWidth();
|
||||
|
||||
/* Wrap the text area in the elements we need */
|
||||
textarea.wrap("<div class='linedtextarea'></div>");
|
||||
var linedTextAreaDiv = textarea.parent().wrap("<div class='linedwrap'></div>");
|
||||
var linedWrapDiv = linedTextAreaDiv.parent();
|
||||
|
||||
linedWrapDiv.prepend("<div class='lines'></div>");
|
||||
|
||||
var linesDiv = linedWrapDiv.find(".lines");
|
||||
linesDiv.height( textarea.height() + 4 );
|
||||
|
||||
|
||||
/* Draw the number bar; filling it out where necessary */
|
||||
linesDiv.append( "<div class='codelines'></div>" );
|
||||
var codeLinesDiv = linesDiv.find(".codelines");
|
||||
lineNo = fillOutLines( codeLinesDiv, linesDiv.height(), 1 );
|
||||
|
||||
/* Move the textarea to the selected line */
|
||||
if ( opts.selectedLine != -1 && !isNaN(opts.selectedLine) ){
|
||||
var fontSize = parseInt( textarea.height() / (lineNo-2) );
|
||||
var position = parseInt( fontSize * opts.selectedLine ) - (textarea.height()/2);
|
||||
textarea[0].scrollTop = position;
|
||||
}
|
||||
|
||||
|
||||
/* React to the scroll event */
|
||||
textarea.scroll( function(){
|
||||
var domTextArea = $(this)[0];
|
||||
var scrollTop = domTextArea.scrollTop;
|
||||
var clientHeight = domTextArea.clientHeight;
|
||||
codeLinesDiv.css( {'margin-top': (-1*scrollTop) + "px"} );
|
||||
lineNo = fillOutLines( codeLinesDiv, scrollTop + clientHeight, lineNo );
|
||||
});
|
||||
|
||||
|
||||
/* Should the textarea get resized outside of our control */
|
||||
textarea.resize( function(){
|
||||
var domTextArea = $(this)[0];
|
||||
linesDiv.height( domTextArea.clientHeight + 4 );
|
||||
});
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
// default options
|
||||
$.fn.linedtextarea.defaults = {
|
||||
selectedLine: -1,
|
||||
selectedClass: 'lineselect'
|
||||
};
|
||||
})(jQuery);
|
Reference in New Issue
Block a user