~michaelforrest/use-case-mapper/trunk

« back to all changes in this revision

Viewing changes to vendor/rails/railties/guides/files/javascripts/code_highlighter.js

  • Committer: Richard Lee (Canonical)
  • Date: 2010-10-15 15:17:58 UTC
  • mfrom: (190.1.3 use-case-mapper)
  • Revision ID: richard.lee@canonical.com-20101015151758-wcvmfxrexsongf9d
Merge

Show diffs side-by-side

added added

removed removed

Lines of Context:
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+= "&nbsp;";
173
 
                                        return "\n" + spaces;
174
 
                                });
175
 
                                parsed = parsed.replace(/\t/g, "&nbsp;&nbsp;&nbsp;&nbsp;");
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
 
}