green_shoes 0.189.0 → 0.198.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +4 -0
- data/README.md +4 -0
- data/VERSION +1 -1
- data/lib/ext/hpricot.rb +31 -0
- data/lib/ext/hpricot/blankslate.rb +63 -0
- data/lib/ext/hpricot/builder.rb +216 -0
- data/lib/ext/hpricot/elements.rb +510 -0
- data/lib/ext/hpricot/hpricot_scan.so +0 -0
- data/lib/ext/hpricot/htmlinfo.rb +691 -0
- data/lib/ext/hpricot/inspect.rb +103 -0
- data/lib/ext/hpricot/modules.rb +40 -0
- data/lib/ext/hpricot/parse.rb +38 -0
- data/lib/ext/hpricot/tag.rb +202 -0
- data/lib/ext/hpricot/tags.rb +164 -0
- data/lib/ext/hpricot/traverse.rb +838 -0
- data/lib/ext/hpricot/xchar.rb +94 -0
- data/lib/green_shoes.rb +1 -0
- data/lib/shoes/app.rb +17 -1
- data/lib/shoes/help.rb +168 -13
- data/static/code_highlighter.js +188 -0
- data/static/code_highlighter_ruby.js +26 -0
- data/static/manual-en.txt +133 -61
- data/static/manual.css +177 -0
- metadata +19 -3
@@ -0,0 +1,94 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# The XChar library is provided courtesy of Sam Ruby (See
|
4
|
+
# http://intertwingly.net/stories/2005/09/28/xchar.rb)
|
5
|
+
|
6
|
+
# --------------------------------------------------------------------
|
7
|
+
|
8
|
+
######################################################################
|
9
|
+
module Hpricot
|
10
|
+
|
11
|
+
####################################################################
|
12
|
+
# XML Character converter, from Sam Ruby:
|
13
|
+
# (see http://intertwingly.net/stories/2005/09/28/xchar.rb).
|
14
|
+
#
|
15
|
+
module XChar # :nodoc:
|
16
|
+
|
17
|
+
# See
|
18
|
+
# http://intertwingly.net/stories/2004/04/14/i18n.html#CleaningWindows
|
19
|
+
# for details.
|
20
|
+
CP1252 = { # :nodoc:
|
21
|
+
128 => 8364, # euro sign
|
22
|
+
130 => 8218, # single low-9 quotation mark
|
23
|
+
131 => 402, # latin small letter f with hook
|
24
|
+
132 => 8222, # double low-9 quotation mark
|
25
|
+
133 => 8230, # horizontal ellipsis
|
26
|
+
134 => 8224, # dagger
|
27
|
+
135 => 8225, # double dagger
|
28
|
+
136 => 710, # modifier letter circumflex accent
|
29
|
+
137 => 8240, # per mille sign
|
30
|
+
138 => 352, # latin capital letter s with caron
|
31
|
+
139 => 8249, # single left-pointing angle quotation mark
|
32
|
+
140 => 338, # latin capital ligature oe
|
33
|
+
142 => 381, # latin capital letter z with caron
|
34
|
+
145 => 8216, # left single quotation mark
|
35
|
+
146 => 8217, # right single quotation mark
|
36
|
+
147 => 8220, # left double quotation mark
|
37
|
+
148 => 8221, # right double quotation mark
|
38
|
+
149 => 8226, # bullet
|
39
|
+
150 => 8211, # en dash
|
40
|
+
151 => 8212, # em dash
|
41
|
+
152 => 732, # small tilde
|
42
|
+
153 => 8482, # trade mark sign
|
43
|
+
154 => 353, # latin small letter s with caron
|
44
|
+
155 => 8250, # single right-pointing angle quotation mark
|
45
|
+
156 => 339, # latin small ligature oe
|
46
|
+
158 => 382, # latin small letter z with caron
|
47
|
+
159 => 376, # latin capital letter y with diaeresis
|
48
|
+
}
|
49
|
+
|
50
|
+
# See http://www.w3.org/TR/REC-xml/#dt-chardata for details.
|
51
|
+
PREDEFINED = {
|
52
|
+
34 => '"', # quotation mark
|
53
|
+
38 => '&', # ampersand
|
54
|
+
60 => '<', # left angle bracket
|
55
|
+
62 => '>' # right angle bracket
|
56
|
+
}
|
57
|
+
PREDEFINED_U = PREDEFINED.inject({}) { |hsh, (k, v)| hsh[v] = k; hsh }
|
58
|
+
|
59
|
+
# See http://www.w3.org/TR/REC-xml/#charsets for details.
|
60
|
+
VALID = [
|
61
|
+
0x9, 0xA, 0xD,
|
62
|
+
(0x20..0xD7FF),
|
63
|
+
(0xE000..0xFFFD),
|
64
|
+
(0x10000..0x10FFFF)
|
65
|
+
]
|
66
|
+
end
|
67
|
+
|
68
|
+
class << self
|
69
|
+
# XML escaped version of chr
|
70
|
+
def xchr(str)
|
71
|
+
n = XChar::CP1252[str] || str
|
72
|
+
case n when *XChar::VALID
|
73
|
+
XChar::PREDEFINED[n] or (n<128 ? n.chr : "&##{n};")
|
74
|
+
else
|
75
|
+
'*'
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# XML escaped version of to_s
|
80
|
+
def xs(str)
|
81
|
+
str.to_s.unpack('U*').map {|n| xchr(n)}.join # ASCII, UTF-8
|
82
|
+
rescue
|
83
|
+
str.to_s.unpack('C*').map {|n| xchr(n)}.join # ISO-8859-1, WIN-1252
|
84
|
+
end
|
85
|
+
|
86
|
+
# XML unescape
|
87
|
+
def uxs(str)
|
88
|
+
str.to_s.
|
89
|
+
gsub(/\&\w+;/) { |x| (XChar::PREDEFINED_U[x] || ??).chr }.
|
90
|
+
gsub(/\&\#(\d+);/) { [$1.to_i].pack("U*") }
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
data/lib/green_shoes.rb
CHANGED
@@ -45,3 +45,4 @@ require_relative 'shoes/manual'
|
|
45
45
|
autoload :ChipMunk, File.join(Shoes::DIR, 'ext/chipmunk')
|
46
46
|
autoload :Bloops, File.join(Shoes::DIR, 'ext/bloops')
|
47
47
|
autoload :Projector, File.join(Shoes::DIR, 'ext/projector')
|
48
|
+
autoload :Hpricot, File.join(Shoes::DIR, 'ext/hpricot')
|
data/lib/shoes/app.rb
CHANGED
@@ -237,7 +237,7 @@ class Shoes
|
|
237
237
|
end if block_given?
|
238
238
|
|
239
239
|
@canvas.put eb, args[:left], args[:top]
|
240
|
-
eb.
|
240
|
+
eb.show_all
|
241
241
|
args[:real], args[:app], args[:textview] = eb, self, tv
|
242
242
|
@_eb = EditBox.new args
|
243
243
|
end
|
@@ -520,6 +520,22 @@ class Shoes
|
|
520
520
|
shapebase Star, args
|
521
521
|
end
|
522
522
|
|
523
|
+
def arrow *attrs
|
524
|
+
args = attrs.last.class == Hash ? attrs.pop : {}
|
525
|
+
w = attrs[2]
|
526
|
+
args.merge!({left: attrs[0], top: attrs[1], width: w, height: w})
|
527
|
+
shape args do
|
528
|
+
move_to 0, w*0.5*0.6
|
529
|
+
line_to w*0.58, w*0.5*0.6
|
530
|
+
line_to w*0.58, w*0.5*0.2
|
531
|
+
line_to w, w*0.5
|
532
|
+
line_to w*0.58, w*(1-0.5*0.2)
|
533
|
+
line_to w*0.58, w*(1-0.5*0.6)
|
534
|
+
line_to 0, w*(1-0.5*0.6)
|
535
|
+
line_to 0, w*0.5*0.6
|
536
|
+
end
|
537
|
+
end
|
538
|
+
|
523
539
|
def rotate angle
|
524
540
|
@pixbuf_rotate, angle = angle.divmod(90)
|
525
541
|
@pixbuf_rotate %= 4
|
data/lib/shoes/help.rb
CHANGED
@@ -2,6 +2,8 @@ class Manual < Shoes
|
|
2
2
|
url '/', :index
|
3
3
|
url '/manual/(\d+)', :index
|
4
4
|
|
5
|
+
include Hpricot
|
6
|
+
|
5
7
|
def index pnum = 0
|
6
8
|
font LANG == 'ja' ? 'MS UI Gothic' : 'Arial'
|
7
9
|
style Link, underline: false, weight: 'bold'
|
@@ -13,6 +15,7 @@ class Manual < Shoes
|
|
13
15
|
|
14
16
|
def get_title_and_desc pnum
|
15
17
|
chapter, section = PNUMS[pnum]
|
18
|
+
return nil unless chapter
|
16
19
|
if section
|
17
20
|
[pnum, DOCS[chapter][1][:sections][section][1][:title],
|
18
21
|
DOCS[chapter][1][:sections][section][1][:description],
|
@@ -45,6 +48,7 @@ class Manual < Shoes
|
|
45
48
|
stack{para NL * 4}
|
46
49
|
flow width: 0.2, margin_left: 10 do
|
47
50
|
para *TOC
|
51
|
+
para link(fg 'to_html', darkmagenta){html_manual}
|
48
52
|
end
|
49
53
|
|
50
54
|
flow width: 0.8, margin: [10, 0, 20, 0] do
|
@@ -76,11 +80,11 @@ class Manual < Shoes
|
|
76
80
|
text.gsub CODE_RE do |lines|
|
77
81
|
lines = lines.split NL
|
78
82
|
n = lines[1] =~ /\#\!ruby/ ? 2 : 1
|
79
|
-
|
83
|
+
_code = lines[n...-1].join(NL+' ')
|
80
84
|
flow do
|
81
85
|
background rgb(190, 190, 190), curve: 5
|
82
|
-
inscription link(fg('Run this', green)){eval mk_executable(
|
83
|
-
para ' '
|
86
|
+
inscription link(fg('Run this', green)){eval mk_executable(_code), TOPLEVEL_BINDING}, margin_left: 480
|
87
|
+
para fg(code(' ' + _code), maroon), NL, margin_left: -10
|
84
88
|
end
|
85
89
|
para
|
86
90
|
end
|
@@ -138,7 +142,7 @@ class Manual < Shoes
|
|
138
142
|
end
|
139
143
|
|
140
144
|
def color_page
|
141
|
-
|
145
|
+
COLORS.each do |color, v|
|
142
146
|
r, g, b = v
|
143
147
|
c = v.dark? ? white : black
|
144
148
|
flow width: 0.33 do
|
@@ -151,15 +155,7 @@ class Manual < Shoes
|
|
151
155
|
end
|
152
156
|
|
153
157
|
def sample_page
|
154
|
-
|
155
|
-
orig_name = File.basename file
|
156
|
-
dummy_name = orig_name.sub(/sample(.*)\.rb/){
|
157
|
-
first, second = $1.split('-')
|
158
|
-
"%02d%s%s" % [first.to_i, ('-' if second), second]
|
159
|
-
}
|
160
|
-
[dummy_name, orig_name]
|
161
|
-
end
|
162
|
-
names.sort.map(&:last).each do |file|
|
158
|
+
mk_sample_names.each do |file|
|
163
159
|
stack width: 80 do
|
164
160
|
inscription file[0...-3]
|
165
161
|
img = image File.join(DIR, "../snapshots/#{file[0..-3]}png"), width: 50, height: 50
|
@@ -168,6 +164,17 @@ class Manual < Shoes
|
|
168
164
|
end
|
169
165
|
end
|
170
166
|
end
|
167
|
+
|
168
|
+
def mk_sample_names
|
169
|
+
Dir[File.join(DIR, '../samples/sample*.rb')].map do |file|
|
170
|
+
orig_name = File.basename file
|
171
|
+
dummy_name = orig_name.sub(/sample(.*)\.rb/){
|
172
|
+
first, second = $1.split('-')
|
173
|
+
"%02d%s%s" % [first.to_i, ('-' if second), second]
|
174
|
+
}
|
175
|
+
[dummy_name, orig_name]
|
176
|
+
end.sort.map &:last
|
177
|
+
end
|
171
178
|
|
172
179
|
def find_pnum page
|
173
180
|
TOC_LIST.each_with_index do |e, i|
|
@@ -203,6 +210,154 @@ class Manual < Shoes
|
|
203
210
|
pnum
|
204
211
|
end
|
205
212
|
|
213
|
+
def html_manual
|
214
|
+
dir = ask_save_folder
|
215
|
+
return unless dir
|
216
|
+
FileUtils.mkdir_p File.join(dir, 'static')
|
217
|
+
FileUtils.mkdir_p File.join(dir, 'snapshots')
|
218
|
+
%w[gshoes-icon.png shoes-manual-apps.png manual.css code_highlighter.js code_highlighter_ruby.js].
|
219
|
+
each{|x| FileUtils.cp "#{DIR}/../static/#{x}", "#{dir}/static"}
|
220
|
+
Dir[File.join DIR, '../static/man-*.png'].each{|x| FileUtils.cp x, "#{dir}/static"}
|
221
|
+
Dir[File.join DIR, '../snapshots/sample*.png'].each{|x| FileUtils.cp x, "#{dir}/snapshots"}
|
222
|
+
|
223
|
+
TOC_LIST.length.times do |n|
|
224
|
+
num, title, desc, methods = get_title_and_desc n
|
225
|
+
open File.join(dir, "#{TOC_LIST[n][0]}.html"), 'w' do |f|
|
226
|
+
f.puts mk_html(title, desc, methods, TOC_LIST[n+1], get_title_and_desc(n+1), mk_sidebar_list(num))
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
def mk_html title, desc, methods, next_file, next_title, menu
|
232
|
+
man = self
|
233
|
+
Hpricot do
|
234
|
+
xhtml_transitional do
|
235
|
+
head do
|
236
|
+
meta :"http-equiv" => "Content-Type", "content" => "text/html; charset=utf-8"
|
237
|
+
title "The Green Shoes Manual // #{title}"
|
238
|
+
script type: "text/javascript", src: "static/code_highlighter.js"
|
239
|
+
script type: "text/javascript", src: "static/code_highlighter_ruby.js"
|
240
|
+
style type: "text/css" do
|
241
|
+
text "@import 'static/manual.css';"
|
242
|
+
end
|
243
|
+
end
|
244
|
+
body do
|
245
|
+
div.main! do
|
246
|
+
div.manual! do
|
247
|
+
h2 "The Green Shoes Manual #{VERSION}"
|
248
|
+
h1 title
|
249
|
+
|
250
|
+
paras = man.mk_paras desc
|
251
|
+
div.intro{p man.manual_p(paras.shift)}
|
252
|
+
|
253
|
+
html_paragraph = proc do
|
254
|
+
paras.each do |str|
|
255
|
+
if str =~ CODE_RE
|
256
|
+
pre{code.rb $1.gsub(/^\s*?\n/, '')}
|
257
|
+
else
|
258
|
+
cmd, str = case str
|
259
|
+
when /\A==== (.+) ====/; [:h4, $1]
|
260
|
+
when /\A=== (.+) ===/; [:h3, $1]
|
261
|
+
when /\A== (.+) ==/; [:h2, $1]
|
262
|
+
when /\A= (.+) =/; [:h1, $1]
|
263
|
+
when /\A\{COLORS\}/
|
264
|
+
COLORS.each do |color, v|
|
265
|
+
f = v.dark? ? "white" : "black"
|
266
|
+
div.color(style: "background: #{color}; color: #{f}"){h3 color; p("rgb(%d, %d, %d)" % v)}
|
267
|
+
end
|
268
|
+
when /\A\{SAMPLES\}/
|
269
|
+
man.mk_sample_names.each do |name|
|
270
|
+
name = name[0...-3]
|
271
|
+
div.sample do
|
272
|
+
h3 name
|
273
|
+
p '<a href="snapshots/%s.png"><img src="snapshots/%s.png" alt="%s" border=0 width=50 height=50></a>' % [name, name, name]
|
274
|
+
end
|
275
|
+
end
|
276
|
+
when /\A \* (.+)/m
|
277
|
+
ul{$1.split(/^ \* /).each{|x| li{self << man.manual_p(x)}}}
|
278
|
+
else
|
279
|
+
[:p, str]
|
280
|
+
end
|
281
|
+
send(cmd){self << man.manual_p(str)} if cmd.is_a?(Symbol)
|
282
|
+
end
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
html_paragraph.call
|
287
|
+
|
288
|
+
methods.each do |m, d|
|
289
|
+
n = m.index("\u00BB")
|
290
|
+
n ? (sig, val = m[0...n-1], m[n-1..-1]) : (sig, val = m, nil)
|
291
|
+
aname = sig[/^[^(=]+=?/].gsub(/\s/, '').downcase
|
292
|
+
a name: aname
|
293
|
+
div.method do
|
294
|
+
a sig, href: "##{aname}"
|
295
|
+
text val if val
|
296
|
+
end
|
297
|
+
div.desc do
|
298
|
+
paras = man.mk_paras d
|
299
|
+
html_paragraph.call
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
p.next{text "Next: "; a next_title[1], href: "#{next_file[0]}.html"} if next_title
|
304
|
+
end
|
305
|
+
div.sidebar do
|
306
|
+
img src: "static/gshoes-icon.png"
|
307
|
+
ul do
|
308
|
+
li{a.prime "HELP", href: "./"}
|
309
|
+
menu.each do |m|
|
310
|
+
li do
|
311
|
+
unless m.is_a?(Array)
|
312
|
+
a m, href: "#{m}.html"
|
313
|
+
else
|
314
|
+
ul.sub do
|
315
|
+
m.each do |sm|
|
316
|
+
li{a sm, href: "#{sm}.html"}
|
317
|
+
end
|
318
|
+
end
|
319
|
+
end
|
320
|
+
end
|
321
|
+
end
|
322
|
+
end
|
323
|
+
end
|
324
|
+
end
|
325
|
+
end
|
326
|
+
end
|
327
|
+
end.to_html
|
328
|
+
end
|
329
|
+
|
330
|
+
def mk_sidebar_list num
|
331
|
+
toc = []
|
332
|
+
[0..3, 4..9, 10..16, 17..32, 33..35].each do |r|
|
333
|
+
toc.push TOC_LIST[r.first][0]
|
334
|
+
toc.push(TOC_LIST[r.first+1..r.last].to_a.map &:first) if r.include?(num)
|
335
|
+
end
|
336
|
+
toc
|
337
|
+
end
|
338
|
+
|
339
|
+
def manual_p str
|
340
|
+
str.gsub(/\n+\s*/, " ").
|
341
|
+
gsub(/&/, '&').gsub(/>/, '>').gsub(/>/, '<').gsub(/"/, '"').
|
342
|
+
gsub(/`(.+?)`/m, '<code>\1</code>').gsub(/\[\[BR\]\]/i, "<br />\n").
|
343
|
+
gsub(/\^(.+?)\^/m, '\1').
|
344
|
+
gsub(/'''(.+?)'''/m, '<strong>\1</strong>').gsub(/''(.+?)''/m, '<em>\1</em>').
|
345
|
+
gsub(/\[\[((http|https):\/\/\S+?)\]\]/m, '<a href="\1" target="_new">\1</a>').
|
346
|
+
gsub(/\[\[((http|https):\/\/\S+?) (.+?)\]\]/m, '<a href="\1" target="_new">\3</a>').
|
347
|
+
gsub(/\[\[(\S+?)\]\]/m) do
|
348
|
+
ms, mn = $1.split(".", 2)
|
349
|
+
if mn
|
350
|
+
'<a href="' + ms + '.html#' + mn + '">' + mn + '</a>'
|
351
|
+
else
|
352
|
+
'<a href="' + ms + '.html">' + ms + '</a>'
|
353
|
+
end
|
354
|
+
end.
|
355
|
+
gsub(/\[\[(\S+?) (.+?)\]\]/m, '<a href="\1.html">\2</a>').
|
356
|
+
gsub(/\!(\{[^}\n]+\})?([^!\n]+\.\w+)\!/) do
|
357
|
+
'<img src="' + "static/#$2" + '" />'
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
206
361
|
IMAGE_RE = /\!(\{([^}\n]+)\})?([^!\n]+\.\w+)\!/
|
207
362
|
CODE_RE = /\{{3}(?:\s*\#![^\n]+)?(.+?)\}{3}/m
|
208
363
|
NL = "\n"
|
@@ -0,0 +1,188 @@
|
|
1
|
+
/* Unobtrustive Code Highlighter By Dan Webb 11/2005
|
2
|
+
Version: 0.4
|
3
|
+
|
4
|
+
Usage:
|
5
|
+
Add a script tag for this script and any stylesets you need to use
|
6
|
+
to the page in question, add correct class names to CODE elements,
|
7
|
+
define CSS styles for elements. That's it!
|
8
|
+
|
9
|
+
Known to work on:
|
10
|
+
IE 5.5+ PC
|
11
|
+
Firefox/Mozilla PC/Mac
|
12
|
+
Opera 7.23 + PC
|
13
|
+
Safari 2
|
14
|
+
|
15
|
+
Known to degrade gracefully on:
|
16
|
+
IE5.0 PC
|
17
|
+
|
18
|
+
Note: IE5.0 fails due to the use of lookahead in some stylesets. To avoid script errors
|
19
|
+
in older browsers use expressions that use lookahead in string format when defining stylesets.
|
20
|
+
|
21
|
+
This script is inspired by star-light by entirely cunning Dean Edwards
|
22
|
+
http://dean.edwards.name/star-light/.
|
23
|
+
*/
|
24
|
+
|
25
|
+
// replace callback support for safari.
|
26
|
+
if ("a".replace(/a/, function() {return "b"}) != "b") (function(){
|
27
|
+
var default_replace = String.prototype.replace;
|
28
|
+
String.prototype.replace = function(search,replace){
|
29
|
+
// replace is not function
|
30
|
+
if(typeof replace != "function"){
|
31
|
+
return default_replace.apply(this,arguments)
|
32
|
+
}
|
33
|
+
var str = "" + this;
|
34
|
+
var callback = replace;
|
35
|
+
// search string is not RegExp
|
36
|
+
if(!(search instanceof RegExp)){
|
37
|
+
var idx = str.indexOf(search);
|
38
|
+
return (
|
39
|
+
idx == -1 ? str :
|
40
|
+
default_replace.apply(str,[search,callback(search, idx, str)])
|
41
|
+
)
|
42
|
+
}
|
43
|
+
var reg = search;
|
44
|
+
var result = [];
|
45
|
+
var lastidx = reg.lastIndex;
|
46
|
+
var re;
|
47
|
+
while((re = reg.exec(str)) != null){
|
48
|
+
var idx = re.index;
|
49
|
+
var args = re.concat(idx, str);
|
50
|
+
result.push(
|
51
|
+
str.slice(lastidx,idx),
|
52
|
+
callback.apply(null,args).toString()
|
53
|
+
);
|
54
|
+
if(!reg.global){
|
55
|
+
lastidx += RegExp.lastMatch.length;
|
56
|
+
break
|
57
|
+
}else{
|
58
|
+
lastidx = reg.lastIndex;
|
59
|
+
}
|
60
|
+
}
|
61
|
+
result.push(str.slice(lastidx));
|
62
|
+
return result.join("")
|
63
|
+
}
|
64
|
+
})();
|
65
|
+
|
66
|
+
var CodeHighlighter = { styleSets : new Array };
|
67
|
+
|
68
|
+
CodeHighlighter.addStyle = function(name, rules) {
|
69
|
+
// using push test to disallow older browsers from adding styleSets
|
70
|
+
if ([].push) this.styleSets.push({
|
71
|
+
name : name,
|
72
|
+
rules : rules,
|
73
|
+
ignoreCase : arguments[2] || false
|
74
|
+
})
|
75
|
+
|
76
|
+
function setEvent() {
|
77
|
+
// set highlighter to run on load (use LowPro if present)
|
78
|
+
if (typeof Event != 'undefined' && typeof Event.onReady == 'function')
|
79
|
+
return Event.onReady(CodeHighlighter.init.bind(CodeHighlighter));
|
80
|
+
|
81
|
+
var old = window.onload;
|
82
|
+
|
83
|
+
if (typeof window.onload != 'function') {
|
84
|
+
window.onload = function() { CodeHighlighter.init() };
|
85
|
+
} else {
|
86
|
+
window.onload = function() {
|
87
|
+
old();
|
88
|
+
CodeHighlighter.init();
|
89
|
+
}
|
90
|
+
}
|
91
|
+
}
|
92
|
+
|
93
|
+
// only set the event when the first style is added
|
94
|
+
if (this.styleSets.length==1) setEvent();
|
95
|
+
}
|
96
|
+
|
97
|
+
CodeHighlighter.init = function() {
|
98
|
+
if (!document.getElementsByTagName) return;
|
99
|
+
if ("a".replace(/a/, function() {return "b"}) != "b") return; // throw out Safari versions that don't support replace function
|
100
|
+
// throw out older browsers
|
101
|
+
|
102
|
+
var codeEls = document.getElementsByTagName("CODE");
|
103
|
+
// collect array of all pre elements
|
104
|
+
codeEls.filter = function(f) {
|
105
|
+
var a = new Array;
|
106
|
+
for (var i = 0; i < this.length; i++) if (f(this[i])) a[a.length] = this[i];
|
107
|
+
return a;
|
108
|
+
}
|
109
|
+
|
110
|
+
var rules = new Array;
|
111
|
+
rules.toString = function() {
|
112
|
+
// joins regexes into one big parallel regex
|
113
|
+
var exps = new Array;
|
114
|
+
for (var i = 0; i < this.length; i++) exps.push(this[i].exp);
|
115
|
+
return exps.join("|");
|
116
|
+
}
|
117
|
+
|
118
|
+
function addRule(className, rule) {
|
119
|
+
// add a replace rule
|
120
|
+
var exp = (typeof rule.exp != "string")?String(rule.exp).substr(1, String(rule.exp).length-2):rule.exp;
|
121
|
+
// converts regex rules to strings and chops of the slashes
|
122
|
+
rules.push({
|
123
|
+
className : className,
|
124
|
+
exp : "(" + exp + ")",
|
125
|
+
length : (exp.match(/(^|[^\\])\([^?]/g) || "").length + 1, // number of subexps in rule
|
126
|
+
replacement : rule.replacement || null
|
127
|
+
});
|
128
|
+
}
|
129
|
+
|
130
|
+
function parse(text, ignoreCase) {
|
131
|
+
// main text parsing and replacement
|
132
|
+
return text.replace(new RegExp(rules, (ignoreCase)?"gi":"g"), function() {
|
133
|
+
var i = 0, j = 1, rule;
|
134
|
+
while (rule = rules[i++]) {
|
135
|
+
if (arguments[j]) {
|
136
|
+
// if no custom replacement defined do the simple replacement
|
137
|
+
if (!rule.replacement) return "<span class=\"" + rule.className + "\">" + arguments[0] + "</span>";
|
138
|
+
else {
|
139
|
+
// replace $0 with the className then do normal replaces
|
140
|
+
var str = rule.replacement.replace("$0", rule.className);
|
141
|
+
for (var k = 1; k <= rule.length - 1; k++) str = str.replace("$" + k, arguments[j + k]);
|
142
|
+
return str;
|
143
|
+
}
|
144
|
+
} else j+= rule.length;
|
145
|
+
}
|
146
|
+
});
|
147
|
+
}
|
148
|
+
|
149
|
+
function highlightCode(styleSet) {
|
150
|
+
// clear rules array
|
151
|
+
var parsed, clsRx = new RegExp("(\\s|^)" + styleSet.name + "(\\s|$)");
|
152
|
+
rules.length = 0;
|
153
|
+
|
154
|
+
// get stylable elements by filtering out all code elements without the correct className
|
155
|
+
var stylableEls = codeEls.filter(function(item) { return clsRx.test(item.className) });
|
156
|
+
|
157
|
+
// add style rules to parser
|
158
|
+
for (var className in styleSet.rules) addRule(className, styleSet.rules[className]);
|
159
|
+
|
160
|
+
|
161
|
+
// replace for all elements
|
162
|
+
for (var i = 0; i < stylableEls.length; i++) {
|
163
|
+
// EVIL hack to fix IE whitespace badness if it's inside a <pre>
|
164
|
+
if (/MSIE/.test(navigator.appVersion) && stylableEls[i].parentNode.nodeName == 'PRE') {
|
165
|
+
stylableEls[i] = stylableEls[i].parentNode;
|
166
|
+
|
167
|
+
parsed = stylableEls[i].innerHTML.replace(/(<code[^>]*>)([^<]*)<\/code>/i, function() {
|
168
|
+
return arguments[1] + parse(arguments[2], styleSet.ignoreCase) + "</code>"
|
169
|
+
});
|
170
|
+
parsed = parsed.replace(/\n( *)/g, function() {
|
171
|
+
var spaces = "";
|
172
|
+
for (var i = 0; i < arguments[1].length; i++) spaces+= " ";
|
173
|
+
return "\n" + spaces;
|
174
|
+
});
|
175
|
+
parsed = parsed.replace(/\t/g, " ");
|
176
|
+
parsed = parsed.replace(/\n(<\/\w+>)?/g, "<br />$1").replace(/<br \/>[\n\r\s]*<br \/>/g, "<p><br></p>");
|
177
|
+
|
178
|
+
} else parsed = parse(stylableEls[i].innerHTML, styleSet.ignoreCase);
|
179
|
+
|
180
|
+
stylableEls[i].innerHTML = parsed;
|
181
|
+
}
|
182
|
+
}
|
183
|
+
|
184
|
+
// run highlighter on all stylesets
|
185
|
+
for (var i=0; i < this.styleSets.length; i++) {
|
186
|
+
highlightCode(this.styleSets[i]);
|
187
|
+
}
|
188
|
+
}
|