Mercurial > zeropaste
comparison vendor/assets/javascripts/prettify.js @ 220:183e8560a337
Update prettify to 2013/03/04.
author | Edho Arief <edho@myconan.net> |
---|---|
date | Sun, 12 May 2013 12:05:08 +0900 |
parents | 56c4cd16d849 |
children |
comparison
equal
deleted
inserted
replaced
219:56c4cd16d849 | 220:183e8560a337 |
---|---|
51 * </blockquote> | 51 * </blockquote> |
52 * @requires console | 52 * @requires console |
53 */ | 53 */ |
54 | 54 |
55 // JSLint declarations | 55 // JSLint declarations |
56 /*global console, document, navigator, setTimeout, window */ | 56 /*global console, document, navigator, setTimeout, window, define */ |
57 | |
58 /** @define {boolean} */ | |
59 var IN_GLOBAL_SCOPE = true; | |
57 | 60 |
58 /** | 61 /** |
59 * Split {@code prettyPrint} into multiple timeouts so as not to interfere with | 62 * Split {@code prettyPrint} into multiple timeouts so as not to interfere with |
60 * UI events. | 63 * UI events. |
61 * If set to {@code false}, {@code prettyPrint()} is synchronous. | 64 * If set to {@code false}, {@code prettyPrint()} is synchronous. |
62 */ | 65 */ |
63 window['PR_SHOULD_USE_CONTINUATION'] = true; | 66 window['PR_SHOULD_USE_CONTINUATION'] = true; |
64 | 67 |
68 /** | |
69 * Pretty print a chunk of code. | |
70 * @param {string} sourceCodeHtml The HTML to pretty print. | |
71 * @param {string} opt_langExtension The language name to use. | |
72 * Typically, a filename extension like 'cpp' or 'java'. | |
73 * @param {number|boolean} opt_numberLines True to number lines, | |
74 * or the 1-indexed number of the first line in sourceCodeHtml. | |
75 * @return {string} code as html, but prettier | |
76 */ | |
77 var prettyPrintOne; | |
78 /** | |
79 * Find all the {@code <pre>} and {@code <code>} tags in the DOM with | |
80 * {@code class=prettyprint} and prettify them. | |
81 * | |
82 * @param {Function} opt_whenDone called when prettifying is done. | |
83 * @param {HTMLElement|HTMLDocument} opt_root an element or document | |
84 * containing all the elements to pretty print. | |
85 * Defaults to {@code document.body}. | |
86 */ | |
87 var prettyPrint; | |
88 | |
89 | |
65 (function () { | 90 (function () { |
91 var win = window; | |
66 // Keyword lists for various languages. | 92 // Keyword lists for various languages. |
67 // We use things that coerce to strings to make them compact when minified | 93 // We use things that coerce to strings to make them compact when minified |
68 // and to defeat aggressive optimizers that fold large string constants. | 94 // and to defeat aggressive optimizers that fold large string constants. |
69 var FLOW_CONTROL_KEYWORDS = ["break,continue,do,else,for,if,return,while"]; | 95 var FLOW_CONTROL_KEYWORDS = ["break,continue,do,else,for,if,return,while"]; |
70 var C_KEYWORDS = [FLOW_CONTROL_KEYWORDS,"auto,case,char,const,default," + | 96 var C_KEYWORDS = [FLOW_CONTROL_KEYWORDS,"auto,case,char,const,default," + |
71 "double,enum,extern,float,goto,int,long,register,short,signed,sizeof," + | 97 "double,enum,extern,float,goto,inline,int,long,register,short,signed," + |
72 "static,struct,switch,typedef,union,unsigned,void,volatile"]; | 98 "sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"]; |
73 var COMMON_KEYWORDS = [C_KEYWORDS,"catch,class,delete,false,import," + | 99 var COMMON_KEYWORDS = [C_KEYWORDS,"catch,class,delete,false,import," + |
74 "new,operator,private,protected,public,this,throw,true,try,typeof"]; | 100 "new,operator,private,protected,public,this,throw,true,try,typeof"]; |
75 var CPP_KEYWORDS = [COMMON_KEYWORDS,"alignof,align_union,asm,axiom,bool," + | 101 var CPP_KEYWORDS = [COMMON_KEYWORDS,"alignof,align_union,asm,axiom,bool," + |
76 "concept,concept_map,const_cast,constexpr,decltype," + | 102 "concept,concept_map,const_cast,constexpr,decltype,delegate," + |
77 "dynamic_cast,explicit,export,friend,inline,late_check," + | 103 "dynamic_cast,explicit,export,friend,generic,late_check," + |
78 "mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast," + | 104 "mutable,namespace,nullptr,property,reinterpret_cast,static_assert," + |
79 "template,typeid,typename,using,virtual,where"]; | 105 "static_cast,template,typeid,typename,using,virtual,where"]; |
80 var JAVA_KEYWORDS = [COMMON_KEYWORDS, | 106 var JAVA_KEYWORDS = [COMMON_KEYWORDS, |
81 "abstract,boolean,byte,extends,final,finally,implements,import," + | 107 "abstract,assert,boolean,byte,extends,final,finally,implements,import," + |
82 "instanceof,null,native,package,strictfp,super,synchronized,throws," + | 108 "instanceof,interface,null,native,package,strictfp,super,synchronized," + |
83 "transient"]; | 109 "throws,transient"]; |
84 var CSHARP_KEYWORDS = [JAVA_KEYWORDS, | 110 var CSHARP_KEYWORDS = [JAVA_KEYWORDS, |
85 "as,base,by,checked,decimal,delegate,descending,dynamic,event," + | 111 "as,base,by,checked,decimal,delegate,descending,dynamic,event," + |
86 "fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock," + | 112 "fixed,foreach,from,group,implicit,in,internal,into,is,let," + |
87 "object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed," + | 113 "lock,object,out,override,orderby,params,partial,readonly,ref,sbyte," + |
88 "stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"]; | 114 "sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort," + |
115 "var,virtual,where"]; | |
89 var COFFEE_KEYWORDS = "all,and,by,catch,class,else,extends,false,finally," + | 116 var COFFEE_KEYWORDS = "all,and,by,catch,class,else,extends,false,finally," + |
90 "for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then," + | 117 "for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then," + |
91 "true,try,unless,until,when,while,yes"; | 118 "throw,true,try,unless,until,when,while,yes"; |
92 var JSCRIPT_KEYWORDS = [COMMON_KEYWORDS, | 119 var JSCRIPT_KEYWORDS = [COMMON_KEYWORDS, |
93 "debugger,eval,export,function,get,null,set,undefined,var,with," + | 120 "debugger,eval,export,function,get,null,set,undefined,var,with," + |
94 "Infinity,NaN"]; | 121 "Infinity,NaN"]; |
95 var PERL_KEYWORDS = "caller,delete,die,do,dump,elsif,eval,exit,foreach,for," + | 122 var PERL_KEYWORDS = "caller,delete,die,do,dump,elsif,eval,exit,foreach,for," + |
96 "goto,if,import,last,local,my,next,no,our,print,package,redo,require," + | 123 "goto,if,import,last,local,my,next,no,our,print,package,redo,require," + |
101 "False,True,None"]; | 128 "False,True,None"]; |
102 var RUBY_KEYWORDS = [FLOW_CONTROL_KEYWORDS, "alias,and,begin,case,class," + | 129 var RUBY_KEYWORDS = [FLOW_CONTROL_KEYWORDS, "alias,and,begin,case,class," + |
103 "def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo," + | 130 "def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo," + |
104 "rescue,retry,self,super,then,true,undef,unless,until,when,yield," + | 131 "rescue,retry,self,super,then,true,undef,unless,until,when,yield," + |
105 "BEGIN,END"]; | 132 "BEGIN,END"]; |
133 var RUST_KEYWORDS = [FLOW_CONTROL_KEYWORDS, "as,assert,const,copy,drop," + | |
134 "enum,extern,fail,false,fn,impl,let,log,loop,match,mod,move,mut,priv," + | |
135 "pub,pure,ref,self,static,struct,true,trait,type,unsafe,use"]; | |
106 var SH_KEYWORDS = [FLOW_CONTROL_KEYWORDS, "case,done,elif,esac,eval,fi," + | 136 var SH_KEYWORDS = [FLOW_CONTROL_KEYWORDS, "case,done,elif,esac,eval,fi," + |
107 "function,in,local,set,then,until"]; | 137 "function,in,local,set,then,until"]; |
108 var ALL_KEYWORDS = [ | 138 var ALL_KEYWORDS = [ |
109 CPP_KEYWORDS, CSHARP_KEYWORDS, JSCRIPT_KEYWORDS, PERL_KEYWORDS + | 139 CPP_KEYWORDS, CSHARP_KEYWORDS, JSCRIPT_KEYWORDS, PERL_KEYWORDS, |
110 PYTHON_KEYWORDS, RUBY_KEYWORDS, SH_KEYWORDS]; | 140 PYTHON_KEYWORDS, RUBY_KEYWORDS, SH_KEYWORDS]; |
111 var C_TYPES = /^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/; | 141 var C_TYPES = /^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)\b/; |
112 | 142 |
113 // token style names. correspond to css classes | 143 // token style names. correspond to css classes |
114 /** | 144 /** |
115 * token style for a string literal | 145 * token style for a string literal |
116 * @const | 146 * @const |
140 * token style for a punctuation string. | 170 * token style for a punctuation string. |
141 * @const | 171 * @const |
142 */ | 172 */ |
143 var PR_PUNCTUATION = 'pun'; | 173 var PR_PUNCTUATION = 'pun'; |
144 /** | 174 /** |
145 * token style for a punctuation string. | 175 * token style for plain text. |
146 * @const | 176 * @const |
147 */ | 177 */ |
148 var PR_PLAIN = 'pln'; | 178 var PR_PLAIN = 'pln'; |
149 | 179 |
150 /** | 180 /** |
178 * embedding of line numbers within code listings. | 208 * embedding of line numbers within code listings. |
179 * @const | 209 * @const |
180 */ | 210 */ |
181 var PR_NOCODE = 'nocode'; | 211 var PR_NOCODE = 'nocode'; |
182 | 212 |
183 | 213 |
184 | 214 |
185 /** | 215 /** |
186 * A set of tokens that can precede a regular expression literal in | 216 * A set of tokens that can precede a regular expression literal in |
187 * javascript | 217 * javascript |
188 * http://web.archive.org/web/20070717142515/http://www.mozilla.org/js/language/js20/rationale/syntax.html | 218 * http://web.archive.org/web/20070717142515/http://www.mozilla.org/js/language/js20/rationale/syntax.html |
189 * has the full list, but I've removed ones that might be problematic when | 219 * has the full list, but I've removed ones that might be problematic when |
190 * seen in languages that don't support regular expression literals. | 220 * seen in languages that don't support regular expression literals. |
191 * | 221 * |
192 * <p>Specifically, I've removed any keywords that can't precede a regexp | 222 * <p>Specifically, I've removed any keywords that can't precede a regexp |
193 * literal in a syntactically legal javascript program, and I've removed the | 223 * literal in a syntactically legal javascript program, and I've removed the |
194 * "in" keyword since it's not a keyword in many languages, and might be used | 224 * "in" keyword since it's not a keyword in many languages, and might be used |
195 * as a count of inches. | 225 * as a count of inches. |
196 * | 226 * |
197 * <p>The link a above does not accurately describe EcmaScript rules since | 227 * <p>The link above does not accurately describe EcmaScript rules since |
198 * it fails to distinguish between (a=++/b/i) and (a++/b/i) but it works | 228 * it fails to distinguish between (a=++/b/i) and (a++/b/i) but it works |
199 * very well in practice. | 229 * very well in practice. |
200 * | 230 * |
201 * @private | 231 * @private |
202 * @const | 232 * @const |
203 */ | 233 */ |
204 var REGEXP_PRECEDER_PATTERN = '(?:^^\\.?|[+-]|\\!|\\!=|\\!==|\\#|\\%|\\%=|&|&&|&&=|&=|\\(|\\*|\\*=|\\+=|\\,|\\-=|\\->|\\/|\\/=|:|::|\\;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\@|\\[|\\^|\\^=|\\^\\^|\\^\\^=|\\{|\\||\\|=|\\|\\||\\|\\|=|\\~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*'; | 234 var REGEXP_PRECEDER_PATTERN = '(?:^^\\.?|[+-]|[!=]=?=?|\\#|%=?|&&?=?|\\(|\\*=?|[+\\-]=|->|\\/=?|::?|<<?=?|>>?>?=?|,|;|\\?|@|\\[|~|{|\\^\\^?=?|\\|\\|?=?|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*'; |
205 | 235 |
206 // CAVEAT: this does not properly handle the case where a regular | 236 // CAVEAT: this does not properly handle the case where a regular |
207 // expression immediately follows another since a regular expression may | 237 // expression immediately follows another since a regular expression may |
208 // have flags for case-sensitivity and the like. Having regexp tokens | 238 // have flags for case-sensitivity and the like. Having regexp tokens |
209 // adjacent is not valid in any language I'm aware of, so I'm punting. | 239 // adjacent is not valid in any language I'm aware of, so I'm punting. |
210 // TODO: maybe style special characters inside a regexp as punctuation. | 240 // TODO: maybe style special characters inside a regexp as punctuation. |
211 | |
212 | 241 |
213 /** | 242 /** |
214 * Given a group of {@link RegExp}s, returns a {@code RegExp} that globally | 243 * Given a group of {@link RegExp}s, returns a {@code RegExp} that globally |
215 * matches the union of the sets of strings matched by the input RegExp. | 244 * matches the union of the sets of strings matched by the input RegExp. |
216 * Since it matches globally, if the input strings have a start-of-input | 245 * Since it matches globally, if the input strings have a start-of-input |
265 function encodeEscape(charCode) { | 294 function encodeEscape(charCode) { |
266 if (charCode < 0x20) { | 295 if (charCode < 0x20) { |
267 return (charCode < 0x10 ? '\\x0' : '\\x') + charCode.toString(16); | 296 return (charCode < 0x10 ? '\\x0' : '\\x') + charCode.toString(16); |
268 } | 297 } |
269 var ch = String.fromCharCode(charCode); | 298 var ch = String.fromCharCode(charCode); |
270 if (ch === '\\' || ch === '-' || ch === '[' || ch === ']') { | 299 return (ch === '\\' || ch === '-' || ch === ']' || ch === '^') |
271 ch = '\\' + ch; | 300 ? "\\" + ch : ch; |
272 } | |
273 return ch; | |
274 } | 301 } |
275 | 302 |
276 function caseFoldCharset(charSet) { | 303 function caseFoldCharset(charSet) { |
277 var charsetParts = charSet.substring(1, charSet.length - 1).match( | 304 var charsetParts = charSet.substring(1, charSet.length - 1).match( |
278 new RegExp( | 305 new RegExp( |
282 + '|\\\\[0-7]{1,2}' | 309 + '|\\\\[0-7]{1,2}' |
283 + '|\\\\[\\s\\S]' | 310 + '|\\\\[\\s\\S]' |
284 + '|-' | 311 + '|-' |
285 + '|[^-\\\\]', | 312 + '|[^-\\\\]', |
286 'g')); | 313 'g')); |
287 var groups = []; | |
288 var ranges = []; | 314 var ranges = []; |
289 var inverse = charsetParts[0] === '^'; | 315 var inverse = charsetParts[0] === '^'; |
316 | |
317 var out = ['[']; | |
318 if (inverse) { out.push('^'); } | |
319 | |
290 for (var i = inverse ? 1 : 0, n = charsetParts.length; i < n; ++i) { | 320 for (var i = inverse ? 1 : 0, n = charsetParts.length; i < n; ++i) { |
291 var p = charsetParts[i]; | 321 var p = charsetParts[i]; |
292 if (/\\[bdsw]/i.test(p)) { // Don't muck with named groups. | 322 if (/\\[bdsw]/i.test(p)) { // Don't muck with named groups. |
293 groups.push(p); | 323 out.push(p); |
294 } else { | 324 } else { |
295 var start = decodeEscape(p); | 325 var start = decodeEscape(p); |
296 var end; | 326 var end; |
297 if (i + 2 < n && '-' === charsetParts[i + 1]) { | 327 if (i + 2 < n && '-' === charsetParts[i + 1]) { |
298 end = decodeEscape(charsetParts[i + 2]); | 328 end = decodeEscape(charsetParts[i + 2]); |
318 | 348 |
319 // [[1, 10], [3, 4], [8, 12], [14, 14], [16, 16], [17, 17]] | 349 // [[1, 10], [3, 4], [8, 12], [14, 14], [16, 16], [17, 17]] |
320 // -> [[1, 12], [14, 14], [16, 17]] | 350 // -> [[1, 12], [14, 14], [16, 17]] |
321 ranges.sort(function (a, b) { return (a[0] - b[0]) || (b[1] - a[1]); }); | 351 ranges.sort(function (a, b) { return (a[0] - b[0]) || (b[1] - a[1]); }); |
322 var consolidatedRanges = []; | 352 var consolidatedRanges = []; |
323 var lastRange = [NaN, NaN]; | 353 var lastRange = []; |
324 for (var i = 0; i < ranges.length; ++i) { | 354 for (var i = 0; i < ranges.length; ++i) { |
325 var range = ranges[i]; | 355 var range = ranges[i]; |
326 if (range[0] <= lastRange[1] + 1) { | 356 if (range[0] <= lastRange[1] + 1) { |
327 lastRange[1] = Math.max(lastRange[1], range[1]); | 357 lastRange[1] = Math.max(lastRange[1], range[1]); |
328 } else { | 358 } else { |
329 consolidatedRanges.push(lastRange = range); | 359 consolidatedRanges.push(lastRange = range); |
330 } | 360 } |
331 } | 361 } |
332 | 362 |
333 var out = ['[']; | |
334 if (inverse) { out.push('^'); } | |
335 out.push.apply(out, groups); | |
336 for (var i = 0; i < consolidatedRanges.length; ++i) { | 363 for (var i = 0; i < consolidatedRanges.length; ++i) { |
337 var range = consolidatedRanges[i]; | 364 var range = consolidatedRanges[i]; |
338 out.push(encodeEscape(range[0])); | 365 out.push(encodeEscape(range[0])); |
339 if (range[1] > range[0]) { | 366 if (range[1] > range[0]) { |
340 if (range[1] + 1 > range[0]) { out.push('-'); } | 367 if (range[1] + 1 > range[0]) { out.push('-'); } |
356 + '|\\\\u[A-Fa-f0-9]{4}' // a unicode escape | 383 + '|\\\\u[A-Fa-f0-9]{4}' // a unicode escape |
357 + '|\\\\x[A-Fa-f0-9]{2}' // a hex escape | 384 + '|\\\\x[A-Fa-f0-9]{2}' // a hex escape |
358 + '|\\\\[0-9]+' // a back-reference or octal escape | 385 + '|\\\\[0-9]+' // a back-reference or octal escape |
359 + '|\\\\[^ux0-9]' // other escape sequence | 386 + '|\\\\[^ux0-9]' // other escape sequence |
360 + '|\\(\\?[:!=]' // start of a non-capturing group | 387 + '|\\(\\?[:!=]' // start of a non-capturing group |
361 + '|[\\(\\)\\^]' // start/emd of a group, or line start | 388 + '|[\\(\\)\\^]' // start/end of a group, or line start |
362 + '|[^\\x5B\\x5C\\(\\)\\^]+' // run of other characters | 389 + '|[^\\x5B\\x5C\\(\\)\\^]+' // run of other characters |
363 + ')', | 390 + ')', |
364 'g')); | 391 'g')); |
365 var n = parts.length; | 392 var n = parts.length; |
366 | 393 |
376 if (p === '(') { | 403 if (p === '(') { |
377 // groups are 1-indexed, so max group index is count of '(' | 404 // groups are 1-indexed, so max group index is count of '(' |
378 ++groupIndex; | 405 ++groupIndex; |
379 } else if ('\\' === p.charAt(0)) { | 406 } else if ('\\' === p.charAt(0)) { |
380 var decimalValue = +p.substring(1); | 407 var decimalValue = +p.substring(1); |
381 if (decimalValue && decimalValue <= groupIndex) { | 408 if (decimalValue) { |
382 capturedGroups[decimalValue] = -1; | 409 if (decimalValue <= groupIndex) { |
410 capturedGroups[decimalValue] = -1; | |
411 } else { | |
412 // Replace with an unambiguous escape sequence so that | |
413 // an octal escape sequence does not turn into a backreference | |
414 // to a capturing group from an earlier regex. | |
415 parts[i] = encodeEscape(decimalValue); | |
416 } | |
383 } | 417 } |
384 } | 418 } |
385 } | 419 } |
386 | 420 |
387 // Renumber groups and reduce capturing groups to non-capturing groups | 421 // Renumber groups and reduce capturing groups to non-capturing groups |
393 } | 427 } |
394 for (var i = 0, groupIndex = 0; i < n; ++i) { | 428 for (var i = 0, groupIndex = 0; i < n; ++i) { |
395 var p = parts[i]; | 429 var p = parts[i]; |
396 if (p === '(') { | 430 if (p === '(') { |
397 ++groupIndex; | 431 ++groupIndex; |
398 if (capturedGroups[groupIndex] === undefined) { | 432 if (!capturedGroups[groupIndex]) { |
399 parts[i] = '(?:'; | 433 parts[i] = '(?:'; |
400 } | 434 } |
401 } else if ('\\' === p.charAt(0)) { | 435 } else if ('\\' === p.charAt(0)) { |
402 var decimalValue = +p.substring(1); | 436 var decimalValue = +p.substring(1); |
403 if (decimalValue && decimalValue <= groupIndex) { | 437 if (decimalValue && decimalValue <= groupIndex) { |
404 parts[i] = '\\' + capturedGroups[groupIndex]; | 438 parts[i] = '\\' + capturedGroups[decimalValue]; |
405 } | 439 } |
406 } | 440 } |
407 } | 441 } |
408 | 442 |
409 // Remove any prefix anchors so that the output will match anywhere. | 443 // Remove any prefix anchors so that the output will match anywhere. |
410 // ^^ really does mean an anchored match though. | 444 // ^^ really does mean an anchored match though. |
411 for (var i = 0, groupIndex = 0; i < n; ++i) { | 445 for (var i = 0; i < n; ++i) { |
412 if ('^' === parts[i] && '^' !== parts[i + 1]) { parts[i] = ''; } | 446 if ('^' === parts[i] && '^' !== parts[i + 1]) { parts[i] = ''; } |
413 } | 447 } |
414 | 448 |
415 // Expand letters to groups to handle mixing of case-sensitive and | 449 // Expand letters to groups to handle mixing of case-sensitive and |
416 // case-insensitive patterns if necessary. | 450 // case-insensitive patterns if necessary. |
443 '(?:' + allowAnywhereFoldCaseAndRenumberGroups(regex) + ')'); | 477 '(?:' + allowAnywhereFoldCaseAndRenumberGroups(regex) + ')'); |
444 } | 478 } |
445 | 479 |
446 return new RegExp(rewritten.join('|'), ignoreCase ? 'gi' : 'g'); | 480 return new RegExp(rewritten.join('|'), ignoreCase ? 'gi' : 'g'); |
447 } | 481 } |
448 | |
449 | 482 |
450 /** | 483 /** |
451 * Split markup into a string of source code and an array mapping ranges in | 484 * Split markup into a string of source code and an array mapping ranges in |
452 * that string to the text nodes in which they appear. | 485 * that string to the text nodes in which they appear. |
453 * | 486 * |
468 * <p> | 501 * <p> |
469 * It will produce the output:</p> | 502 * It will produce the output:</p> |
470 * <pre> | 503 * <pre> |
471 * { | 504 * { |
472 * sourceCode: "print 'Hello '\n + 'World';", | 505 * sourceCode: "print 'Hello '\n + 'World';", |
473 * // 1 2 | 506 * // 1 2 |
474 * // 012345678901234 5678901234567 | 507 * // 012345678901234 5678901234567 |
475 * spans: [0, #1, 6, #2, 14, #3, 15, #4] | 508 * spans: [0, #1, 6, #2, 14, #3, 15, #4] |
476 * } | 509 * } |
477 * </pre> | 510 * </pre> |
478 * <p> | 511 * <p> |
479 * where #1 is a reference to the {@code "print "} text node above, and so | 512 * where #1 is a reference to the {@code "print "} text node above, and so |
486 * that contain the text for those substrings. | 519 * that contain the text for those substrings. |
487 * Substrings continue until the next index or the end of the source. | 520 * Substrings continue until the next index or the end of the source. |
488 * </p> | 521 * </p> |
489 * | 522 * |
490 * @param {Node} node an HTML DOM subtree containing source-code. | 523 * @param {Node} node an HTML DOM subtree containing source-code. |
524 * @param {boolean} isPreformatted true if white-space in text nodes should | |
525 * be considered significant. | |
491 * @return {Object} source code and the text nodes in which they occur. | 526 * @return {Object} source code and the text nodes in which they occur. |
492 */ | 527 */ |
493 function extractSourceSpans(node) { | 528 function extractSourceSpans(node, isPreformatted) { |
494 var nocode = /(?:^|\s)nocode(?:\s|$)/; | 529 var nocode = /(?:^|\s)nocode(?:\s|$)/; |
495 | 530 |
496 var chunks = []; | 531 var chunks = []; |
497 var length = 0; | 532 var length = 0; |
498 var spans = []; | 533 var spans = []; |
499 var k = 0; | 534 var k = 0; |
500 | 535 |
501 var whitespace; | |
502 if (node.currentStyle) { | |
503 whitespace = node.currentStyle.whiteSpace; | |
504 } else if (window.getComputedStyle) { | |
505 whitespace = document.defaultView.getComputedStyle(node, null) | |
506 .getPropertyValue('white-space'); | |
507 } | |
508 var isPreformatted = whitespace && 'pre' === whitespace.substring(0, 3); | |
509 | |
510 function walk(node) { | 536 function walk(node) { |
511 switch (node.nodeType) { | 537 var type = node.nodeType; |
512 case 1: // Element | 538 if (type == 1) { // Element |
513 if (nocode.test(node.className)) { return; } | 539 if (nocode.test(node.className)) { return; } |
514 for (var child = node.firstChild; child; child = child.nextSibling) { | 540 for (var child = node.firstChild; child; child = child.nextSibling) { |
515 walk(child); | 541 walk(child); |
516 } | 542 } |
517 var nodeName = node.nodeName; | 543 var nodeName = node.nodeName.toLowerCase(); |
518 if ('BR' === nodeName || 'LI' === nodeName) { | 544 if ('br' === nodeName || 'li' === nodeName) { |
519 chunks[k] = '\n'; | 545 chunks[k] = '\n'; |
520 spans[k << 1] = length++; | 546 spans[k << 1] = length++; |
521 spans[(k++ << 1) | 1] = node; | 547 spans[(k++ << 1) | 1] = node; |
522 } | 548 } |
523 break; | 549 } else if (type == 3 || type == 4) { // Text |
524 case 3: case 4: // Text | 550 var text = node.nodeValue; |
525 var text = node.nodeValue; | 551 if (text.length) { |
526 if (text.length) { | 552 if (!isPreformatted) { |
527 if (!isPreformatted) { | 553 text = text.replace(/[ \t\r\n]+/g, ' '); |
528 text = text.replace(/[ \t\r\n]+/g, ' '); | 554 } else { |
529 } else { | 555 text = text.replace(/\r\n?/g, '\n'); // Normalize newlines. |
530 text = text.replace(/\r\n?/g, '\n'); // Normalize newlines. | 556 } |
531 } | 557 // TODO: handle tabs here? |
532 // TODO: handle tabs here? | 558 chunks[k] = text; |
533 chunks[k] = text; | 559 spans[k << 1] = length; |
534 spans[k << 1] = length; | 560 length += text.length; |
535 length += text.length; | 561 spans[(k++ << 1) | 1] = node; |
536 spans[(k++ << 1) | 1] = node; | 562 } |
537 } | |
538 break; | |
539 } | 563 } |
540 } | 564 } |
541 | 565 |
542 walk(node); | 566 walk(node); |
543 | 567 |
544 return { | 568 return { |
545 sourceCode: chunks.join('').replace(/\n$/, ''), | 569 sourceCode: chunks.join('').replace(/\n$/, ''), |
546 spans: spans | 570 spans: spans |
547 }; | 571 }; |
548 } | 572 } |
549 | |
550 | 573 |
551 /** | 574 /** |
552 * Apply the given language handler to sourceCode and add the resulting | 575 * Apply the given language handler to sourceCode and add the resulting |
553 * decorations to out. | 576 * decorations to out. |
554 * @param {number} basePos the index of sourceCode within the chunk of source | 577 * @param {number} basePos the index of sourceCode within the chunk of source |
810 shortcutStylePatterns.push( | 833 shortcutStylePatterns.push( |
811 [PR_COMMENT, /^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/, null, '#']); | 834 [PR_COMMENT, /^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/, null, '#']); |
812 } else { | 835 } else { |
813 // Stop C preprocessor declarations at an unclosed open comment | 836 // Stop C preprocessor declarations at an unclosed open comment |
814 shortcutStylePatterns.push( | 837 shortcutStylePatterns.push( |
815 [PR_COMMENT, /^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/, | 838 [PR_COMMENT, /^#(?:(?:define|e(?:l|nd)if|else|error|ifn?def|include|line|pragma|undef|warning)\b|[^\r\n]*)/, |
816 null, '#']); | 839 null, '#']); |
817 } | 840 } |
841 // #include <stdio.h> | |
818 fallthroughStylePatterns.push( | 842 fallthroughStylePatterns.push( |
819 [PR_STRING, | 843 [PR_STRING, |
820 /^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/, | 844 /^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h(?:h|pp|\+\+)?|[a-z]\w*)>/, |
821 null]); | 845 null]); |
822 } else { | 846 } else { |
823 shortcutStylePatterns.push([PR_COMMENT, /^#[^\r\n]*/, null, '#']); | 847 shortcutStylePatterns.push([PR_COMMENT, /^#[^\r\n]*/, null, '#']); |
824 } | 848 } |
825 } | 849 } |
826 if (options['cStyleComments']) { | 850 if (options['cStyleComments']) { |
827 fallthroughStylePatterns.push([PR_COMMENT, /^\/\/[^\r\n]*/, null]); | 851 fallthroughStylePatterns.push([PR_COMMENT, /^\/\/[^\r\n]*/, null]); |
828 fallthroughStylePatterns.push( | 852 fallthroughStylePatterns.push( |
829 [PR_COMMENT, /^\/\*[\s\S]*?(?:\*\/|$)/, null]); | 853 [PR_COMMENT, /^\/\*[\s\S]*?(?:\*\/|$)/, null]); |
830 } | 854 } |
831 if (options['regexLiterals']) { | 855 var regexLiterals = options['regexLiterals']; |
856 if (regexLiterals) { | |
857 /** | |
858 * @const | |
859 */ | |
860 var regexExcls = regexLiterals > 1 | |
861 ? '' // Multiline regex literals | |
862 : '\n\r'; | |
863 /** | |
864 * @const | |
865 */ | |
866 var regexAny = regexExcls ? '.' : '[\\S\\s]'; | |
832 /** | 867 /** |
833 * @const | 868 * @const |
834 */ | 869 */ |
835 var REGEX_LITERAL = ( | 870 var REGEX_LITERAL = ( |
836 // A regular expression literal starts with a slash that is | 871 // A regular expression literal starts with a slash that is |
837 // not followed by * or / so that it is not confused with | 872 // not followed by * or / so that it is not confused with |
838 // comments. | 873 // comments. |
839 '/(?=[^/*])' | 874 '/(?=[^/*' + regexExcls + '])' |
840 // and then contains any number of raw characters, | 875 // and then contains any number of raw characters, |
841 + '(?:[^/\\x5B\\x5C]' | 876 + '(?:[^/\\x5B\\x5C' + regexExcls + ']' |
842 // escape sequences (\x5C), | 877 // escape sequences (\x5C), |
843 + '|\\x5C[\\s\\S]' | 878 + '|\\x5C' + regexAny |
844 // or non-nesting character sets (\x5B\x5D); | 879 // or non-nesting character sets (\x5B\x5D); |
845 + '|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+' | 880 + '|\\x5B(?:[^\\x5C\\x5D' + regexExcls + ']' |
881 + '|\\x5C' + regexAny + ')*(?:\\x5D|$))+' | |
846 // finally closed by a /. | 882 // finally closed by a /. |
847 + '/'); | 883 + '/'); |
848 fallthroughStylePatterns.push( | 884 fallthroughStylePatterns.push( |
849 ['lang-regex', | 885 ['lang-regex', |
850 new RegExp('^' + REGEXP_PRECEDER_PATTERN + '(' + REGEX_LITERAL + ')') | 886 RegExp('^' + REGEXP_PRECEDER_PATTERN + '(' + REGEX_LITERAL + ')') |
851 ]); | 887 ]); |
852 } | 888 } |
853 | 889 |
854 var types = options['types']; | 890 var types = options['types']; |
855 if (types) { | 891 if (types) { |
863 new RegExp('^(?:' + keywords.replace(/[\s,]+/g, '|') + ')\\b'), | 899 new RegExp('^(?:' + keywords.replace(/[\s,]+/g, '|') + ')\\b'), |
864 null]); | 900 null]); |
865 } | 901 } |
866 | 902 |
867 shortcutStylePatterns.push([PR_PLAIN, /^\s+/, null, ' \r\n\t\xA0']); | 903 shortcutStylePatterns.push([PR_PLAIN, /^\s+/, null, ' \r\n\t\xA0']); |
904 | |
905 var punctuation = | |
906 // The Bash man page says | |
907 | |
908 // A word is a sequence of characters considered as a single | |
909 // unit by GRUB. Words are separated by metacharacters, | |
910 // which are the following plus space, tab, and newline: { } | |
911 // | & $ ; < > | |
912 // ... | |
913 | |
914 // A word beginning with # causes that word and all remaining | |
915 // characters on that line to be ignored. | |
916 | |
917 // which means that only a '#' after /(?:^|[{}|&$;<>\s])/ starts a | |
918 // comment but empirically | |
919 // $ echo {#} | |
920 // {#} | |
921 // $ echo \$# | |
922 // $# | |
923 // $ echo }# | |
924 // }# | |
925 | |
926 // so /(?:^|[|&;<>\s])/ is more appropriate. | |
927 | |
928 // http://gcc.gnu.org/onlinedocs/gcc-2.95.3/cpp_1.html#SEC3 | |
929 // suggests that this definition is compatible with a | |
930 // default mode that tries to use a single token definition | |
931 // to recognize both bash/python style comments and C | |
932 // preprocessor directives. | |
933 | |
934 // This definition of punctuation does not include # in the list of | |
935 // follow-on exclusions, so # will not be broken before if preceeded | |
936 // by a punctuation character. We could try to exclude # after | |
937 // [|&;<>] but that doesn't seem to cause many major problems. | |
938 // If that does turn out to be a problem, we should change the below | |
939 // when hc is truthy to include # in the run of punctuation characters | |
940 // only when not followint [|&;<>]. | |
941 '^.[^\\s\\w.$@\'"`/\\\\]*'; | |
942 if (options['regexLiterals']) { | |
943 punctuation += '(?!\s*\/)'; | |
944 } | |
945 | |
868 fallthroughStylePatterns.push( | 946 fallthroughStylePatterns.push( |
869 // TODO(mikesamuel): recognize non-latin letters and numerals in idents | 947 // TODO(mikesamuel): recognize non-latin letters and numerals in idents |
870 [PR_LITERAL, /^@[a-z_$][a-z_$@0-9]*/i, null], | 948 [PR_LITERAL, /^@[a-z_$][a-z_$@0-9]*/i, null], |
871 [PR_TYPE, /^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/, null], | 949 [PR_TYPE, /^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/, null], |
872 [PR_PLAIN, /^[a-z_$][a-z_$@0-9]*/i, null], | 950 [PR_PLAIN, /^[a-z_$][a-z_$@0-9]*/i, null], |
881 + '(?:e[+\\-]?\\d+)?' | 959 + '(?:e[+\\-]?\\d+)?' |
882 + ')' | 960 + ')' |
883 // with an optional modifier like UL for unsigned long | 961 // with an optional modifier like UL for unsigned long |
884 + '[a-z]*', 'i'), | 962 + '[a-z]*', 'i'), |
885 null, '0123456789'], | 963 null, '0123456789'], |
886 // Don't treat escaped quotes in bash as starting strings. See issue 144. | 964 // Don't treat escaped quotes in bash as starting strings. |
965 // See issue 144. | |
887 [PR_PLAIN, /^\\[\s\S]?/, null], | 966 [PR_PLAIN, /^\\[\s\S]?/, null], |
888 [PR_PUNCTUATION, /^.[^\s\w\.$@\'\"\`\/\#\\]*/, null]); | 967 [PR_PUNCTUATION, new RegExp(punctuation), null]); |
889 | 968 |
890 return createSimpleLexer(shortcutStylePatterns, fallthroughStylePatterns); | 969 return createSimpleLexer(shortcutStylePatterns, fallthroughStylePatterns); |
891 } | 970 } |
892 | 971 |
893 var decorateSource = sourceDecorator({ | 972 var decorateSource = sourceDecorator({ |
904 * | 983 * |
905 * @param {Node} node modified in place. Its content is pulled into an | 984 * @param {Node} node modified in place. Its content is pulled into an |
906 * HTMLOListElement, and each line is moved into a separate list item. | 985 * HTMLOListElement, and each line is moved into a separate list item. |
907 * This requires cloning elements, so the input might not have unique | 986 * This requires cloning elements, so the input might not have unique |
908 * IDs after numbering. | 987 * IDs after numbering. |
909 */ | 988 * @param {boolean} isPreformatted true iff white-space in text nodes should |
910 function numberLines(node, opt_startLineNum) { | 989 * be treated as significant. |
990 */ | |
991 function numberLines(node, opt_startLineNum, isPreformatted) { | |
911 var nocode = /(?:^|\s)nocode(?:\s|$)/; | 992 var nocode = /(?:^|\s)nocode(?:\s|$)/; |
912 var lineBreak = /\r\n?|\n/; | 993 var lineBreak = /\r\n?|\n/; |
913 | 994 |
914 var document = node.ownerDocument; | 995 var document = node.ownerDocument; |
915 | 996 |
916 var whitespace; | 997 var li = document.createElement('li'); |
917 if (node.currentStyle) { | |
918 whitespace = node.currentStyle.whiteSpace; | |
919 } else if (window.getComputedStyle) { | |
920 whitespace = document.defaultView.getComputedStyle(node, null) | |
921 .getPropertyValue('white-space'); | |
922 } | |
923 // If it's preformatted, then we need to split lines on line breaks | |
924 // in addition to <BR>s. | |
925 var isPreformatted = whitespace && 'pre' === whitespace.substring(0, 3); | |
926 | |
927 var li = document.createElement('LI'); | |
928 while (node.firstChild) { | 998 while (node.firstChild) { |
929 li.appendChild(node.firstChild); | 999 li.appendChild(node.firstChild); |
930 } | 1000 } |
931 // An array of lines. We split below, so this is initialized to one | 1001 // An array of lines. We split below, so this is initialized to one |
932 // un-split line. | 1002 // un-split line. |
933 var listItems = [li]; | 1003 var listItems = [li]; |
934 | 1004 |
935 function walk(node) { | 1005 function walk(node) { |
936 switch (node.nodeType) { | 1006 var type = node.nodeType; |
937 case 1: // Element | 1007 if (type == 1 && !nocode.test(node.className)) { // Element |
938 if (nocode.test(node.className)) { break; } | 1008 if ('br' === node.nodeName) { |
939 if ('BR' === node.nodeName) { | 1009 breakAfter(node); |
940 breakAfter(node); | 1010 // Discard the <BR> since it is now flush against a </LI>. |
941 // Discard the <BR> since it is now flush against a </LI>. | 1011 if (node.parentNode) { |
942 if (node.parentNode) { | 1012 node.parentNode.removeChild(node); |
943 node.parentNode.removeChild(node); | 1013 } |
944 } | 1014 } else { |
945 } else { | 1015 for (var child = node.firstChild; child; child = child.nextSibling) { |
946 for (var child = node.firstChild; child; child = child.nextSibling) { | 1016 walk(child); |
947 walk(child); | 1017 } |
948 } | 1018 } |
949 } | 1019 } else if ((type == 3 || type == 4) && isPreformatted) { // Text |
950 break; | 1020 var text = node.nodeValue; |
951 case 3: case 4: // Text | 1021 var match = text.match(lineBreak); |
952 if (isPreformatted) { | 1022 if (match) { |
953 var text = node.nodeValue; | 1023 var firstLine = text.substring(0, match.index); |
954 var match = text.match(lineBreak); | 1024 node.nodeValue = firstLine; |
955 if (match) { | 1025 var tail = text.substring(match.index + match[0].length); |
956 var firstLine = text.substring(0, match.index); | 1026 if (tail) { |
957 node.nodeValue = firstLine; | 1027 var parent = node.parentNode; |
958 var tail = text.substring(match.index + match[0].length); | 1028 parent.insertBefore( |
959 if (tail) { | 1029 document.createTextNode(tail), node.nextSibling); |
960 var parent = node.parentNode; | 1030 } |
961 parent.insertBefore( | 1031 breakAfter(node); |
962 document.createTextNode(tail), node.nextSibling); | 1032 if (!firstLine) { |
963 } | 1033 // Don't leave blank text nodes in the DOM. |
964 breakAfter(node); | 1034 node.parentNode.removeChild(node); |
965 if (!firstLine) { | 1035 } |
966 // Don't leave blank text nodes in the DOM. | 1036 } |
967 node.parentNode.removeChild(node); | |
968 } | |
969 } | |
970 } | |
971 break; | |
972 } | 1037 } |
973 } | 1038 } |
974 | 1039 |
975 // Split a line after the given node. | 1040 // Split a line after the given node. |
976 function breakAfter(lineEndNode) { | 1041 function breakAfter(lineEndNode) { |
1026 // Make sure numeric indices show correctly. | 1091 // Make sure numeric indices show correctly. |
1027 if (opt_startLineNum === (opt_startLineNum|0)) { | 1092 if (opt_startLineNum === (opt_startLineNum|0)) { |
1028 listItems[0].setAttribute('value', opt_startLineNum); | 1093 listItems[0].setAttribute('value', opt_startLineNum); |
1029 } | 1094 } |
1030 | 1095 |
1031 var ol = document.createElement('OL'); | 1096 var ol = document.createElement('ol'); |
1032 ol.className = 'linenums'; | 1097 ol.className = 'linenums'; |
1033 var offset = Math.max(0, ((opt_startLineNum - 1 /* zero index */)) | 0) || 0; | 1098 var offset = Math.max(0, ((opt_startLineNum - 1 /* zero index */)) | 0) || 0; |
1034 for (var i = 0, n = listItems.length; i < n; ++i) { | 1099 for (var i = 0, n = listItems.length; i < n; ++i) { |
1035 li = listItems[i]; | 1100 li = listItems[i]; |
1036 // Stick a class on the LIs so that stylesheets can | 1101 // Stick a class on the LIs so that stylesheets can |
1043 ol.appendChild(li); | 1108 ol.appendChild(li); |
1044 } | 1109 } |
1045 | 1110 |
1046 node.appendChild(ol); | 1111 node.appendChild(ol); |
1047 } | 1112 } |
1048 | |
1049 /** | 1113 /** |
1050 * Breaks {@code job.sourceCode} around style boundaries in | 1114 * Breaks {@code job.sourceCode} around style boundaries in |
1051 * {@code job.decorations} and modifies {@code job.sourceNode} in place. | 1115 * {@code job.decorations} and modifies {@code job.sourceNode} in place. |
1052 * @param {Object} job like <pre>{ | 1116 * @param {Object} job like <pre>{ |
1053 * sourceCode: {string} source as plain text, | 1117 * sourceCode: {string} source as plain text, |
1118 * sourceNode: {HTMLElement} the element containing the source, | |
1054 * spans: {Array.<number|Node>} alternating span start indices into source | 1119 * spans: {Array.<number|Node>} alternating span start indices into source |
1055 * and the text node or element (e.g. {@code <BR>}) corresponding to that | 1120 * and the text node or element (e.g. {@code <BR>}) corresponding to that |
1056 * span. | 1121 * span. |
1057 * decorations: {Array.<number|string} an array of style classes preceded | 1122 * decorations: {Array.<number|string} an array of style classes preceded |
1058 * by the position at which they start in job.sourceCode in order | 1123 * by the position at which they start in job.sourceCode in order |
1059 * }</pre> | 1124 * }</pre> |
1060 * @private | 1125 * @private |
1061 */ | 1126 */ |
1062 function recombineTagsAndDecorations(job) { | 1127 function recombineTagsAndDecorations(job) { |
1063 var isIE = /\bMSIE\b/.test(navigator.userAgent); | 1128 var isIE8OrEarlier = /\bMSIE\s(\d+)/.exec(navigator.userAgent); |
1129 isIE8OrEarlier = isIE8OrEarlier && +isIE8OrEarlier[1] <= 8; | |
1064 var newlineRe = /\n/g; | 1130 var newlineRe = /\n/g; |
1065 | 1131 |
1066 var source = job.sourceCode; | 1132 var source = job.sourceCode; |
1067 var sourceLength = source.length; | 1133 var sourceLength = source.length; |
1068 // Index into source after the last code-unit recombined. | 1134 // Index into source after the last code-unit recombined. |
1106 i = end; | 1172 i = end; |
1107 } | 1173 } |
1108 | 1174 |
1109 nDecorations = decorations.length = decPos; | 1175 nDecorations = decorations.length = decPos; |
1110 | 1176 |
1111 var decoration = null; | 1177 var sourceNode = job.sourceNode; |
1112 while (spanIndex < nSpans) { | 1178 var oldDisplay; |
1113 var spanStart = spans[spanIndex]; | 1179 if (sourceNode) { |
1114 var spanEnd = spans[spanIndex + 2] || sourceLength; | 1180 oldDisplay = sourceNode.style.display; |
1115 | 1181 sourceNode.style.display = 'none'; |
1116 var decStart = decorations[decorationIndex]; | 1182 } |
1117 var decEnd = decorations[decorationIndex + 2] || sourceLength; | 1183 try { |
1118 | 1184 var decoration = null; |
1119 var end = Math.min(spanEnd, decEnd); | 1185 while (spanIndex < nSpans) { |
1120 | 1186 var spanStart = spans[spanIndex]; |
1121 var textNode = spans[spanIndex + 1]; | 1187 var spanEnd = spans[spanIndex + 2] || sourceLength; |
1122 var styledText; | 1188 |
1123 if (textNode.nodeType !== 1 // Don't muck with <BR>s or <LI>s | 1189 var decEnd = decorations[decorationIndex + 2] || sourceLength; |
1124 // Don't introduce spans around empty text nodes. | 1190 |
1125 && (styledText = source.substring(sourceIndex, end))) { | 1191 var end = Math.min(spanEnd, decEnd); |
1126 // This may seem bizarre, and it is. Emitting LF on IE causes the | 1192 |
1127 // code to display with spaces instead of line breaks. | 1193 var textNode = spans[spanIndex + 1]; |
1128 // Emitting Windows standard issue linebreaks (CRLF) causes a blank | 1194 var styledText; |
1129 // space to appear at the beginning of every line but the first. | 1195 if (textNode.nodeType !== 1 // Don't muck with <BR>s or <LI>s |
1130 // Emitting an old Mac OS 9 line separator makes everything spiffy. | 1196 // Don't introduce spans around empty text nodes. |
1131 if (isIE) { styledText = styledText.replace(newlineRe, '\r'); } | 1197 && (styledText = source.substring(sourceIndex, end))) { |
1132 textNode.nodeValue = styledText; | 1198 // This may seem bizarre, and it is. Emitting LF on IE causes the |
1133 var document = textNode.ownerDocument; | 1199 // code to display with spaces instead of line breaks. |
1134 var span = document.createElement('SPAN'); | 1200 // Emitting Windows standard issue linebreaks (CRLF) causes a blank |
1135 span.className = decorations[decorationIndex + 1]; | 1201 // space to appear at the beginning of every line but the first. |
1136 var parentNode = textNode.parentNode; | 1202 // Emitting an old Mac OS 9 line separator makes everything spiffy. |
1137 parentNode.replaceChild(span, textNode); | 1203 if (isIE8OrEarlier) { |
1138 span.appendChild(textNode); | 1204 styledText = styledText.replace(newlineRe, '\r'); |
1139 if (sourceIndex < spanEnd) { // Split off a text node. | 1205 } |
1140 spans[spanIndex + 1] = textNode | 1206 textNode.nodeValue = styledText; |
1141 // TODO: Possibly optimize by using '' if there's no flicker. | 1207 var document = textNode.ownerDocument; |
1142 = document.createTextNode(source.substring(end, spanEnd)); | 1208 var span = document.createElement('span'); |
1143 parentNode.insertBefore(textNode, span.nextSibling); | 1209 span.className = decorations[decorationIndex + 1]; |
1144 } | 1210 var parentNode = textNode.parentNode; |
1145 } | 1211 parentNode.replaceChild(span, textNode); |
1146 | 1212 span.appendChild(textNode); |
1147 sourceIndex = end; | 1213 if (sourceIndex < spanEnd) { // Split off a text node. |
1148 | 1214 spans[spanIndex + 1] = textNode |
1149 if (sourceIndex >= spanEnd) { | 1215 // TODO: Possibly optimize by using '' if there's no flicker. |
1150 spanIndex += 2; | 1216 = document.createTextNode(source.substring(end, spanEnd)); |
1151 } | 1217 parentNode.insertBefore(textNode, span.nextSibling); |
1152 if (sourceIndex >= decEnd) { | 1218 } |
1153 decorationIndex += 2; | 1219 } |
1220 | |
1221 sourceIndex = end; | |
1222 | |
1223 if (sourceIndex >= spanEnd) { | |
1224 spanIndex += 2; | |
1225 } | |
1226 if (sourceIndex >= decEnd) { | |
1227 decorationIndex += 2; | |
1228 } | |
1229 } | |
1230 } finally { | |
1231 if (sourceNode) { | |
1232 sourceNode.style.display = oldDisplay; | |
1154 } | 1233 } |
1155 } | 1234 } |
1156 } | 1235 } |
1157 | |
1158 | 1236 |
1159 /** Maps language-specific file extensions to handlers. */ | 1237 /** Maps language-specific file extensions to handlers. */ |
1160 var langHandlerRegistry = {}; | 1238 var langHandlerRegistry = {}; |
1161 /** Register a language handler for the given file extensions. | 1239 /** Register a language handler for the given file extensions. |
1162 * @param {function (Object)} handler a function from source code to a list | 1240 * @param {function (Object)} handler a function from source code to a list |
1177 function registerLangHandler(handler, fileExtensions) { | 1255 function registerLangHandler(handler, fileExtensions) { |
1178 for (var i = fileExtensions.length; --i >= 0;) { | 1256 for (var i = fileExtensions.length; --i >= 0;) { |
1179 var ext = fileExtensions[i]; | 1257 var ext = fileExtensions[i]; |
1180 if (!langHandlerRegistry.hasOwnProperty(ext)) { | 1258 if (!langHandlerRegistry.hasOwnProperty(ext)) { |
1181 langHandlerRegistry[ext] = handler; | 1259 langHandlerRegistry[ext] = handler; |
1182 } else if (window['console']) { | 1260 } else if (win['console']) { |
1183 console['warn']('cannot override language handler %s', ext); | 1261 console['warn']('cannot override language handler %s', ext); |
1184 } | 1262 } |
1185 } | 1263 } |
1186 } | 1264 } |
1187 function langHandlerForExtension(extension, source) { | 1265 function langHandlerForExtension(extension, source) { |
1257 }), ['java']); | 1335 }), ['java']); |
1258 registerLangHandler(sourceDecorator({ | 1336 registerLangHandler(sourceDecorator({ |
1259 'keywords': SH_KEYWORDS, | 1337 'keywords': SH_KEYWORDS, |
1260 'hashComments': true, | 1338 'hashComments': true, |
1261 'multiLineStrings': true | 1339 'multiLineStrings': true |
1262 }), ['bsh', 'csh', 'sh']); | 1340 }), ['bash', 'bsh', 'csh', 'sh']); |
1263 registerLangHandler(sourceDecorator({ | 1341 registerLangHandler(sourceDecorator({ |
1264 'keywords': PYTHON_KEYWORDS, | 1342 'keywords': PYTHON_KEYWORDS, |
1265 'hashComments': true, | 1343 'hashComments': true, |
1266 'multiLineStrings': true, | 1344 'multiLineStrings': true, |
1267 'tripleQuotedStrings': true | 1345 'tripleQuotedStrings': true |
1268 }), ['cv', 'py']); | 1346 }), ['cv', 'py', 'python']); |
1269 registerLangHandler(sourceDecorator({ | 1347 registerLangHandler(sourceDecorator({ |
1270 'keywords': PERL_KEYWORDS, | 1348 'keywords': PERL_KEYWORDS, |
1271 'hashComments': true, | 1349 'hashComments': true, |
1272 'multiLineStrings': true, | 1350 'multiLineStrings': true, |
1273 'regexLiterals': true | 1351 'regexLiterals': 2 // multiline regex literals |
1274 }), ['perl', 'pl', 'pm']); | 1352 }), ['perl', 'pl', 'pm']); |
1275 registerLangHandler(sourceDecorator({ | 1353 registerLangHandler(sourceDecorator({ |
1276 'keywords': RUBY_KEYWORDS, | 1354 'keywords': RUBY_KEYWORDS, |
1277 'hashComments': true, | 1355 'hashComments': true, |
1278 'multiLineStrings': true, | 1356 'multiLineStrings': true, |
1279 'regexLiterals': true | 1357 'regexLiterals': true |
1280 }), ['rb']); | 1358 }), ['rb', 'ruby']); |
1281 registerLangHandler(sourceDecorator({ | 1359 registerLangHandler(sourceDecorator({ |
1282 'keywords': JSCRIPT_KEYWORDS, | 1360 'keywords': JSCRIPT_KEYWORDS, |
1283 'cStyleComments': true, | 1361 'cStyleComments': true, |
1284 'regexLiterals': true | 1362 'regexLiterals': true |
1285 }), ['js']); | 1363 }), ['javascript', 'js']); |
1286 registerLangHandler(sourceDecorator({ | 1364 registerLangHandler(sourceDecorator({ |
1287 'keywords': COFFEE_KEYWORDS, | 1365 'keywords': COFFEE_KEYWORDS, |
1288 'hashComments': 3, // ### style block comments | 1366 'hashComments': 3, // ### style block comments |
1289 'cStyleComments': true, | 1367 'cStyleComments': true, |
1290 'multilineStrings': true, | 1368 'multilineStrings': true, |
1291 'tripleQuotedStrings': true, | 1369 'tripleQuotedStrings': true, |
1292 'regexLiterals': true | 1370 'regexLiterals': true |
1293 }), ['coffee']); | 1371 }), ['coffee']); |
1294 registerLangHandler(createSimpleLexer([], [[PR_STRING, /^[\s\S]+/]]), ['regex']); | 1372 registerLangHandler(sourceDecorator({ |
1373 'keywords': RUST_KEYWORDS, | |
1374 'cStyleComments': true, | |
1375 'multilineStrings': true | |
1376 }), ['rc', 'rs', 'rust']); | |
1377 registerLangHandler( | |
1378 createSimpleLexer([], [[PR_STRING, /^[\s\S]+/]]), ['regex']); | |
1295 | 1379 |
1296 function applyDecorator(job) { | 1380 function applyDecorator(job) { |
1297 var opt_langExtension = job.langExtension; | 1381 var opt_langExtension = job.langExtension; |
1298 | 1382 |
1299 try { | 1383 try { |
1300 // Extract tags, and convert the source code to plain text. | 1384 // Extract tags, and convert the source code to plain text. |
1301 var sourceAndSpans = extractSourceSpans(job.sourceNode); | 1385 var sourceAndSpans = extractSourceSpans(job.sourceNode, job.pre); |
1302 /** Plain text. @type {string} */ | 1386 /** Plain text. @type {string} */ |
1303 var source = sourceAndSpans.sourceCode; | 1387 var source = sourceAndSpans.sourceCode; |
1304 job.sourceCode = source; | 1388 job.sourceCode = source; |
1305 job.spans = sourceAndSpans.spans; | 1389 job.spans = sourceAndSpans.spans; |
1306 job.basePos = 0; | 1390 job.basePos = 0; |
1310 | 1394 |
1311 // Integrate the decorations and tags back into the source code, | 1395 // Integrate the decorations and tags back into the source code, |
1312 // modifying the sourceNode in place. | 1396 // modifying the sourceNode in place. |
1313 recombineTagsAndDecorations(job); | 1397 recombineTagsAndDecorations(job); |
1314 } catch (e) { | 1398 } catch (e) { |
1315 if ('console' in window) { | 1399 if (win['console']) { |
1316 console['log'](e && e['stack'] ? e['stack'] : e); | 1400 console['log'](e && e['stack'] || e); |
1317 } | 1401 } |
1318 } | 1402 } |
1319 } | 1403 } |
1320 | 1404 |
1321 /** | 1405 /** |
1406 * Pretty print a chunk of code. | |
1322 * @param sourceCodeHtml {string} The HTML to pretty print. | 1407 * @param sourceCodeHtml {string} The HTML to pretty print. |
1323 * @param opt_langExtension {string} The language name to use. | 1408 * @param opt_langExtension {string} The language name to use. |
1324 * Typically, a filename extension like 'cpp' or 'java'. | 1409 * Typically, a filename extension like 'cpp' or 'java'. |
1325 * @param opt_numberLines {number|boolean} True to number lines, | 1410 * @param opt_numberLines {number|boolean} True to number lines, |
1326 * or the 1-indexed number of the first line in sourceCodeHtml. | 1411 * or the 1-indexed number of the first line in sourceCodeHtml. |
1327 */ | 1412 */ |
1328 function prettyPrintOne(sourceCodeHtml, opt_langExtension, opt_numberLines) { | 1413 function $prettyPrintOne(sourceCodeHtml, opt_langExtension, opt_numberLines) { |
1329 var container = document.createElement('PRE'); | 1414 var container = document.createElement('div'); |
1330 // This could cause images to load and onload listeners to fire. | 1415 // This could cause images to load and onload listeners to fire. |
1331 // E.g. <img onerror="alert(1337)" src="nosuchimage.png">. | 1416 // E.g. <img onerror="alert(1337)" src="nosuchimage.png">. |
1332 // We assume that the inner HTML is from a trusted source. | 1417 // We assume that the inner HTML is from a trusted source. |
1333 container.innerHTML = sourceCodeHtml; | 1418 // The pre-tag is required for IE8 which strips newlines from innerHTML |
1419 // when it is injected into a <pre> tag. | |
1420 // http://stackoverflow.com/questions/451486/pre-tag-loses-line-breaks-when-setting-innerhtml-in-ie | |
1421 // http://stackoverflow.com/questions/195363/inserting-a-newline-into-a-pre-tag-ie-javascript | |
1422 container.innerHTML = '<pre>' + sourceCodeHtml + '</pre>'; | |
1423 container = container.firstChild; | |
1334 if (opt_numberLines) { | 1424 if (opt_numberLines) { |
1335 numberLines(container, opt_numberLines); | 1425 numberLines(container, opt_numberLines, true); |
1336 } | 1426 } |
1337 | 1427 |
1338 var job = { | 1428 var job = { |
1339 langExtension: opt_langExtension, | 1429 langExtension: opt_langExtension, |
1340 numberLines: opt_numberLines, | 1430 numberLines: opt_numberLines, |
1341 sourceNode: container | 1431 sourceNode: container, |
1432 pre: 1 | |
1342 }; | 1433 }; |
1343 applyDecorator(job); | 1434 applyDecorator(job); |
1344 return container.innerHTML; | 1435 return container.innerHTML; |
1345 } | 1436 } |
1346 | 1437 |
1347 function prettyPrint(opt_whenDone) { | 1438 /** |
1348 function byTagName(tn) { return document.getElementsByTagName(tn); } | 1439 * Find all the {@code <pre>} and {@code <code>} tags in the DOM with |
1440 * {@code class=prettyprint} and prettify them. | |
1441 * | |
1442 * @param {Function} opt_whenDone called when prettifying is done. | |
1443 * @param {HTMLElement|HTMLDocument} opt_root an element or document | |
1444 * containing all the elements to pretty print. | |
1445 * Defaults to {@code document.body}. | |
1446 */ | |
1447 function $prettyPrint(opt_whenDone, opt_root) { | |
1448 var root = opt_root || document.body; | |
1449 var doc = root.ownerDocument || document; | |
1450 function byTagName(tn) { return root.getElementsByTagName(tn); } | |
1349 // fetch a list of nodes to rewrite | 1451 // fetch a list of nodes to rewrite |
1350 var codeSegments = [byTagName('pre'), byTagName('code'), byTagName('xmp')]; | 1452 var codeSegments = [byTagName('pre'), byTagName('code'), byTagName('xmp')]; |
1351 var elements = []; | 1453 var elements = []; |
1352 for (var i = 0; i < codeSegments.length; ++i) { | 1454 for (var i = 0; i < codeSegments.length; ++i) { |
1353 for (var j = 0, n = codeSegments[i].length; j < n; ++j) { | 1455 for (var j = 0, n = codeSegments[i].length; j < n; ++j) { |
1366 var k = 0; | 1468 var k = 0; |
1367 var prettyPrintingJob; | 1469 var prettyPrintingJob; |
1368 | 1470 |
1369 var langExtensionRe = /\blang(?:uage)?-([\w.]+)(?!\S)/; | 1471 var langExtensionRe = /\blang(?:uage)?-([\w.]+)(?!\S)/; |
1370 var prettyPrintRe = /\bprettyprint\b/; | 1472 var prettyPrintRe = /\bprettyprint\b/; |
1473 var prettyPrintedRe = /\bprettyprinted\b/; | |
1474 var preformattedTagNameRe = /pre|xmp/i; | |
1475 var codeRe = /^code$/i; | |
1476 var preCodeXmpRe = /^(?:pre|code|xmp)$/i; | |
1477 var EMPTY = {}; | |
1371 | 1478 |
1372 function doWork() { | 1479 function doWork() { |
1373 var endTime = (window['PR_SHOULD_USE_CONTINUATION'] ? | 1480 var endTime = (win['PR_SHOULD_USE_CONTINUATION'] ? |
1374 clock['now']() + 250 /* ms */ : | 1481 clock['now']() + 250 /* ms */ : |
1375 Infinity); | 1482 Infinity); |
1376 for (; k < elements.length && clock['now']() < endTime; k++) { | 1483 for (; k < elements.length && clock['now']() < endTime; k++) { |
1377 var cs = elements[k]; | 1484 var cs = elements[k]; |
1485 | |
1486 // Look for a preceding comment like | |
1487 // <?prettify lang="..." linenums="..."?> | |
1488 var attrs = EMPTY; | |
1489 { | |
1490 for (var preceder = cs; (preceder = preceder.previousSibling);) { | |
1491 var nt = preceder.nodeType; | |
1492 // <?foo?> is parsed by HTML 5 to a comment node (8) | |
1493 // like <!--?foo?-->, but in XML is a processing instruction | |
1494 var value = (nt === 7 || nt === 8) && preceder.nodeValue; | |
1495 if (value | |
1496 ? !/^\??prettify\b/.test(value) | |
1497 : (nt !== 3 || /\S/.test(preceder.nodeValue))) { | |
1498 // Skip over white-space text nodes but not others. | |
1499 break; | |
1500 } | |
1501 if (value) { | |
1502 attrs = {}; | |
1503 value.replace( | |
1504 /\b(\w+)=([\w:.%+-]+)/g, | |
1505 function (_, name, value) { attrs[name] = value; }); | |
1506 break; | |
1507 } | |
1508 } | |
1509 } | |
1510 | |
1378 var className = cs.className; | 1511 var className = cs.className; |
1379 if (className.indexOf('prettyprint') >= 0) { | 1512 if ((attrs !== EMPTY || prettyPrintRe.test(className)) |
1380 // If the classes includes a language extensions, use it. | 1513 // Don't redo this if we've already done it. |
1381 // Language extensions can be specified like | 1514 // This allows recalling pretty print to just prettyprint elements |
1382 // <pre class="prettyprint lang-cpp"> | 1515 // that have been added to the page since last call. |
1383 // the language extension "cpp" is used to find a language handler as | 1516 && !prettyPrintedRe.test(className)) { |
1384 // passed to PR.registerLangHandler. | |
1385 // HTML5 recommends that a language be specified using "language-" | |
1386 // as the prefix instead. Google Code Prettify supports both. | |
1387 // http://dev.w3.org/html5/spec-author-view/the-code-element.html | |
1388 var langExtension = className.match(langExtensionRe); | |
1389 // Support <pre class="prettyprint"><code class="language-c"> | |
1390 var wrapper; | |
1391 if (!langExtension && (wrapper = childContentWrapper(cs)) | |
1392 && "CODE" === wrapper.tagName) { | |
1393 langExtension = wrapper.className.match(langExtensionRe); | |
1394 } | |
1395 | |
1396 if (langExtension) { | |
1397 langExtension = langExtension[1]; | |
1398 } | |
1399 | 1517 |
1400 // make sure this is not nested in an already prettified element | 1518 // make sure this is not nested in an already prettified element |
1401 var nested = false; | 1519 var nested = false; |
1402 for (var p = cs.parentNode; p; p = p.parentNode) { | 1520 for (var p = cs.parentNode; p; p = p.parentNode) { |
1403 if ((p.tagName === 'pre' || p.tagName === 'code' || | 1521 var tn = p.tagName; |
1404 p.tagName === 'xmp') && | 1522 if (preCodeXmpRe.test(tn) |
1405 p.className && p.className.indexOf('prettyprint') >= 0) { | 1523 && p.className && prettyPrintRe.test(p.className)) { |
1406 nested = true; | 1524 nested = true; |
1407 break; | 1525 break; |
1408 } | 1526 } |
1409 } | 1527 } |
1410 if (!nested) { | 1528 if (!nested) { |
1529 // Mark done. If we fail to prettyprint for whatever reason, | |
1530 // we shouldn't try again. | |
1531 cs.className += ' prettyprinted'; | |
1532 | |
1533 // If the classes includes a language extensions, use it. | |
1534 // Language extensions can be specified like | |
1535 // <pre class="prettyprint lang-cpp"> | |
1536 // the language extension "cpp" is used to find a language handler | |
1537 // as passed to PR.registerLangHandler. | |
1538 // HTML5 recommends that a language be specified using "language-" | |
1539 // as the prefix instead. Google Code Prettify supports both. | |
1540 // http://dev.w3.org/html5/spec-author-view/the-code-element.html | |
1541 var langExtension = attrs['lang']; | |
1542 if (!langExtension) { | |
1543 langExtension = className.match(langExtensionRe); | |
1544 // Support <pre class="prettyprint"><code class="language-c"> | |
1545 var wrapper; | |
1546 if (!langExtension && (wrapper = childContentWrapper(cs)) | |
1547 && codeRe.test(wrapper.tagName)) { | |
1548 langExtension = wrapper.className.match(langExtensionRe); | |
1549 } | |
1550 | |
1551 if (langExtension) { langExtension = langExtension[1]; } | |
1552 } | |
1553 | |
1554 var preformatted; | |
1555 if (preformattedTagNameRe.test(cs.tagName)) { | |
1556 preformatted = 1; | |
1557 } else { | |
1558 var currentStyle = cs['currentStyle']; | |
1559 var defaultView = doc.defaultView; | |
1560 var whitespace = ( | |
1561 currentStyle | |
1562 ? currentStyle['whiteSpace'] | |
1563 : (defaultView | |
1564 && defaultView.getComputedStyle) | |
1565 ? defaultView.getComputedStyle(cs, null) | |
1566 .getPropertyValue('white-space') | |
1567 : 0); | |
1568 preformatted = whitespace | |
1569 && 'pre' === whitespace.substring(0, 3); | |
1570 } | |
1571 | |
1411 // Look for a class like linenums or linenums:<n> where <n> is the | 1572 // Look for a class like linenums or linenums:<n> where <n> is the |
1412 // 1-indexed number of the first line. | 1573 // 1-indexed number of the first line. |
1413 var lineNums = cs.className.match(/\blinenums\b(?::(\d+))?/); | 1574 var lineNums = attrs['linenums']; |
1414 lineNums = lineNums | 1575 if (!(lineNums = lineNums === 'true' || +lineNums)) { |
1415 ? lineNums[1] && lineNums[1].length ? +lineNums[1] : true | 1576 lineNums = className.match(/\blinenums\b(?::(\d+))?/); |
1416 : false; | 1577 lineNums = |
1417 if (lineNums) { numberLines(cs, lineNums); } | 1578 lineNums |
1579 ? lineNums[1] && lineNums[1].length | |
1580 ? +lineNums[1] : true | |
1581 : false; | |
1582 } | |
1583 if (lineNums) { numberLines(cs, lineNums, preformatted); } | |
1418 | 1584 |
1419 // do the pretty printing | 1585 // do the pretty printing |
1420 prettyPrintingJob = { | 1586 prettyPrintingJob = { |
1421 langExtension: langExtension, | 1587 langExtension: langExtension, |
1422 sourceNode: cs, | 1588 sourceNode: cs, |
1423 numberLines: lineNums | 1589 numberLines: lineNums, |
1590 pre: preformatted | |
1424 }; | 1591 }; |
1425 applyDecorator(prettyPrintingJob); | 1592 applyDecorator(prettyPrintingJob); |
1426 } | 1593 } |
1427 } | 1594 } |
1428 } | 1595 } |
1429 if (k < elements.length) { | 1596 if (k < elements.length) { |
1430 // finish up in a continuation | 1597 // finish up in a continuation |
1431 setTimeout(doWork, 250); | 1598 setTimeout(doWork, 250); |
1432 } else if (opt_whenDone) { | 1599 } else if ('function' === typeof opt_whenDone) { |
1433 opt_whenDone(); | 1600 opt_whenDone(); |
1434 } | 1601 } |
1435 } | 1602 } |
1436 | 1603 |
1437 doWork(); | 1604 doWork(); |
1438 } | 1605 } |
1439 | 1606 |
1440 /** | 1607 /** |
1441 * Find all the {@code <pre>} and {@code <code>} tags in the DOM with | 1608 * Contains functions for creating and registering new language handlers. |
1442 * {@code class=prettyprint} and prettify them. | 1609 * @type {Object} |
1443 * | 1610 */ |
1444 * @param {Function?} opt_whenDone if specified, called when the last entry | 1611 var PR = win['PR'] = { |
1445 * has been finished. | |
1446 */ | |
1447 window['prettyPrintOne'] = prettyPrintOne; | |
1448 /** | |
1449 * Pretty print a chunk of code. | |
1450 * | |
1451 * @param {string} sourceCodeHtml code as html | |
1452 * @return {string} code as html, but prettier | |
1453 */ | |
1454 window['prettyPrint'] = prettyPrint; | |
1455 /** | |
1456 * Contains functions for creating and registering new language handlers. | |
1457 * @type {Object} | |
1458 */ | |
1459 window['PR'] = { | |
1460 'createSimpleLexer': createSimpleLexer, | 1612 'createSimpleLexer': createSimpleLexer, |
1461 'registerLangHandler': registerLangHandler, | 1613 'registerLangHandler': registerLangHandler, |
1462 'sourceDecorator': sourceDecorator, | 1614 'sourceDecorator': sourceDecorator, |
1463 'PR_ATTRIB_NAME': PR_ATTRIB_NAME, | 1615 'PR_ATTRIB_NAME': PR_ATTRIB_NAME, |
1464 'PR_ATTRIB_VALUE': PR_ATTRIB_VALUE, | 1616 'PR_ATTRIB_VALUE': PR_ATTRIB_VALUE, |
1470 'PR_PLAIN': PR_PLAIN, | 1622 'PR_PLAIN': PR_PLAIN, |
1471 'PR_PUNCTUATION': PR_PUNCTUATION, | 1623 'PR_PUNCTUATION': PR_PUNCTUATION, |
1472 'PR_SOURCE': PR_SOURCE, | 1624 'PR_SOURCE': PR_SOURCE, |
1473 'PR_STRING': PR_STRING, | 1625 'PR_STRING': PR_STRING, |
1474 'PR_TAG': PR_TAG, | 1626 'PR_TAG': PR_TAG, |
1475 'PR_TYPE': PR_TYPE | 1627 'PR_TYPE': PR_TYPE, |
1628 'prettyPrintOne': | |
1629 IN_GLOBAL_SCOPE | |
1630 ? (win['prettyPrintOne'] = $prettyPrintOne) | |
1631 : (prettyPrintOne = $prettyPrintOne), | |
1632 'prettyPrint': prettyPrint = | |
1633 IN_GLOBAL_SCOPE | |
1634 ? (win['prettyPrint'] = $prettyPrint) | |
1635 : (prettyPrint = $prettyPrint) | |
1476 }; | 1636 }; |
1637 | |
1638 // Make PR available via the Asynchronous Module Definition (AMD) API. | |
1639 // Per https://github.com/amdjs/amdjs-api/wiki/AMD: | |
1640 // The Asynchronous Module Definition (AMD) API specifies a | |
1641 // mechanism for defining modules such that the module and its | |
1642 // dependencies can be asynchronously loaded. | |
1643 // ... | |
1644 // To allow a clear indicator that a global define function (as | |
1645 // needed for script src browser loading) conforms to the AMD API, | |
1646 // any global define function SHOULD have a property called "amd" | |
1647 // whose value is an object. This helps avoid conflict with any | |
1648 // other existing JavaScript code that could have defined a define() | |
1649 // function that does not conform to the AMD API. | |
1650 if (typeof define === "function" && define['amd']) { | |
1651 define("google-code-prettify", [], function () { | |
1652 return PR; | |
1653 }); | |
1654 } | |
1477 })(); | 1655 })(); |