Skip to content
Fetching contributors…
Cannot retrieve contributors at this time
258 lines (234 sloc) 9.62 KB
/**
* @license
* Copyright (C) 2013 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview
* <div style="white-space: pre">
* Looks at query parameters to decide which language handlers and style-sheets
* to load.
*
* Query Parameter Format Effect Default
* +------------------+---------------+------------------------------+--------+
* | autorun= | true | false | If true then prettyPrint() | "true" |
* | | | is called on page load. | |
* +------------------+---------------+------------------------------+--------+
* | lang= | language name | Loads the language handler | Can |
* | | | named "lang-<NAME>.js". | appear |
* | | | See available handlers at | many |
* | | | https://github.com/google/ | times. |
* | | | code-prettify/tree/master/ | |
* | | | src | |
* +------------------+---------------+------------------------------+--------+
* | skin= | skin name | Loads the skin stylesheet | none. |
* | | | named "<NAME>.css". | |
* | | | https://cdn.rawgit.com/ | |
* | | | google/code-prettify/master/ | |
* | | | styles/index.html | |
* +------------------+---------------+------------------------------+--------+
* | callback= | JS identifier | When "prettyPrint" finishes | none |
* | | | window.exports[js_ident] is | |
* | | | called. | |
* | | | The callback must be under | |
* | | | exports to reduce the risk | |
* | | | of XSS via query parameter | |
* | | | injection. | |
* +------------------+---------------+------------------------------+--------+
*
* Exmaples
* .../prettify.js?lang=css&skin=sunburst
* 1. Loads the CSS language handler which can be used to prettify CSS
* stylesheets, HTML <style> element bodies and style="..." attributes
* values.
* 2. Loads the sunburst.css stylesheet instead of the default prettify.css
* stylesheet.
* A gallery of stylesheets is available at
* https://cdn.rawgit.com/google/code-prettify/master/styles/index.html
* 3. Since autorun=false is not specified, calls prettyPrint() on page load.
* </div>
*/
(function () {
"use strict";
var win = window;
var doc = document;
var root = doc.documentElement;
var head = doc['head'] || doc.getElementsByTagName("head")[0] || root;
// From http://javascript.nwbox.com/ContentLoaded/contentloaded.js
// Author: Diego Perini (diego.perini at gmail.com)
// Summary: cross-browser wrapper for DOMContentLoaded
// Updated: 20101020
// License: MIT
// Version: 1.2
function contentLoaded(callback) {
var addEventListener = doc['addEventListener'];
var done = false, top = true,
add = addEventListener ? 'addEventListener' : 'attachEvent',
rem = addEventListener ? 'removeEventListener' : 'detachEvent',
pre = addEventListener ? '' : 'on',
init = function(e) {
if (e.type == 'readystatechange' && doc.readyState != 'complete') {
return;
}
(e.type == 'load' ? win : doc)[rem](pre + e.type, init, false);
if (!done && (done = true)) { callback.call(win, e.type || e); }
},
poll = function() {
try {
root.doScroll('left');
} catch(e) {
win.setTimeout(poll, 50);
return;
}
init('poll');
};
if (doc.readyState == 'complete') {
callback.call(win, 'lazy');
} else {
if (doc.createEventObject && root.doScroll) {
try { top = !win.frameElement; } catch(e) { }
if (top) { poll(); }
}
doc[add](pre + 'DOMContentLoaded', init, false);
doc[add](pre + 'readystatechange', init, false);
win[add](pre + 'load', init, false);
}
}
// Given a list of URLs to stylesheets, loads the first that loads without
// triggering an error event.
function loadStylesheetsFallingBack(stylesheets) {
var n = stylesheets.length;
function load(i) {
if (i === n) { return; }
var link = doc.createElement('link');
link.rel = 'stylesheet';
link.type = 'text/css';
if (i + 1 < n) {
// http://pieisgood.org/test/script-link-events/ indicates that many
// versions of IE do not support onerror on <link>s, though
// http://msdn.microsoft.com/en-us/library/ie/ms535848(v=vs.85).aspx
// indicates that recent IEs do support error.
link.error = link.onerror = function () { load(i + 1); };
}
link.href = stylesheets[i];
head.appendChild(link);
}
load(0);
}
var scriptQuery = '';
// Look for the <script> node that loads this script to get its parameters.
// This starts looking at the end instead of just considering the last
// because deferred and async scripts run out of order.
// If the script is loaded twice, then this will run in reverse order.
var scripts = doc.getElementsByTagName('script');
for (var i = scripts.length; --i >= 0;) {
var script = scripts[i];
var match = script.src.match(
/^[^?#]*\/run_prettify\.js(\?[^#]*)?(?:#.*)?$/);
if (match) {
scriptQuery = match[1] || '';
// Remove the script from the DOM so that multiple runs at least run
// multiple times even if parameter sets are interpreted in reverse
// order.
script.parentNode.removeChild(script);
break;
}
}
// Pull parameters into local variables.
var autorun = true;
var langs = [];
var skins = [];
var callbacks = [];
scriptQuery.replace(
/[?&]([^&=]+)=([^&]+)/g,
function (_, name, value) {
value = decodeURIComponent(value);
name = decodeURIComponent(name);
if (name == 'autorun') { autorun = !/^[0fn]/i.test(value); } else
if (name == 'lang') { langs.push(value); } else
if (name == 'skin') { skins.push(value); } else
if (name == 'callback') { callbacks.push(value); }
});
// Use https to avoid mixed content warnings in client pages and to
// prevent a MITM from rewrite prettify mid-flight.
// This only works if this script is loaded via https : something
// over which we exercise no control.
var LOADER_BASE_URL =
'https://cdn.rawgit.com/google/code-prettify/master/loader';
for (var i = 0, n = langs.length; i < n; ++i) (function (lang) {
var script = doc.createElement("script");
// Excerpted from jQuery.ajaxTransport("script") to fire events when
// a script is finished loading.
// Attach handlers for each script
script.onload = script.onerror = script.onreadystatechange = function () {
if (script && (
!script.readyState || /loaded|complete/.test(script.readyState))) {
// Handle memory leak in IE
script.onerror = script.onload = script.onreadystatechange = null;
--pendingLanguages;
checkPendingLanguages();
// Remove the script
if (script.parentNode) {
script.parentNode.removeChild(script);
}
script = null;
}
};
script.type = 'text/javascript';
script.src = LOADER_BASE_URL
+ '/lang-' + encodeURIComponent(langs[i]) + '.js';
// Circumvent IE6 bugs with base elements (#2709 and #4378) by prepending
head.insertBefore(script, head.firstChild);
})(langs[i]);
var pendingLanguages = langs.length;
function checkPendingLanguages() {
if (!pendingLanguages) {
win.setTimeout(onLangsLoaded, 0);
}
}
var skinUrls = [];
for (var i = 0, n = skins.length; i < n; ++i) {
skinUrls.push(LOADER_BASE_URL
+ '/skins/' + encodeURIComponent(skins[i]) + '.css');
}
skinUrls.push(LOADER_BASE_URL + '/prettify.css');
loadStylesheetsFallingBack(skinUrls);
var prettyPrint = (function () {
include("prettify.js");
return prettyPrint;
})();
// If this script is deferred or async and the document is already
// loaded we need to wait for language handlers to load before performing
// any autorun.
function onLangsLoaded() {
if (autorun) {
contentLoaded(
function () {
var n = callbacks.length;
var callback = n ? function () {
for (var i = 0; i < n; ++i) {
(function (i) {
win.setTimeout(
function () {
win['exports'][callbacks[i]].apply(win, arguments);
}, 0);
})(i);
}
} : void 0;
prettyPrint(callback);
});
}
}
checkPendingLanguages();
}());
Something went wrong with that request. Please try again.