| # A convenient place to stash server data |
| Server = {directors: []} |
| |
| # |
| # function to assist with production of HTML and regular expressions |
| # |
| |
| # Escape HTML characters so that raw text can be safely inserted as HTML |
| def htmlEscape(string) |
| return string.gsub(htmlEscape.chars) {|c| htmlEscape.replacement[c]} |
| end |
| |
| htmlEscape.chars = Regexp.new('[&<>]', 'g') |
| htmlEscape.replacement = {'&' => '&', '<' => '<', '>' => '>'} |
| |
| # escape a string so that it can be used as a regular expression |
| def escapeRegExp(string) |
| # https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions |
| return string.gsub(/([.*+?^=!:${}()|\[\]\/\\])/, "\\$1"); |
| end |
| |
| # Replace http[s] links in text with anchor tags |
| def hotlink(string) |
| return string.gsub hotlink.regexp do |match, pre, link| |
| "#{pre}<a href='#{link}'>#{link}</a>" |
| end |
| end |
| |
| hotlink.regexp = Regexp.new(/(^|[\s.:;?\-\]<\(]) |
| (https?:\/\/[-\w;\/?:@&=+$.!~*'()%,#]+[\w\/]) |
| (?=$|[\s.:;,?\-\[\]&\)])/x, "g") |
| |
| # |
| # Requests to the server |
| # |
| |
| # "AJAX" style post request to the server, with a callback |
| def post(target, data, &block) |
| xhr = XMLHttpRequest.new() |
| xhr.open('POST', "../json/#{target}", true) |
| xhr.setRequestHeader('Content-Type', 'application/json;charset=utf-8') |
| xhr.responseType = 'text' |
| |
| def xhr.onreadystatechange() |
| if xhr.readyState == 4 |
| data = nil |
| |
| begin |
| if xhr.status == 200 |
| data = JSON.parse(xhr.responseText) |
| alert "Exception\n#{data.exception}" if data.exception |
| elsif xhr.status == 404 |
| alert "Not Found: json/#{target}" |
| elsif xhr.status >= 400 |
| if not xhr.response |
| message = "Exception - #{xhr.statusText}" |
| elsif xhr.response.exception |
| message = "Exception\n#{xhr.response.exception}" |
| else |
| begin |
| message = "Exception\n#{JSON.parse(xhr.responseText).exception}" |
| rescue |
| message = "Exception\n#{xhr.responseText}" |
| end |
| end |
| |
| console.log(message) |
| alert message |
| end |
| rescue => e |
| console.log(e) |
| end |
| |
| block(data) |
| Main.refresh() |
| end |
| end |
| |
| xhr.send(JSON.stringify(data)) |
| end |
| |
| # "AJAX" style get request to the server, with a callback |
| # |
| # Would love to use/build on 'fetch', but alas: |
| # |
| # https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API#Browser_compatibility |
| def retrieve(target, type, &block) |
| xhr = XMLHttpRequest.new() |
| |
| def xhr.onreadystatechange() |
| if xhr.readyState == 1 |
| Header.clock_counter += 1 |
| elsif xhr.readyState == 4 |
| data = nil |
| |
| begin |
| if xhr.status == 200 |
| if type == :json |
| data = xhr.response || JSON.parse(xhr.responseText) |
| else |
| data = xhr.responseText |
| end |
| elsif xhr.status == 404 |
| alert "Not Found: #{type}/#{target}" |
| elsif xhr.status >= 400 |
| if not xhr.response |
| message = "Exception - #{xhr.statusText}" |
| elsif xhr.response.exception |
| message = "Exception\n#{xhr.response.exception}" |
| else |
| begin |
| message = "Exception\n#{JSON.parse(xhr.responseText).exception}" |
| rescue => e |
| message = "Exception\n#{xhr.responseText}" |
| end |
| end |
| |
| console.log(message) |
| alert(message) |
| end |
| rescue => e |
| console.log(e) |
| end |
| |
| block(data) |
| Header.clock_counter -= 1 |
| end |
| end |
| |
| if target =~ /^https?:/ |
| xhr.open('GET', target, true) |
| xhr.setRequestHeader("Accept", "application/json") if type == :json |
| else |
| xhr.open('GET', "../#{type}/#{target}", true) |
| end |
| xhr.responseType = type |
| xhr.send() |
| end |
| |
| # |
| # Reflow comments and lines |
| # |
| |
| class Flow |
| # reflow comment |
| def self.comment(comment, initials, indent=' ') |
| lines = comment.split("\n") |
| len = 71 - indent.length |
| for i in 0...lines.length |
| lines[i] = (i == 0 ? initials + ': ' : "#{indent} ") + lines[i]. |
| gsub(/(.{1,#{len}})( +|$\n?)|(.{1,#{len}})/, "$1$3\n#{indent}"). |
| trim() |
| end |
| return lines.join("\n") |
| end |
| |
| # reflow text. Indent is a string containing the amount of spaces that are |
| # to be added to each line. The Incubator has special punctuation rules that |
| # prohibit the joining of lines where the first line ends in either a colon |
| # or a question mark. |
| def self.text(text, indent='', puncrules=false) |
| # remove trailing spaces on lines |
| text.gsub! /[ \r\t]+\n/, "\n" |
| |
| # split into lines |
| lines = text.split("\n") |
| |
| # join consecutive lines, making exception for lines that start with a |
| # hash (#) and <markers> like <private>, ")". |
| (lines.length-1).downto(1) do |i| |
| next if lines[i-1] =~ /^$|^#|\w>$/ |
| next if puncrules and lines[i-1] =~ /[:?]$/ |
| if lines[i] =~ /^\s*\w/ and lines[i] !~ /^\s*\d+\./ |
| lines.splice(i-1, 2, lines[i-1] + lines[i].sub(/^\s*/, ' ')) |
| end |
| end |
| |
| # reflow each line |
| len = 78 - indent.length |
| for i in 0...lines.length |
| line = lines[i] |
| next if line.length <= len |
| prefix = /^\d+\.\s+|^\W*/.exec(line)[0] |
| |
| if prefix.length == 0 |
| # not indented -> split |
| lines[i] = line. |
| gsub(/(.{1,#{len}})( +|$\n?)/, "$1\n"). |
| sub(/[\n\r]+$/, '') |
| else |
| # ensure line can be split after column 40 |
| lastspace = /^.*\s\S/.exec(line) |
| if lastspace and lastspace[0].length - 1 > 40 |
| # preserve indentation. |
| n = len - prefix.length; |
| indent = prefix.gsub(/\S/, ' ') |
| lines[i] = prefix + line[prefix.length..-1]. |
| gsub(/(.{1,#{n}})( +|$\n?)/, indent + "$1\n"). |
| sub(indent, '').sub(/[\n\r]+$/, '') |
| end |
| end |
| end |
| |
| return lines.join("\n") |
| end |
| end |
| |
| # |
| # Split comments string into individual comments |
| # |
| |
| def splitComments(string) |
| results = [] |
| return results unless string |
| |
| comment = '' |
| string.split("\n").each do |line| |
| if line =~ /^\S/ |
| results << comment unless comment.empty? |
| comment = line |
| else |
| comment += "\n" + line |
| end |
| end |
| |
| results << comment unless comment.empty? |
| return results |
| end |
| |