diff --git a/.gitignore b/.gitignore index 4e183355..89d0de42 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ /rubocop.html /tmp /vagrant/ +/.vagrant *.sublime-* /.idea /.vagrant diff --git a/Gemfile b/Gemfile index 3b1b2cd2..5c6bbd31 100644 --- a/Gemfile +++ b/Gemfile @@ -5,9 +5,9 @@ gem 'bcrypt', '~> 3.1.7' gem 'bootstrap-will_paginate' gem 'carrierwave' gem 'coffee-rails', '~> 4.0.0' -gem 'concurrent-ruby' -gem 'concurrent-ruby-ext', platform: :ruby -gem 'docker-api','~> 1.21.1', require: 'docker' +gem 'concurrent-ruby', '~> 1.0.0' +gem 'concurrent-ruby-ext', '~> 1.0.0', platform: :ruby +gem 'docker-api','~> 1.25.0', require: 'docker' gem 'factory_girl_rails', '~> 4.0' gem 'forgery' gem 'highline' @@ -19,9 +19,9 @@ gem 'kramdown' gem 'newrelic_rpm' gem 'pg', platform: :ruby gem 'pry' -gem 'puma' +gem 'puma', '~> 2.15.3' gem 'pundit' -gem 'rails', '~> 4.1.2' +gem 'rails', '~> 4.1.13' gem 'rails-i18n', '~> 4.0.0' gem 'ransack' gem 'rubytree' @@ -35,6 +35,7 @@ gem 'uglifier', '>= 1.3.0' gem 'will_paginate', '~> 3.0' gem 'tubesock' gem 'faye-websocket' +gem 'nokogiri' group :development do gem 'better_errors', platform: :ruby diff --git a/Gemfile.lock b/Gemfile.lock index d27789ea..5feafdc7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -2,41 +2,40 @@ GEM remote: https://rubygems.org/ specs: ZenTest (4.11.0) - actionmailer (4.1.10) - actionpack (= 4.1.10) - actionview (= 4.1.10) + actionmailer (4.1.14.1) + actionpack (= 4.1.14.1) + actionview (= 4.1.14.1) mail (~> 2.5, >= 2.5.4) - actionpack (4.1.10) - actionview (= 4.1.10) - activesupport (= 4.1.10) + actionpack (4.1.14.1) + actionview (= 4.1.14.1) + activesupport (= 4.1.14.1) rack (~> 1.5.2) rack-test (~> 0.6.2) - actionview (4.1.10) - activesupport (= 4.1.10) + actionview (4.1.14.1) + activesupport (= 4.1.14.1) builder (~> 3.1) erubis (~> 2.7.0) - activemodel (4.1.10) - activesupport (= 4.1.10) + activemodel (4.1.14.1) + activesupport (= 4.1.14.1) builder (~> 3.1) - activerecord (4.1.10) - activemodel (= 4.1.10) - activesupport (= 4.1.10) + activerecord (4.1.14.1) + activemodel (= 4.1.14.1) + activesupport (= 4.1.14.1) arel (~> 5.0.0) - activerecord-jdbc-adapter (1.3.15) + activerecord-jdbc-adapter (1.3.19) activerecord (>= 2.2) - activerecord-jdbcpostgresql-adapter (1.3.15) - activerecord-jdbc-adapter (~> 1.3.15) + activerecord-jdbcpostgresql-adapter (1.3.19) + activerecord-jdbc-adapter (~> 1.3.19) jdbc-postgres (>= 9.1) - activesupport (4.1.10) + activesupport (4.1.14.1) i18n (~> 0.6, >= 0.6.9) json (~> 1.7, >= 1.7.7) minitest (~> 5.1) thread_safe (~> 0.1) tzinfo (~> 1.1) + addressable (2.4.0) arel (5.0.1.20140414130214) - ast (2.0.0) - astrolabe (1.3.0) - parser (>= 2.2.0.pre.3, < 3.0) + ast (2.2.0) autotest-rails (4.2.1) ZenTest (~> 4.5) bcrypt (3.1.10) @@ -50,7 +49,7 @@ GEM bootstrap-will_paginate (0.0.10) will_paginate builder (3.2.2) - byebug (6.0.2) + byebug (8.2.2) capistrano (3.3.5) capistrano-stats (~> 1.1.0) i18n @@ -59,19 +58,20 @@ GEM capistrano-bundler (1.1.4) capistrano (~> 3.1) sshkit (~> 1.2) - capistrano-rails (1.1.2) + capistrano-rails (1.1.6) capistrano (~> 3.1) capistrano-bundler (~> 1.1) capistrano-rvm (0.1.2) capistrano (~> 3.0) sshkit (~> 1.2) capistrano-stats (1.1.1) - capistrano-upload-config (0.6.0) + capistrano-upload-config (0.7.0) capistrano (>= 3.0) - capistrano3-puma (0.9.0) + capistrano3-puma (1.2.1) capistrano (~> 3.0) puma (>= 2.6) - capybara (2.4.4) + capybara (2.6.2) + addressable mime-types (>= 1.16) nokogiri (>= 1.3.3) rack (>= 1.0.0) @@ -82,9 +82,9 @@ GEM activesupport (>= 3.2.0) json (>= 1.7) mime-types (>= 1.16) - childprocess (0.5.6) + childprocess (0.5.9) ffi (~> 1.0, >= 1.0.11) - codeclimate-test-reporter (0.4.7) + codeclimate-test-reporter (0.4.8) simplecov (>= 0.7.1, < 1.0.0) coderay (1.1.0) coffee-rails (4.0.1) @@ -93,168 +93,165 @@ GEM coffee-script (2.4.1) coffee-script-source execjs - coffee-script-source (1.9.1) - colorize (0.7.7) - concurrent-ruby (0.8.0) - ref (~> 1.0, >= 1.0.5) - concurrent-ruby (0.8.0-java) - concurrent-ruby-ext (0.8.0) - concurrent-ruby (~> 0.8.0) - database_cleaner (1.4.1) + coffee-script-source (1.10.0) + concurrent-ruby (1.0.0) + concurrent-ruby (1.0.0-java) + concurrent-ruby-ext (1.0.0) + concurrent-ruby (~> 1.0.0) + database_cleaner (1.5.1) debug_inspector (0.0.2) diff-lcs (1.2.5) docile (1.1.5) - docker-api (1.21.1) + docker-api (1.25.0) excon (>= 0.38.0) json erubis (2.7.0) - eventmachine (1.0.8) - eventmachine (1.0.8-java) - excon (0.45.2) - execjs (2.5.2) + eventmachine (1.0.9.1) + eventmachine (1.0.9.1-java) + excon (0.45.4) + execjs (2.6.0) factory_girl (4.5.0) activesupport (>= 3.0.0) - factory_girl_rails (4.5.0) + factory_girl_rails (4.6.0) factory_girl (~> 4.5.0) railties (>= 3.0.0) - faraday (0.9.1) + faraday (0.9.2) multipart-post (>= 1.2, < 3) - faye-websocket (0.10.0) + faye-websocket (0.10.2) eventmachine (>= 0.12.0) websocket-driver (>= 0.5.1) - ffi (1.9.8) - ffi (1.9.8-java) + ffi (1.9.10) + ffi (1.9.10-java) forgery (0.6.0) - highline (1.7.1) + highline (1.7.8) hike (1.2.3) i18n (0.7.0) - ims-lti (1.1.8) + ims-lti (1.1.10) builder oauth (~> 0.4.5) - jbuilder (2.2.13) - activesupport (>= 3.0.0, < 5) + jbuilder (2.4.1) + activesupport (>= 3.0.0, < 5.1) multi_json (~> 1.2) - jdbc-postgres (9.4.1200) - jquery-rails (3.1.2) + jdbc-postgres (9.4.1206) + jquery-rails (3.1.4) railties (>= 3.0, < 5.0) thor (>= 0.14, < 2.0) jquery-turbolinks (2.1.0) railties (>= 3.1.0) turbolinks - json (1.8.2) - json (1.8.2-java) - jwt (1.4.1) - kramdown (1.6.0) + json (1.8.3) + json (1.8.3-java) + jwt (1.5.1) + kramdown (1.9.0) mail (2.6.3) mime-types (>= 1.16, < 3) method_source (0.8.2) - mime-types (2.4.3) - mini_portile (0.6.2) - minitest (5.5.1) - multi_json (1.11.0) + mime-types (2.99) + mini_portile2 (2.0.0) + minitest (5.8.4) + multi_json (1.11.2) multi_xml (0.5.5) multipart-post (2.0.0) net-scp (1.2.1) net-ssh (>= 2.6.5) - net-ssh (2.9.2) - newrelic_rpm (3.11.2.286) - nokogiri (1.6.6.2) - mini_portile (~> 0.6.0) - nokogiri (1.6.6.2-java) + net-ssh (3.0.2) + newrelic_rpm (3.14.3.313) + nokogiri (1.6.7.2) + mini_portile2 (~> 2.0.0.rc2) + nokogiri (1.6.7.2-java) nyan-cat-formatter (0.11) rspec (>= 2.99, >= 2.14.2, < 4) oauth (0.4.7) - oauth2 (1.0.0) + oauth2 (1.1.0) faraday (>= 0.8, < 0.10) - jwt (~> 1.0) + jwt (~> 1.0, < 1.5.2) multi_json (~> 1.3) multi_xml (~> 0.5) - rack (~> 1.2) - parser (2.2.0.3) - ast (>= 1.1, < 3.0) - pg (0.18.1) - polyamorous (1.2.0) + rack (>= 1.2, < 3) + parser (2.3.0.6) + ast (~> 2.2) + pg (0.18.4) + polyamorous (1.3.0) activerecord (>= 3.0) - powerpack (0.1.0) - pry (0.10.1) + powerpack (0.1.1) + pry (0.10.3) coderay (~> 1.1.0) method_source (~> 0.8.1) slop (~> 3.4) - pry (0.10.1-java) + pry (0.10.3-java) coderay (~> 1.1.0) method_source (~> 0.8.1) slop (~> 3.4) spoon (~> 0.0) - puma (2.11.1) - rack (>= 1.1, < 2.0) - puma (2.11.1-java) - rack (>= 1.1, < 2.0) - pundit (0.3.0) + puma (2.15.3) + puma (2.15.3-java) + pundit (1.1.0) activesupport (>= 3.0.0) - rack (1.5.2) + rack (1.5.5) rack-test (0.6.3) rack (>= 1.0) - rails (4.1.10) - actionmailer (= 4.1.10) - actionpack (= 4.1.10) - actionview (= 4.1.10) - activemodel (= 4.1.10) - activerecord (= 4.1.10) - activesupport (= 4.1.10) + rails (4.1.14.1) + actionmailer (= 4.1.14.1) + actionpack (= 4.1.14.1) + actionview (= 4.1.14.1) + activemodel (= 4.1.14.1) + activerecord (= 4.1.14.1) + activesupport (= 4.1.14.1) bundler (>= 1.3.0, < 2.0) - railties (= 4.1.10) + railties (= 4.1.14.1) sprockets-rails (~> 2.0) - rails-i18n (4.0.4) - i18n (~> 0.6) + rails-i18n (4.0.8) + i18n (~> 0.7) railties (~> 4.0) - railties (4.1.10) - actionpack (= 4.1.10) - activesupport (= 4.1.10) + railties (4.1.14.1) + actionpack (= 4.1.14.1) + activesupport (= 4.1.14.1) rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) - rainbow (2.0.0) - rake (10.4.2) - ransack (1.6.6) + rainbow (2.1.0) + rake (10.5.0) + ransack (1.7.0) actionpack (>= 3.0) activerecord (>= 3.0) activesupport (>= 3.0) i18n polyamorous (~> 1.2) - rdoc (4.2.0) - ref (1.0.5) - rspec (3.1.0) - rspec-core (~> 3.1.0) - rspec-expectations (~> 3.1.0) - rspec-mocks (~> 3.1.0) + rdoc (4.2.2) + json (~> 1.4) + rspec (3.4.0) + rspec-core (~> 3.4.0) + rspec-expectations (~> 3.4.0) + rspec-mocks (~> 3.4.0) rspec-autotest (1.0.0) rspec-core (>= 2.99.0.beta1, < 4.0.0) - rspec-core (3.1.7) - rspec-support (~> 3.1.0) - rspec-expectations (3.1.2) + rspec-core (3.4.2) + rspec-support (~> 3.4.0) + rspec-expectations (3.4.0) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.1.0) - rspec-mocks (3.1.3) - rspec-support (~> 3.1.0) - rspec-rails (3.1.0) - actionpack (>= 3.0) - activesupport (>= 3.0) - railties (>= 3.0) - rspec-core (~> 3.1.0) - rspec-expectations (~> 3.1.0) - rspec-mocks (~> 3.1.0) - rspec-support (~> 3.1.0) - rspec-support (3.1.2) - rubocop (0.30.0) - astrolabe (~> 1.3) - parser (>= 2.2.0.1, < 3.0) + rspec-support (~> 3.4.0) + rspec-mocks (3.4.1) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.4.0) + rspec-rails (3.4.2) + actionpack (>= 3.0, < 4.3) + activesupport (>= 3.0, < 4.3) + railties (>= 3.0, < 4.3) + rspec-core (~> 3.4.0) + rspec-expectations (~> 3.4.0) + rspec-mocks (~> 3.4.0) + rspec-support (~> 3.4.0) + rspec-support (3.4.1) + rubocop (0.37.2) + parser (>= 2.3.0.4, < 3.0) powerpack (~> 0.1) rainbow (>= 1.99.1, < 3.0) - ruby-progressbar (~> 1.4) - rubocop-rspec (1.2.2) + ruby-progressbar (~> 1.7) + unicode-display_width (~> 0.3) + rubocop-rspec (1.4.0) ruby-progressbar (1.7.5) - rubytree (0.9.4) + rubytree (0.9.7) json (~> 1.8) - structured_warnings (~> 0.1) + structured_warnings (~> 0.2) rubyzip (1.1.7) sass (3.2.19) sass-rails (4.0.5) @@ -265,17 +262,17 @@ GEM sdoc (0.4.1) json (~> 1.7, >= 1.7.7) rdoc (~> 4.0) - selenium-webdriver (2.45.0) + selenium-webdriver (2.52.0) childprocess (~> 0.5) multi_json (~> 1.0) rubyzip (~> 1.0) websocket (~> 1.0) - simplecov (0.9.2) + simplecov (0.11.2) docile (~> 1.1.0) - multi_json (~> 1.0) - simplecov-html (~> 0.9.0) - simplecov-html (0.9.0) - slim (3.0.3) + json (~> 1.8) + simplecov-html (~> 0.10.0) + simplecov-html (0.10.0) + slim (3.0.6) temple (~> 0.7.3) tilt (>= 1.3.3, < 2.1) slop (3.6.0) @@ -285,22 +282,21 @@ GEM oauth2 (>= 0.8.0) spoon (0.0.4) ffi - spring (1.3.4) - sprockets (2.12.3) + spring (1.6.3) + sprockets (2.12.4) hike (~> 1.2) multi_json (~> 1.0) rack (~> 1.0) tilt (~> 1.1, != 1.3.0) - sprockets-rails (2.2.4) + sprockets-rails (2.3.3) actionpack (>= 3.0) activesupport (>= 3.0) sprockets (>= 2.8, < 4.0) - sshkit (1.7.1) - colorize (>= 0.7.0) + sshkit (1.8.1) net-scp (>= 1.1.2) net-ssh (>= 2.8.0) structured_warnings (0.2.0) - temple (0.7.5) + temple (0.7.6) thor (0.19.1) thread_safe (0.3.5) thread_safe (0.3.5-java) @@ -312,21 +308,22 @@ GEM coffee-rails tzinfo (1.2.2) thread_safe (~> 0.1) - uglifier (2.7.1) + uglifier (2.7.2) execjs (>= 0.3.0) json (>= 1.8.0) - web-console (2.1.2) + unicode-display_width (0.3.1) + web-console (2.3.0) activemodel (>= 4.0) binding_of_caller (>= 0.7.2) railties (>= 4.0) sprockets-rails (>= 2.0, < 4.0) - websocket (1.2.1) - websocket-driver (0.6.2) + websocket (1.2.2) + websocket-driver (0.6.3) websocket-extensions (>= 0.1.0) - websocket-driver (0.6.2-java) + websocket-driver (0.6.3-java) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.2) - will_paginate (3.0.7) + will_paginate (3.1.0) xpath (2.0.0) nokogiri (~> 1.3) @@ -351,10 +348,10 @@ DEPENDENCIES carrierwave codeclimate-test-reporter coffee-rails (~> 4.0.0) - concurrent-ruby - concurrent-ruby-ext + concurrent-ruby (~> 1.0.0) + concurrent-ruby-ext (~> 1.0.0) database_cleaner - docker-api (~> 1.21.1) + docker-api (~> 1.25.0) factory_girl_rails (~> 4.0) faye-websocket forgery @@ -365,12 +362,13 @@ DEPENDENCIES jquery-turbolinks kramdown newrelic_rpm + nokogiri nyan-cat-formatter pg pry - puma + puma (~> 2.15.3) pundit - rails (~> 4.1.2) + rails (~> 4.1.13) rails-i18n (~> 4.0.0) rake ransack @@ -392,6 +390,3 @@ DEPENDENCIES uglifier (>= 1.3.0) web-console (~> 2.0) will_paginate (~> 3.0) - -BUNDLED WITH - 1.10.6 diff --git a/app/assets/javascripts/editor.js b/app/assets/javascripts/editor.js.erb similarity index 96% rename from app/assets/javascripts/editor.js rename to app/assets/javascripts/editor.js.erb index f67d1fb5..2da4a37b 100644 --- a/app/assets/javascripts/editor.js +++ b/app/assets/javascripts/editor.js.erb @@ -30,7 +30,7 @@ $(function() { numMessages = 0, turtlecanvas = $('#turtlecanvas'), prompt = $('#prompt'), - commands = ['input', 'write', 'turtle', 'turtlebatch', 'exit', 'timeout', 'status'], + commands = ['input', 'write', 'turtle', 'turtlebatch', 'render', 'exit', 'timeout', 'status'], streams = ['stdin', 'stdout', 'stderr']; var ENTER_KEY_CODE = 13; @@ -100,12 +100,12 @@ $(function() { } }; - var confirmSubmission = function(event) { - event.preventDefault(); - if (confirm($(this).data('message-confirm'))) { - submitCode(); - } - }; + //var confirmSubmission = function(event) { + // event.preventDefault(); + // if (confirm($(this).data('message-confirm'))) { + // submitCode(); + // } + //}; var createSubmission = function(initiator, filter, callback) { showSpinner(initiator); @@ -245,6 +245,18 @@ $(function() { } }; + var findOrCreateRenderElement = function(index) { + if ($('#render-' + index).isPresent()) { + return $('#render-' + index); + } else { + var element = $('
').attr('id', 'render-' + index); + $('#render').append(element); + return element; + } + }; + + + var getPanelClass = function(result) { if (result.stderr && !result.score) { return 'panel-danger'; @@ -408,6 +420,8 @@ $(function() { setActiveFile($(element).parent().data('filename'), file_id); document.insertLines(0, content.text().split(/\n/)); + // remove last (empty) that is there by default line + document.removeLines(document.getLength()-1,document.getLength()-1); editor.setReadOnly($(element).data('read-only') !== undefined); editor.setShowPrintMargin(false); editor.setTheme(THEME); @@ -419,10 +433,7 @@ $(function() { session.setUseWrapMode(true); var file_id = $(element).data('id'); - setAnnotations(editor, file_id); - - session.on('annotationRemoval', handleAnnotationRemoval); - session.on('annotationChange', handleAnnotationChange); + //setAnnotations(editor, file_id); /* * Register event handlers @@ -637,7 +648,8 @@ $(function() { var initializeWorkflowButtons = function() { $('#start').on('click', showWorkspaceTab); - $('#submit').on('click', confirmSubmission); + //$('#submit').on('click', confirmSubmission); + $('#submit').on('click', submitCode); }; var initializeWorkspaceButtons = function() { @@ -1117,7 +1129,10 @@ $(function() { }; var initWebsocketConnection = function(url) { - websocket = new WebSocket('wss://' + window.location.hostname + ':' + window.location.port + url); + //TODO: get the protocol from config file dependent on environment. (dev: ws, prod: wss) + //causes: Puma::HttpParserError: Invalid HTTP format, parsing fails. + //TODO: make sure that this gets cached. + websocket = new WebSocket('<%= DockerClient.config['ws_client_protocol'] %>' + window.location.hostname + ':' + window.location.port + url); websocket.onopen = function(evt) { resetOutputTab(); }; // todo show some kind of indicator for established connection websocket.onclose = function(evt) { /* expected at some point */ }; websocket.onmessage = function(evt) { parseCanvasMessage(evt.data, true); }; @@ -1169,6 +1184,9 @@ $(function() { showCanvas(); handleTurtlebatchCommand(msg); break; + case 'render': + renderWebsocketOutput(msg); + break; case 'exit': killWebsocketAndContainer(); break; @@ -1182,6 +1200,11 @@ $(function() { } }; + var renderWebsocketOutput = function(msg){ + var element = findOrCreateRenderElement(0); + element.append(msg.data); + }; + var printWebsocketOutput = function(msg) { if (!msg.data) { return; diff --git a/app/assets/javascripts/sortable.js b/app/assets/javascripts/sortable.js new file mode 100644 index 00000000..c9a767c8 --- /dev/null +++ b/app/assets/javascripts/sortable.js @@ -0,0 +1,498 @@ +$(document).ready(function(){ + (function vendorTableSorter(){ + /* + SortTable + version 2 + 7th April 2007 + Stuart Langridge, http://www.kryogenix.org/code/browser/sorttable/ + + Instructions: + Download this file + Add to your HTML + Add class="sortable" to any table you'd like to make sortable + Click on the headers to sort + + Thanks to many, many people for contributions and suggestions. + Licenced as X11: http://www.kryogenix.org/code/browser/licence.html + This basically means: do what you want with it. + */ + + + var stIsIE = /*@cc_on!@*/false; + + sorttable = { + init: function() { + // quit if this function has already been called + if (arguments.callee.done) return; + // flag this function so we don't do the same thing twice + arguments.callee.done = true; + // kill the timer + if (_timer) clearInterval(_timer); + + if (!document.createElement || !document.getElementsByTagName) return; + + sorttable.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/; + + forEach(document.getElementsByTagName('table'), function(table) { + if (table.className.search(/\bsortable\b/) != -1) { + sorttable.makeSortable(table); + } + }); + + }, + + makeSortable: function(table) { + if (table.getElementsByTagName('thead').length == 0) { + // table doesn't have a tHead. Since it should have, create one and + // put the first table row in it. + the = document.createElement('thead'); + the.appendChild(table.rows[0]); + table.insertBefore(the,table.firstChild); + } + // Safari doesn't support table.tHead, sigh + if (table.tHead == null) table.tHead = table.getElementsByTagName('thead')[0]; + + if (table.tHead.rows.length != 1) return; // can't cope with two header rows + + // Sorttable v1 put rows with a class of "sortbottom" at the bottom (as + // "total" rows, for example). This is B&R, since what you're supposed + // to do is put them in a tfoot. So, if there are sortbottom rows, + // for backwards compatibility, move them to tfoot (creating it if needed). + sortbottomrows = []; + for (var i=0; i5' : ' ▴'; + this.appendChild(sortrevind); + return; + } + if (this.className.search(/\bsorttable_sorted_reverse\b/) != -1) { + // if we're already sorted by this column in reverse, just + // re-reverse the table, which is quicker + sorttable.reverse(this.sorttable_tbody); + this.className = this.className.replace('sorttable_sorted_reverse', + 'sorttable_sorted'); + this.removeChild(document.getElementById('sorttable_sortrevind')); + sortfwdind = document.createElement('span'); + sortfwdind.id = "sorttable_sortfwdind"; + sortfwdind.innerHTML = stIsIE ? ' 6' : ' ▾'; + this.appendChild(sortfwdind); + return; + } + + // remove sorttable_sorted classes + theadrow = this.parentNode; + forEach(theadrow.childNodes, function(cell) { + if (cell.nodeType == 1) { // an element + cell.className = cell.className.replace('sorttable_sorted_reverse',''); + cell.className = cell.className.replace('sorttable_sorted',''); + } + }); + sortfwdind = document.getElementById('sorttable_sortfwdind'); + if (sortfwdind) { sortfwdind.parentNode.removeChild(sortfwdind); } + sortrevind = document.getElementById('sorttable_sortrevind'); + if (sortrevind) { sortrevind.parentNode.removeChild(sortrevind); } + + this.className += ' sorttable_sorted'; + sortfwdind = document.createElement('span'); + sortfwdind.id = "sorttable_sortfwdind"; + sortfwdind.innerHTML = stIsIE ? ' 6' : ' ▾'; + this.appendChild(sortfwdind); + + // build an array to sort. This is a Schwartzian transform thing, + // i.e., we "decorate" each row with the actual sort key, + // sort based on the sort keys, and then put the rows back in order + // which is a lot faster because you only do getInnerText once per row + row_array = []; + col = this.sorttable_columnindex; + rows = this.sorttable_tbody.rows; + for (var j=0; j 12) { + // definitely dd/mm + return sorttable.sort_ddmm; + } else if (second > 12) { + return sorttable.sort_mmdd; + } else { + // looks like a date, but we can't tell which, so assume + // that it's dd/mm (English imperialism!) and keep looking + sortfn = sorttable.sort_ddmm; + } + } + } + } + return sortfn; + }, + + getInnerText: function(node) { + // gets the text we want to use for sorting for a cell. + // strips leading and trailing whitespace. + // this is *not* a generic getInnerText function; it's special to sorttable. + // for example, you can override the cell text with a customkey attribute. + // it also gets .value for fields. + + if (!node) return ""; + + hasInputs = (typeof node.getElementsByTagName == 'function') && + node.getElementsByTagName('input').length; + + if (node.getAttribute("sorttable_customkey") != null) { + return node.getAttribute("sorttable_customkey"); + } + else if (typeof node.textContent != 'undefined' && !hasInputs) { + return node.textContent.replace(/^\s+|\s+$/g, ''); + } + else if (typeof node.innerText != 'undefined' && !hasInputs) { + return node.innerText.replace(/^\s+|\s+$/g, ''); + } + else if (typeof node.text != 'undefined' && !hasInputs) { + return node.text.replace(/^\s+|\s+$/g, ''); + } + else { + switch (node.nodeType) { + case 3: + if (node.nodeName.toLowerCase() == 'input') { + return node.value.replace(/^\s+|\s+$/g, ''); + } + case 4: + return node.nodeValue.replace(/^\s+|\s+$/g, ''); + break; + case 1: + case 11: + var innerText = ''; + for (var i = 0; i < node.childNodes.length; i++) { + innerText += sorttable.getInnerText(node.childNodes[i]); + } + return innerText.replace(/^\s+|\s+$/g, ''); + break; + default: + return ''; + } + } + }, + + reverse: function(tbody) { + // reverse the rows in a tbody + newrows = []; + for (var i=0; i=0; i--) { + tbody.appendChild(newrows[i]); + } + delete newrows; + }, + + /* sort functions + each sort function takes two parameters, a and b + you are comparing a[0] and b[0] */ + sort_numeric: function(a,b) { + aa = parseFloat(a[0].replace(/[^0-9.-]/g,'')); + if (isNaN(aa)) aa = 0; + bb = parseFloat(b[0].replace(/[^0-9.-]/g,'')); + if (isNaN(bb)) bb = 0; + return aa-bb; + }, + sort_alpha: function(a,b) { + if (a[0]==b[0]) return 0; + if (a[0] 0 ) { + var q = list[i]; list[i] = list[i+1]; list[i+1] = q; + swap = true; + } + } // for + t--; + + if (!swap) break; + + for(var i = t; i > b; --i) { + if ( comp_func(list[i], list[i-1]) < 0 ) { + var q = list[i]; list[i] = list[i-1]; list[i-1] = q; + swap = true; + } + } // for + b++; + + } // while(swap) + } + } + + /* ****************************************************************** + Supporting functions: bundled here to avoid depending on a library + ****************************************************************** */ + + // Dean Edwards/Matthias Miller/John Resig + + /* for Mozilla/Opera9 */ + if (document.addEventListener) { + document.addEventListener("DOMContentLoaded", sorttable.init, false); + } + + /* for Internet Explorer */ + /*@cc_on @*/ + /*@if (@_win32) + document.write("