diff --git a/LICENSE b/LICENSE index b89ac2f..797d5e8 100644 --- a/LICENSE +++ b/LICENSE @@ -3,6 +3,7 @@ Copyright (c) 2010-2011 ashbb Except: * hh/static/(all).png (c) 2008 why the lucky stiff + * lib/ext/hpricot/(all) (c) 2008 why the lucky stiff * lib/ext/projector/(all).rb (c) 2010 MIZUTANI Tociyuki * samples/akatsukiface.png (c) 2010 MIZUTANI Tociyuki * samples/class-book.yaml (c) 2008 why the lucky stiff @@ -13,6 +14,9 @@ Except: * static/Lacuna.ttf (c) 2003 Glashaus, designed by Peter Hoffman * static/gshoes-icon.png (c) 2010 Zachary Scott * static/gshoes-heading-icon.png (c) 2010 Zachary Scott + * static/code_highlighter.js (c) 2005 Dan Webb + * static/code_highlighter_ruby.js (c) 2008 why the lucky stiff + * static/manual.css (c) 2008 why the lucky stiff Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/README.md b/README.md index d1dd357..a632e1e 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,7 @@ Copyright (c) 2010-2011 ashbb Except: - hh/static/(all).png (c) 2008 why the lucky stiff +- lib/ext/hpricot/(all) (c) 2008 why the lucky stiff - lib/ext/projector/(all).rb (c) 2010 MIZUTANI Tociyuki - samples/akatsukiface.png (c) 2010 MIZUTANI Tociyuki - samples/class-book.yaml (c) 2008 why the lucky stiff @@ -107,6 +108,9 @@ Except: - static/Lacuna.ttf (c) 2003 Glashaus, designed by Peter Hoffman - static/gshoes-icon.png (c) 2010 Zachary Scott - static/gshoes-heading-icon.png (c) 2010 Zachary Scott +- static/code_highlighter.js (c) 2005 Dan Webb +- static/code_highlighter_ruby.js (c) 2008 why the lucky stiff +- static/manual.css (c) 2008 why the lucky stiff Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation diff --git a/VERSION b/VERSION index 3aeb049..15806f1 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.192.0 +0.193.0 diff --git a/lib/shoes/help.rb b/lib/shoes/help.rb index db1f9ee..106dc0c 100644 --- a/lib/shoes/help.rb +++ b/lib/shoes/help.rb @@ -2,6 +2,8 @@ class Manual < Shoes url '/', :index url '/manual/(\d+)', :index + include Hpricot + def index pnum = 0 font LANG == 'ja' ? 'MS UI Gothic' : 'Arial' style Link, underline: false, weight: 'bold' @@ -13,6 +15,7 @@ def index pnum = 0 def get_title_and_desc pnum chapter, section = PNUMS[pnum] + return nil unless chapter if section [pnum, DOCS[chapter][1][:sections][section][1][:title], DOCS[chapter][1][:sections][section][1][:description], @@ -45,6 +48,7 @@ def manual pnum, docs_title, docs_description, docs_methods stack{para NL * 4} flow width: 0.2, margin_left: 10 do para *TOC + para link(fg 'to_html', darkmagenta){html_manual} end flow width: 0.8, margin: [10, 0, 20, 0] do @@ -203,6 +207,78 @@ def self.mk_page_numbers docs pnum end + def html_manual + dir = ask_save_folder + return unless dir + FileUtils.mkdir_p File.join(dir, 'static') + %w[gshoes-icon.png shoes-manual-apps.png manual.css code_highlighter.js code_highlighter_ruby.js]. + each{|x| FileUtils.cp "#{DIR}/../static/#{x}", "#{dir}/static"} + Dir[File.join DIR, '../static/man-*.png'].each{|x| FileUtils.cp x, "#{dir}/static"} + + TOC_LIST.length.times do |n| + num, title, desc = get_title_and_desc n + open File.join(dir, "#{TOC_LIST[n][0]}.html"), 'w' do |f| + f.puts mk_html(title, desc, TOC_LIST[n+1], get_title_and_desc(n+1), mk_sidebar_list(num)) + end + end + end + + def mk_html title, desc, next_file, next_title, menu + Hpricot do + xhtml_transitional do + head do + meta :"http-equiv" => "Content-Type", "content" => "text/html; charset=utf-8" + title "The Green Shoes Manual // #{title}" + script type: "text/javascript", src: "static/code_highlighter.js" + script type: "text/javascript", src: "static/code_highlighter_ruby.js" + style type: "text/css" do + text "@import 'static/manual.css';" + end + end + body do + div.main! do + div.manual! do + h2 "The Green Shoes Manual #{VERSION}" + h1 title + + p "

test test test

" + + p.next{text "Next: "; a next_title[1], href: "#{next_file[0]}.html"} if next_title + end + div.sidebar do + img src: "static/gshoes-icon.png" + ul do + li{a.prime "HELP", href: "./"} + menu.each do |m| + li do + unless m.is_a?(Array) + a m, href: "#{m}.html" + else + ul.sub do + m.each do |sm| + li{a sm, href: "#{sm}.html"} + end + end + end + end + end + end + end + end + end + end + end.to_html + end + + def mk_sidebar_list num + toc = [] + [0..3, 4..9, 10..16, 17..32, 33..35].each do |r| + toc.push TOC_LIST[r.first][0] + toc.push(TOC_LIST[r.first+1..r.last].to_a.map &:first) if r.include?(num) + end + toc + end + IMAGE_RE = /\!(\{([^}\n]+)\})?([^!\n]+\.\w+)\!/ CODE_RE = /\{{3}(?:\s*\#![^\n]+)?(.+?)\}{3}/m NL = "\n" diff --git a/static/code_highlighter.js b/static/code_highlighter.js new file mode 100644 index 0000000..ded1839 --- /dev/null +++ b/static/code_highlighter.js @@ -0,0 +1,188 @@ +/* Unobtrustive Code Highlighter By Dan Webb 11/2005 + Version: 0.4 + + Usage: + Add a script tag for this script and any stylesets you need to use + to the page in question, add correct class names to CODE elements, + define CSS styles for elements. That's it! + + Known to work on: + IE 5.5+ PC + Firefox/Mozilla PC/Mac + Opera 7.23 + PC + Safari 2 + + Known to degrade gracefully on: + IE5.0 PC + + Note: IE5.0 fails due to the use of lookahead in some stylesets. To avoid script errors + in older browsers use expressions that use lookahead in string format when defining stylesets. + + This script is inspired by star-light by entirely cunning Dean Edwards + http://dean.edwards.name/star-light/. +*/ + +// replace callback support for safari. +if ("a".replace(/a/, function() {return "b"}) != "b") (function(){ + var default_replace = String.prototype.replace; + String.prototype.replace = function(search,replace){ + // replace is not function + if(typeof replace != "function"){ + return default_replace.apply(this,arguments) + } + var str = "" + this; + var callback = replace; + // search string is not RegExp + if(!(search instanceof RegExp)){ + var idx = str.indexOf(search); + return ( + idx == -1 ? str : + default_replace.apply(str,[search,callback(search, idx, str)]) + ) + } + var reg = search; + var result = []; + var lastidx = reg.lastIndex; + var re; + while((re = reg.exec(str)) != null){ + var idx = re.index; + var args = re.concat(idx, str); + result.push( + str.slice(lastidx,idx), + callback.apply(null,args).toString() + ); + if(!reg.global){ + lastidx += RegExp.lastMatch.length; + break + }else{ + lastidx = reg.lastIndex; + } + } + result.push(str.slice(lastidx)); + return result.join("") + } +})(); + +var CodeHighlighter = { styleSets : new Array }; + +CodeHighlighter.addStyle = function(name, rules) { + // using push test to disallow older browsers from adding styleSets + if ([].push) this.styleSets.push({ + name : name, + rules : rules, + ignoreCase : arguments[2] || false + }) + + function setEvent() { + // set highlighter to run on load (use LowPro if present) + if (typeof Event != 'undefined' && typeof Event.onReady == 'function') + return Event.onReady(CodeHighlighter.init.bind(CodeHighlighter)); + + var old = window.onload; + + if (typeof window.onload != 'function') { + window.onload = function() { CodeHighlighter.init() }; + } else { + window.onload = function() { + old(); + CodeHighlighter.init(); + } + } + } + + // only set the event when the first style is added + if (this.styleSets.length==1) setEvent(); +} + +CodeHighlighter.init = function() { + if (!document.getElementsByTagName) return; + if ("a".replace(/a/, function() {return "b"}) != "b") return; // throw out Safari versions that don't support replace function + // throw out older browsers + + var codeEls = document.getElementsByTagName("CODE"); + // collect array of all pre elements + codeEls.filter = function(f) { + var a = new Array; + for (var i = 0; i < this.length; i++) if (f(this[i])) a[a.length] = this[i]; + return a; + } + + var rules = new Array; + rules.toString = function() { + // joins regexes into one big parallel regex + var exps = new Array; + for (var i = 0; i < this.length; i++) exps.push(this[i].exp); + return exps.join("|"); + } + + function addRule(className, rule) { + // add a replace rule + var exp = (typeof rule.exp != "string")?String(rule.exp).substr(1, String(rule.exp).length-2):rule.exp; + // converts regex rules to strings and chops of the slashes + rules.push({ + className : className, + exp : "(" + exp + ")", + length : (exp.match(/(^|[^\\])\([^?]/g) || "").length + 1, // number of subexps in rule + replacement : rule.replacement || null + }); + } + + function parse(text, ignoreCase) { + // main text parsing and replacement + return text.replace(new RegExp(rules, (ignoreCase)?"gi":"g"), function() { + var i = 0, j = 1, rule; + while (rule = rules[i++]) { + if (arguments[j]) { + // if no custom replacement defined do the simple replacement + if (!rule.replacement) return "" + arguments[0] + ""; + else { + // replace $0 with the className then do normal replaces + var str = rule.replacement.replace("$0", rule.className); + for (var k = 1; k <= rule.length - 1; k++) str = str.replace("$" + k, arguments[j + k]); + return str; + } + } else j+= rule.length; + } + }); + } + + function highlightCode(styleSet) { + // clear rules array + var parsed, clsRx = new RegExp("(\\s|^)" + styleSet.name + "(\\s|$)"); + rules.length = 0; + + // get stylable elements by filtering out all code elements without the correct className + var stylableEls = codeEls.filter(function(item) { return clsRx.test(item.className) }); + + // add style rules to parser + for (var className in styleSet.rules) addRule(className, styleSet.rules[className]); + + + // replace for all elements + for (var i = 0; i < stylableEls.length; i++) { + // EVIL hack to fix IE whitespace badness if it's inside a
+			if (/MSIE/.test(navigator.appVersion) && stylableEls[i].parentNode.nodeName == 'PRE') {
+				stylableEls[i] = stylableEls[i].parentNode;
+				
+				parsed = stylableEls[i].innerHTML.replace(/(]*>)([^<]*)<\/code>/i, function() {
+					return arguments[1] + parse(arguments[2], styleSet.ignoreCase) + ""
+				});
+				parsed = parsed.replace(/\n( *)/g, function() { 
+					var spaces = "";
+					for (var i = 0; i < arguments[1].length; i++) spaces+= " ";
+					return "\n" + spaces;  
+				});
+				parsed = parsed.replace(/\t/g, "    ");
+				parsed = parsed.replace(/\n(<\/\w+>)?/g, "
$1").replace(/
[\n\r\s]*
/g, "


"); + + } else parsed = parse(stylableEls[i].innerHTML, styleSet.ignoreCase); + + stylableEls[i].innerHTML = parsed; + } + } + + // run highlighter on all stylesets + for (var i=0; i < this.styleSets.length; i++) { + highlightCode(this.styleSets[i]); + } +} diff --git a/static/code_highlighter_ruby.js b/static/code_highlighter_ruby.js new file mode 100644 index 0000000..e603118 --- /dev/null +++ b/static/code_highlighter_ruby.js @@ -0,0 +1,26 @@ +CodeHighlighter.addStyle("rb",{ + comment : { + exp : /#[^\n]+/ + }, + brackets : { + exp : /\(|\)|\{|\}/ + }, + string : { + exp : /'[^']*'|"[^"]*"/ + }, + keywords : { + exp : /\b(do|end|self|class|def|if|module|yield|then|else|for|until|unless|while|elsif|case|when|break|retry|redo|rescue|raise)\b/ + }, + constant : { + exp : /\b([A-Z]\w+)\b/ + }, + ivar : { + exp : /([^@])(@{1,2}\w+)\b/ + }, + ns : { + exp : /(:{2,})/ + }, + symbol : { + exp : /(:[A-Za-z0-9_!?]+)/ + } +}); diff --git a/static/manual.css b/static/manual.css new file mode 100644 index 0000000..fa849a6 --- /dev/null +++ b/static/manual.css @@ -0,0 +1,167 @@ +body { + font-family: verdana, arial, sans-serif; + background: #DDD; + margin: 0; padding: 0; +} +a { + color: #378; + text-decoration: none; +} +a.hi { + color: #C30; + font-weight: bold; +} +a:hover { + text-decoration: underline; +} +#main { + width: 720px; + margin: 40px auto; +} +.sidebar { + position: fixed; + width: 120px; +} +#manual { + float: right; + width: 540px; + padding: 20px; + border: solid 1px #BBB; + background: #eee; + margin-bottom: 80px; +} +#manual li { + margin-bottom: 8px; +} +h1 { + font-weight: normal; + font-size: 42px; + margin-top: 0; +} +h2 { + font-weight: normal; + font-size: 12px; + color: #777; + margin: 0; +} +h4 { + font-weight: normal; + font-size: 32px; + margin-bottom: 0; +} +#manual img { + display: block; + margin: 0 auto; + padding: 10px; +} +div.method { + background: #333; + padding: 4px; + color: #CCC; +} +div.method a { + color: white; + text-decoration: none; + font-weight: bold; +} +.intro { + font-size: 140%; + border-bottom: solid 1px #BBB; +} +.sidebar ul { + list-style: none; + text-align: center; + margin: 0; padding: 10px; + font-size: 18px; +} +.sidebar ul.sub { + margin: 6px 0; padding: 0; + border-left: solid 1px #CCC; + border-right: solid 1px #CCC; +} +.sidebar ul.sub li { + margin: 0; padding: 0; + font-size: 14px; +} +.sidebar ul.sub a { + font-weight: normal; +} +.sidebar a { + color: #666; + font-weight: bold; + text-decoration: none; +} +.sidebar .prime { + display: block; + color: #BBB; + font-size: 38px; + margin-bottom: 20px; +} +.sidebar a:hover { + color: black; +} +div.color { + width: 31%; + float: left; + text-align: center; + padding: 6px; + font-size: 80%; +} +div.color h3, div.color p { + margin: 4px; +} +p.next { + clear: both; + border-top: solid 1px #BBB; + text-align: right; + font-size: 120%; + padding: 8px; +} + +/* code highlighting */ +pre { + background: white; + padding: 8px 0; + border: solid 1px #ddd; +} +pre .comment, .ruby .comment { + color: #696; +} pre .string, .ruby .string { + color: teal; +} +pre .constant, .ruby .constant { + font-weight: bold; +} +pre .symbol, .ruby .symbol { + color: green; +} +pre .keywords, .ruby .keywords { + color: #662; +} +pre .global, pre .ivar, .ruby .ivar { + color: #F60; +} +pre .brackets, .ruby .brackets { + color: #993; +} + +/* index pages */ +#index .hibox { + background: white; + border: solid 1px #ddd; +} +#index .hibox p { + font-size: 14px; + margin: 8px; +} +#index h1 { + margin: 0; +} +#index ul { + list-style: none; + font-size: 13px; +} +#index ul a.hi, +#index ul a.lo { + font-size: 18px; +}