diff --git a/.eslintrc.yml b/.eslintrc.yml new file mode 100644 index 0000000..dec7a9c --- /dev/null +++ b/.eslintrc.yml @@ -0,0 +1,19 @@ +# http://eslint.org/docs/user-guide/configuring +# http://eslint.org/docs/2.0.0/rules/ +env: + browser: true + jquery: true +extends: 'eslint:recommended' +rules: + indent: + - error + - 2 + linebreak-style: + - error + - unix + no-trailing-spaces: + - warn + quotes: off + semi: + - error + - always diff --git a/Dockerfile b/Dockerfile index befa229..e744705 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,6 +19,10 @@ RUN apt-get update \ && echo "alias la='ls -ahl'" >> /root/.bashrc \ && echo "export HISTCONTROL=ignoredups" >> /root/.bashrc +# RUN curl -sL https://deb.nodesource.com/setup_6.x | bash - +# RUN apt-get update\ +# && apt-get install --yes nodejs + # install current Ruby RUN curl -L --progress https://github.com/postmodern/ruby-install/archive/v0.6.0.tar.gz | tar xz \ && cd ruby-install-0.6.0 \ diff --git a/Gemfile b/Gemfile index b03c04f..4529cd4 100644 --- a/Gemfile +++ b/Gemfile @@ -21,10 +21,10 @@ gem 'neat' gem 'bitters' group :development do + gem 'better_errors' gem 'rack-livereload' gem 'rails-erd' gem 'web-console' - gem 'better_errors' end group :development, :test do diff --git a/Guardfile b/Guardfile index 3a072a4..b3d22bf 100644 --- a/Guardfile +++ b/Guardfile @@ -23,7 +23,7 @@ guard :minitest, spring: true do # , all_after_pass: true end guard 'livereload' do - watch(%r{app/assets/.+\.(scss|css|js)}) + watch(%r{app/assets/.+\.(scss|css|js|erb)}) watch(%r{app/views/.+\.(erb|haml|slim)$}) watch(%r{app/controllers/.+\.rb}) watch(%r{app/helpers/.+\.rb}) @@ -31,7 +31,7 @@ guard 'livereload' do watch(%r{config/locales/.+\.yml}) # Rails Assets Pipeline - watch(%r{(app|vendor)(/assets/\w+/(.+\.(scss|css|js|html|png|jpg))).*}) do |m| + watch(%r{(app|vendor)(/assets/\w+/(.+\.(scss|css|js|erb|html|png|jpg))).*}) do |m| "/assets/#{m[3]}" end end @@ -41,3 +41,10 @@ guard :rubocop do watch(/Rakefile/) watch(%r{(?:.+/)?\.rubocop\.yml$}) { |m| File.dirname(m[0]) } end + +# ESLint +guard :shell, all_on_start: true do + watch %r{app/assets/javascripts/*/.*} do |file| + `eslint #{file[0]}` + end +end diff --git a/app/assets/javascripts/button-group.js b/app/assets/javascripts/button-group.js index 727382b..bea798c 100644 --- a/app/assets/javascripts/button-group.js +++ b/app/assets/javascripts/button-group.js @@ -1,7 +1,7 @@ /** * Button Group Functionality */ - + $('.btn-group button').click(function() { $(this).siblings().removeClass('selected'); $(this).addClass('selected'); diff --git a/app/assets/javascripts/cable.js b/app/assets/javascripts/cable.js index 71ee1e6..24e7047 100644 --- a/app/assets/javascripts/cable.js +++ b/app/assets/javascripts/cable.js @@ -5,9 +5,9 @@ //= require_self //= require_tree ./channels -(function() { - this.App || (this.App = {}); - - App.cable = ActionCable.createConsumer(); - -}).call(this); +// (function() { +// this.App || (this.App = {}); +// +// App.cable = ActionCable.createConsumer(); +// +// }).call(this); diff --git a/app/assets/javascripts/jquery-linedtextarea-moser.js b/app/assets/javascripts/jquery-linedtextarea-moser.js index 27dced7..bea9ef9 100644 --- a/app/assets/javascripts/jquery-linedtextarea-moser.js +++ b/app/assets/javascripts/jquery-linedtextarea-moser.js @@ -1,5 +1,6 @@ /** * NOTE: MARK MOSER EDITED COPY. DO NOT USE BOWER. + * * jQuery Lined Textarea Plugin * http://alan.blog-city.com/jquerylinedtextarea.htm * @@ -29,99 +30,96 @@ * */ (function($) { + $.fn.linedtextarea = function(options) { - $.fn.linedtextarea = function(options) { + // Get the Options + var opts = $.extend({}, $.fn.linedtextarea.defaults, 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("
" + lineNo + "
"); + else + codeLines.append("
" + lineNo + "
"); + + 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("
"); + var linedTextAreaDiv = textarea.parent().wrap("
"); + var linedWrapDiv = linedTextAreaDiv.parent(); + + linedWrapDiv.prepend("
"); + + var linesDiv = linedWrapDiv.find(".lines"); + linesDiv.height( textarea.height() + 4 ); - /* - * 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("
" + lineNo + "
"); - else - codeLines.append("
" + lineNo + "
"); + /* Draw the number bar; filling it out where necessary */ + linesDiv.append( "
" ); + var codeLinesDiv = linesDiv.find(".codelines"); + lineNo = fillOutLines( codeLinesDiv, linesDiv.height(), 1 ); - lineNo++; - } - return lineNo; - }; + /* 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; + } - /* - * 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("
"); - var linedTextAreaDiv = textarea.parent().wrap("
"); - var linedWrapDiv = linedTextAreaDiv.parent(); - - linedWrapDiv.prepend("
"); - - var linesDiv = linedWrapDiv.find(".lines"); - linesDiv.height( textarea.height() + 4 ); - - - /* Draw the number bar; filling it out where necessary */ - linesDiv.append( "
" ); - 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; - } - - - /* Set the width */ - // var sidebarWidth = linesDiv.outerWidth(); - // var paddingHorizontal = parseInt( linedWrapDiv.css("border-left-width") ) + parseInt( linedWrapDiv.css("border-right-width") ) + parseInt( linedWrapDiv.css("padding-left") ) + parseInt( linedWrapDiv.css("padding-right") ); - // var linedWrapDivNewWidth = originalTextAreaWidth - paddingHorizontal; - // var textareaNewWidth = originalTextAreaWidth - sidebarWidth - paddingHorizontal - 20; - // - // textarea.width( textareaNewWidth ); - // linedWrapDiv.width( linedWrapDivNewWidth ); + /* Set the width */ + // var sidebarWidth = linesDiv.outerWidth(); + // var paddingHorizontal = parseInt( linedWrapDiv.css("border-left-width") ) + parseInt( linedWrapDiv.css("border-right-width") ) + parseInt( linedWrapDiv.css("padding-left") ) + parseInt( linedWrapDiv.css("padding-right") ); + // var linedWrapDivNewWidth = originalTextAreaWidth - paddingHorizontal; + // var textareaNewWidth = originalTextAreaWidth - sidebarWidth - paddingHorizontal - 20; + // + // textarea.width( textareaNewWidth ); + // linedWrapDiv.width( linedWrapDivNewWidth ); - /* React to the scroll event */ - textarea.scroll( function(tn){ - 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 ); - }); + /* 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(tn){ - var domTextArea = $(this)[0]; - linesDiv.height( domTextArea.clientHeight + 4 ); - }); + /* 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' + selectedLine: -1, + selectedClass: 'lineselect' }; })(jQuery); diff --git a/app/assets/javascripts/live-coder.js.erb b/app/assets/javascripts/live-coder.js.erb index ffc2a64..f559a09 100644 --- a/app/assets/javascripts/live-coder.js.erb +++ b/app/assets/javascripts/live-coder.js.erb @@ -1,4 +1,5 @@ -function updateResults(elem) { var resultsContainer = $(elem).find('[data-id="results"]')[0]; +function updateResults(elem) { + 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(); @@ -15,7 +16,9 @@ function updateResults(elem) { var resultsContainer = $(elem).find('[data-id="r var jqueryNode = document.createElement("script"); jqueryNode.setAttribute("type", "text/javascript"); - jqueryNode.setAttribute("src", "<%= "//#{ENV['full_app_url']}#{javascript_path "jquery"}" %>"); + // TODO: fix eslint runner to handle erb snippets + // jqueryNode.setAttribute("src", "<%= "//#{ENV['full_app_url']}#{javascript_path "jquery"}" %>"); + jqueryNode.setAttribute("src", "https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"); iHead.appendChild(jqueryNode); var codeStyle = document.createElement("style"); @@ -92,7 +95,7 @@ function indentSelection(e){ } -timer = 0; +var timer = 0; $(function(){ // wait a half second before updating results // restart the timer if they resume typing diff --git a/app/assets/javascripts/summary-edit.js b/app/assets/javascripts/summary-edit.js index 2611acc..e3ebf7f 100644 --- a/app/assets/javascripts/summary-edit.js +++ b/app/assets/javascripts/summary-edit.js @@ -41,7 +41,7 @@ var editClickHandler = function(e) { else if(thisEd.find('input').attr('type') == 'checkbox') { $(thisEd.find('input')).each(function() { if($(this).prop('checked') === true) { - existingValue.push($(this).val()); + existingValue.push($(this).val()); } }); } @@ -66,13 +66,13 @@ var cancelClickHandler = function(e) { var thisEd = $(e.delegateTarget); if(thisEd.find('input').attr('type') == 'radio') { $(thisEd.find('input')).each(function() { - if($(this).val()!=existingValue) { - $(this).attr('checked', false).prop('checked', false); - } - else { - $(this).prop('checked', true); - } - }); + if($(this).val()!=existingValue) { + $(this).attr('checked', false).prop('checked', false); + } + else { + $(this).prop('checked', true); + } + }); } else if(thisEd.find('input').attr('type') == 'checkbox') { $(existingValue).each(function(index, value) { @@ -137,39 +137,39 @@ var saveClickHandler = function(e) { $(thisEd).before('
Please select or enter a value.
'); } else { thisEd.find('textarea:not(.code-answer)').replaceWith('

' + $.trim(thisEd.find('textarea').val()) + '

'); - url = thisEd.closest('form').attr('action'); + var postUrl = thisEd.closest('form').attr('action'); $.ajax({ type: "POST", - url: url, + url: postUrl, data: ({ 'answer': $.extend(data, {'question_id': questionId, 'answer_id': answerId}), 'submit': true }), - success: function(data){ + success: function(){ //unused data executeQuery = true; }, - error: function(data){ + error: function(){ //unused data executeQuery = false; } }).done(function() { - if(executeQuery === true) { - $('.success, .error').remove(); - $(thisEd).before('
Your answer has been updated successfully!
'); - $(thisEd).find('.code-answer').attr('disabled', true); - } - if(executeQuery === false) { - $('.error, .success').remove(); - $(thisEd).before('
Oops! There was an error processing your request. Please try again.
'); - } + if(executeQuery === true) { + $('.success, .error').remove(); + $(thisEd).before('
Your answer has been updated successfully!
'); + $(thisEd).find('.code-answer').attr('disabled', true); + } + if(executeQuery === false) { + $('.error, .success').remove(); + $(thisEd).before('
Oops! There was an error processing your request. Please try again.
'); + } }); - $('.button-edit, .submit-button').removeClass('disabled-button'); - thisEd.removeClass('editable'); - thisEd.find('.answer-block').prop('disabled', true); - thisEd.find('.button-edit').show(); - thisEd.find('.button-save, .button-cancel').hide(); -} + $('.button-edit, .submit-button').removeClass('disabled-button'); + thisEd.removeClass('editable'); + thisEd.find('.answer-block').prop('disabled', true); + thisEd.find('.button-edit').show(); + thisEd.find('.button-save, .button-cancel').hide(); + } }; $('.answer-block').prop('disabled', true); diff --git a/app/assets/javascripts/textarea-limit.js b/app/assets/javascripts/textarea-limit.js index ca9ee07..6605f85 100644 --- a/app/assets/javascripts/textarea-limit.js +++ b/app/assets/javascripts/textarea-limit.js @@ -1,30 +1,28 @@ $(document).ready(function() { - setTextAreaLimit(); + setTextAreaLimit(); -function setTextAreaLimit() { - $.fn.extend({ - limiter: function(limit, elem) { - $('textarea').on("keyup focus show", function() { - setCount(this, elem); - }); - - function setCount(src, elem) { - if(src != undefined) { - var chars = src.value.length; - if (chars > limit) { - src.value = src.value.substr(0, limit); - chars = limit; - } - elem.html(limit - chars); - } - } - setCount($(this)[0], elem); - } + function setTextAreaLimit() { + $.fn.extend({ + limiter: function(limit, elem) { + $('textarea').on("keyup focus show", function() { + setCount(this, elem); }); - var elem = $(".chars span"); - $('textarea').limiter(1000, elem); - //$('input').limiter(1000, elem); - //$('.Question-1').addClass('active'); -} -}); \ No newline at end of file + function setCount(src, elem) { + if(src !== undefined) { + var chars = src.value.length; + if (chars > limit) { + src.value = src.value.substr(0, limit); + chars = limit; + } + elem.html(limit - chars); + } + } + setCount($(this)[0], elem); + } + }); + + var elem = $(".chars span"); + $('textarea').limiter(1000, elem); + } +}); diff --git a/package.json b/package.json new file mode 100644 index 0000000..a5660a3 --- /dev/null +++ b/package.json @@ -0,0 +1,15 @@ +{ + "name": "skill-assessment-app", + "version": "1.0.0", + "description": "This application manages quizzes intended to be used as pre-interview skill assessments.", + "dependencies": { + "bower": "^1.7.9", + "eslint": "^3.2.2" + }, + "devDependencies": {}, + "repository": { + "type": "git", + "url": "git@gitlab.perficientxd.com:pdr/skill-assessment-app.git" + }, + "license": "ISC" +} diff --git a/start-dev.sh b/start-dev.sh index 8b92cfe..beeef7c 100755 --- a/start-dev.sh +++ b/start-dev.sh @@ -2,6 +2,7 @@ if [ -d '/usr/app' ]; then cd /usr/app bundle + npm install bower install cd vendor/assets/ && bitters install && cd /usr/app diff --git a/start-server.sh b/start-server.sh index e22fe66..aa2a135 100755 --- a/start-server.sh +++ b/start-server.sh @@ -2,6 +2,7 @@ if [ -d '/usr/app' ]; then cd /usr/app bundle + npm install bower install cd vendor/assets/ && bitters install && cd /usr/app