Guest User

Untitled

a guest
Nov 30th, 2018
157
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 21.72 KB | None | 0 0
  1. /**
  2. * writeCapture.js v1.0.5
  3. *
  4. * @author noah <noah.sloan@gmail.com>
  5. *
  6. */
  7. (function($,global) {
  8. var doc = global.document;
  9. function doEvil(code) {
  10. var div = doc.createElement('div');
  11. doc.body.insertBefore(div,null);
  12. $.replaceWith(div,'<script type="text/javascript">'+code+'</script>');
  13. }
  14. // ensure we have our support functions
  15. $ = $ || (function(jQuery) {
  16. /**
  17. * @name writeCaptureSupport
  18. *
  19. * The support functions writeCapture needs.
  20. */
  21. return {
  22. /**
  23. * Takes an options parameter that must support the following:
  24. * {
  25. * url: url,
  26. * type: 'GET', // all requests are GET
  27. * dataType: "script", // it this is set to script, script tag injection is expected, otherwise, treat as plain text
  28. * async: true/false, // local scripts are loaded synchronously by default
  29. * success: callback(text,status), // must not pass a truthy 3rd parameter
  30. * error: callback(xhr,status,error) // must pass truthy 3rd parameter to indicate error
  31. * }
  32. */
  33. ajax: jQuery.ajax,
  34. /**
  35. * @param {String Element} selector an Element or selector
  36. * @return {Element} the first element matching selector
  37. */
  38. $: function(s) { return jQuery(s)[0]; },
  39. /**
  40. * @param {String jQuery Element} selector the element to replace.
  41. * writeCapture only needs the first matched element to be replaced.
  42. * @param {String} content the content to replace
  43. * the matched element with. script tags must be evaluated/loaded
  44. * and executed if present.
  45. */
  46. replaceWith: function(selector,content) {
  47. // jQuery 1.4? has a bug in replaceWith so we can't use it directly
  48. var el = jQuery(selector)[0];
  49. var next = el.nextSibling, parent = el.parentNode;
  50.  
  51. jQuery(el).remove();
  52.  
  53. if ( next ) {
  54. jQuery(next).before( content );
  55. } else {
  56. jQuery(parent).append( content );
  57. }
  58. },
  59.  
  60. onLoad: function(fn) {
  61. jQuery(fn);
  62. },
  63.  
  64. copyAttrs: function(src,dest) {
  65. var el = jQuery(dest), attrs = src.attributes;
  66. for (var i = 0, len = attrs.length; i < len; i++) {
  67. if(attrs[i] && attrs[i].value) {
  68. try {
  69. el.attr(attrs[i].name,attrs[i].value);
  70. } catch(e) { }
  71. }
  72. }
  73. }
  74. };
  75. })(global.jQuery);
  76.  
  77. $.copyAttrs = $.copyAttrs || function() {};
  78. $.onLoad = $.onLoad || function() {
  79. throw "error: autoAsync cannot be used without jQuery " +
  80. "or defining writeCaptureSupport.onLoad";
  81. };
  82.  
  83. // utilities
  84. function each(array,fn) {
  85. for(var i =0, len = array.length; i < len; i++) {
  86. if( fn(array[i]) === false) return;
  87. }
  88. }
  89. function isFunction(o) {
  90. return Object.prototype.toString.call(o) === "[object Function]";
  91. }
  92. function isString(o) {
  93. return Object.prototype.toString.call(o) === "[object String]";
  94. }
  95. function slice(array,start,end) {
  96. return Array.prototype.slice.call(array,start || 0,end || array && array.length);
  97. }
  98. function any(array,fn) {
  99. var result = false;
  100. each(array,check);
  101. function check(it) {
  102. return !(result = fn(it));
  103. }
  104. return result;
  105. }
  106.  
  107. function SubQ(parent) {
  108. this._queue = [];
  109. this._children = [];
  110. this._parent = parent;
  111. if(parent) parent._addChild(this);
  112. }
  113.  
  114. SubQ.prototype = {
  115. _addChild: function(q) {
  116. this._children.push(q);
  117. },
  118. push: function (task) {
  119. this._queue.push(task);
  120. this._bubble('_doRun');
  121. },
  122. pause: function() {
  123. this._bubble('_doPause');
  124. },
  125. resume: function() {
  126. this._bubble('_doResume');
  127. },
  128. _bubble: function(name) {
  129. var root = this;
  130. while(!root[name]) {
  131. root = root._parent;
  132. }
  133. return root[name]();
  134. },
  135. _next: function() {
  136. if(any(this._children,runNext)) return true;
  137. function runNext(c) {
  138. return c._next();
  139. }
  140. var task = this._queue.shift();
  141. if(task) {
  142. task();
  143. }
  144. return !!task;
  145. }
  146. };
  147.  
  148. /**
  149. * Provides a task queue for ensuring that scripts are run in order.
  150. *
  151. * The only public methods are push, pause and resume.
  152. */
  153. function Q(parent) {
  154. if(parent) {
  155. return new SubQ(parent);
  156. }
  157. SubQ.call(this);
  158. this.paused = 0;
  159. }
  160.  
  161. Q.prototype = (function() {
  162. function f() {}
  163. f.prototype = SubQ.prototype;
  164. return new f();
  165. })();
  166.  
  167. Q.prototype._doRun = function() {
  168. if(!this.running) {
  169. this.running = true;
  170. try {
  171. // just in case there is a bug, always resume
  172. // if paused is less than 1
  173. while(this.paused < 1 && this._next()){}
  174. } finally {
  175. this.running = false;
  176. }
  177. }
  178. };
  179. Q.prototype._doPause= function() {
  180. this.paused++;
  181. };
  182. Q.prototype._doResume = function() {
  183. this.paused--;
  184. this._doRun();
  185. };
  186.  
  187. // TODO unit tests...
  188. function MockDocument() { }
  189. MockDocument.prototype = {
  190. _html: '',
  191. open: function( ) {
  192. this._opened = true;
  193. if(this._delegate) {
  194. this._delegate.open();
  195. }
  196. },
  197. write: function(s) {
  198. if(this._closed) return;
  199. this._written = true;
  200. if(this._delegate) {
  201. this._delegate.write(s);
  202. } else {
  203. this._html += s;
  204. }
  205. },
  206. writeln: function(s) {
  207. this.write(s + '\n');
  208. },
  209. close: function( ) {
  210. this._closed = true;
  211. if(this._delegate) {
  212. this._delegate.close();
  213. }
  214. },
  215. copyTo: function(d) {
  216. this._delegate = d;
  217. d.foobar = true;
  218. if(this._opened) {
  219. d.open();
  220. }
  221. if(this._written) {
  222. d.write(this._html);
  223. }
  224. if(this._closed) {
  225. d.close();
  226. }
  227. }
  228. };
  229.  
  230. // test for IE 6/7 issue (issue 6) that prevents us from using call
  231. var canCall = (function() {
  232. var f = { f: doc.getElementById };
  233. try {
  234. f.f.call(doc,'abc');
  235. return true;
  236. } catch(e) {
  237. return false;
  238. }
  239. })();
  240.  
  241. function unProxy(elements) {
  242. each(elements,function(it) {
  243. var real = doc.getElementById(it.id);
  244. if(!real) {
  245. logError('<proxyGetElementById - finish>',
  246. 'no element in writen markup with id ' + it.id);
  247. return;
  248. }
  249.  
  250. each(it.el.childNodes,function(it) {
  251. real.appendChild(it);
  252. });
  253.  
  254. if(real.contentWindow) {
  255. // TODO why is the setTimeout necessary?
  256. global.setTimeout(function() {
  257. it.el.contentWindow.document.
  258. copyTo(real.contentWindow.document);
  259. },1);
  260. }
  261. $.copyAttrs(it.el,real);
  262. });
  263. }
  264.  
  265. function getOption(name,options) {
  266. if(options && options[name] === false) {
  267. return false;
  268. }
  269. return options && options[name] || self[name];
  270. }
  271.  
  272. function capture(context,options) {
  273. var tempEls = [],
  274. proxy = getOption('proxyGetElementById',options),
  275. forceLast = getOption('forceLastScriptTag',options),
  276. writeOnGet = getOption('writeOnGetElementById',options),
  277. immediate = getOption('immediateWrites', options),
  278. state = {
  279. write: doc.write,
  280. writeln: doc.writeln,
  281. finish: function() {},
  282. out: ''
  283. };
  284. context.state = state;
  285. doc.write = immediate ? immediateWrite : replacementWrite;
  286. doc.writeln = immediate ? immediateWriteln : replacementWriteln;
  287. if(proxy || writeOnGet) {
  288. state.getEl = doc.getElementById;
  289. doc.getElementById = getEl;
  290. if(writeOnGet) {
  291. findEl = writeThenGet;
  292. } else {
  293. findEl = makeTemp;
  294. state.finish = function() {
  295. unProxy(tempEls);
  296. };
  297. }
  298. }
  299. if(forceLast) {
  300. state.getByTag = doc.getElementsByTagName;
  301. doc.getElementsByTagName = function(name) {
  302. var result = slice(canCall ? state.getByTag.call(doc,name) :
  303. state.getByTag(name));
  304. if(name === 'script') {
  305. result.push( $.$(context.target) );
  306. }
  307. return result;
  308. };
  309. var f = state.finish;
  310. state.finish = function() {
  311. f();
  312. doc.getElementsByTagName = state.getByTag;
  313. };
  314. }
  315. function replacementWrite(s) {
  316. state.out += s;
  317. }
  318. function replacementWriteln(s) {
  319. state.out += s + '\n';
  320. }
  321. function immediateWrite(s) {
  322. var target = $.$(context.target);
  323. var div = doc.createElement('div');
  324. target.parentNode.insertBefore(div,target);
  325. $.replaceWith(div,sanitize(s));
  326. }
  327. function immediateWriteln(s) {
  328. var target = $.$(context.target);
  329. var div = doc.createElement('div');
  330. target.parentNode.insertBefore(div,target);
  331. $.replaceWith(div,sanitize(s) + '\n');
  332. }
  333. function makeTemp(id) {
  334. var t = doc.createElement('div');
  335. tempEls.push({id:id,el:t});
  336. // mock contentWindow in case it's supposed to be an iframe
  337. t.contentWindow = { document: new MockDocument() };
  338. return t;
  339. }
  340. function writeThenGet(id) {
  341. var target = $.$(context.target);
  342. var div = doc.createElement('div');
  343. target.parentNode.insertBefore(div,target);
  344. $.replaceWith(div,state.out);
  345. state.out = '';
  346. return canCall ? state.getEl.call(doc,id) :
  347. state.getEl(id);
  348. }
  349. function getEl(id) {
  350. var result = canCall ? state.getEl.call(doc,id) :
  351. state.getEl(id);
  352. return result || findEl(id);
  353. }
  354. return state;
  355. }
  356. function uncapture(state) {
  357. doc.write = state.write;
  358. doc.writeln = state.writeln;
  359. if(state.getEl) {
  360. doc.getElementById = state.getEl;
  361. }
  362. return state.out;
  363. }
  364.  
  365. function clean(code) {
  366. // IE will execute inline scripts with <!-- (uncommented) on the first
  367. // line, but will not eval() them happily
  368. return code && code.replace(/^\s*<!(\[CDATA\[|--)/,'').replace(/(\]\]|--)>\s*$/,'');
  369. }
  370.  
  371. function ignore() {}
  372. function doLog(code,error) {
  373. console.error("Error",error,"executing code:",code);
  374. }
  375.  
  376. var logError = isFunction(global.console && console.error) ?
  377. doLog : ignore;
  378.  
  379. function captureWrite(code,context,options) {
  380. var state = capture(context,options);
  381. try {
  382. doEvil(clean(code));
  383. } catch(e) {
  384. logError(code,e);
  385. } finally {
  386. uncapture(state);
  387. }
  388. return state;
  389. }
  390.  
  391. // copied from jQuery
  392. function isXDomain(src) {
  393. var parts = /^(\w+:)?\/\/([^\/?#]+)/.exec(src);
  394. return parts && ( parts[1] && parts[1] != location.protocol || parts[2] != location.host );
  395. }
  396.  
  397. function attrPattern(name) {
  398. return new RegExp('[\\s\\r\\n]'+name+'[\\s\\r\\n]*=[\\s\\r\\n]*(?:(["\'])([\\s\\S]*?)\\1|([^\\s>]+))','i');
  399. }
  400.  
  401. function matchAttr(name) {
  402. var regex = attrPattern(name);
  403. return function(tag) {
  404. var match = regex.exec(tag) || [];
  405. return match[2] || match[3];
  406. };
  407. }
  408.  
  409. var SCRIPT_TAGS = /(<script[^>]*>)([\s\S]*?)<\/script>/ig,
  410. SCRIPT_2 = /<script[^>]*\/>/ig,
  411. SRC_REGEX = attrPattern('src'),
  412. SRC_ATTR = matchAttr('src'),
  413. TYPE_ATTR = matchAttr('type'),
  414. LANG_ATTR = matchAttr('language'),
  415. GLOBAL = "__document_write_ajax_callbacks__",
  416. DIV_PREFIX = "__document_write_ajax_div-",
  417. TEMPLATE = "window['"+GLOBAL+"']['%d']();",
  418. callbacks = global[GLOBAL] = {},
  419. TEMPLATE_TAG = '<script type="text/javascript">' + TEMPLATE + '</script>',
  420. global_id = 0;
  421. function nextId() {
  422. return (++global_id).toString();
  423. }
  424.  
  425. function normalizeOptions(options,callback) {
  426. var done;
  427. if(isFunction(options)) {
  428. done = options;
  429. options = null;
  430. }
  431. options = options || {};
  432. done = done || options && options.done;
  433. options.done = callback ? function() {
  434. callback(done);
  435. } : done;
  436. return options;
  437. }
  438.  
  439. // The global Q synchronizes all sanitize operations.
  440. // The only time this synchronization is really necessary is when two or
  441. // more consecutive sanitize operations make async requests. e.g.,
  442. // sanitize call A requests foo, then sanitize B is called and bar is
  443. // requested. document.write was replaced by B, so if A returns first, the
  444. // content will be captured by B, then when B returns, document.write will
  445. // be the original document.write, probably messing up the page. At the
  446. // very least, A will get nothing and B will get the wrong content.
  447. var GLOBAL_Q = new Q();
  448.  
  449. var debug = [];
  450. var logDebug = window._debugWriteCapture ? function() {} :
  451. function (type,src,data) {
  452. debug.push({type:type,src:src,data:data});
  453. };
  454.  
  455. var logString = window._debugWriteCapture ? function() {} :
  456. function () {
  457. debug.push(arguments);
  458. };
  459.  
  460. function newCallback(fn) {
  461. var id = nextId();
  462. callbacks[id] = function() {
  463. fn();
  464. delete callbacks[id];
  465. };
  466. return id;
  467. }
  468.  
  469. function newCallbackTag(fn) {
  470. return TEMPLATE_TAG.replace(/%d/,newCallback(fn));
  471. }
  472.  
  473. /**
  474. * Sanitize the given HTML so that the scripts will execute with a modified
  475. * document.write that will capture the output and append it in the
  476. * appropriate location.
  477. *
  478. * @param {String} html
  479. * @param {Object Function} [options]
  480. * @param {Function} [options.done] Called when all the scripts in the
  481. * sanitized HTML have run.
  482. * @param {boolean} [options.asyncAll] If true, scripts loaded from the
  483. * same domain will be loaded asynchronously. This can improve UI
  484. * responsiveness, but will delay completion of the scripts and may
  485. * cause problems with some scripts, so it defaults to false.
  486. */
  487. function sanitize(html,options,parentQ,parentContext) {
  488. // each HTML fragment has it's own queue
  489. var queue = parentQ && new Q(parentQ) || GLOBAL_Q;
  490. options = normalizeOptions(options);
  491. var done = getOption('done',options);
  492. var doneHtml = '';
  493.  
  494. var fixUrls = getOption('fixUrls',options);
  495. if(!isFunction(fixUrls)) {
  496. fixUrls = function(src) { return src; };
  497. }
  498.  
  499. // if a done callback is passed, append a script to call it
  500. if(isFunction(done)) {
  501. // no need to proxy the call to done, so we can append this to the
  502. // filtered HTML
  503. doneHtml = newCallbackTag(function() {
  504. queue.push(done);
  505. });
  506. }
  507. // for each tag, generate a function to load and eval the code and queue
  508. // themselves
  509. return html.replace(SCRIPT_TAGS,proxyTag).replace(SCRIPT_2,proxyBodyless) + doneHtml;
  510. function proxyBodyless(tag) {
  511. // hack in a bodyless tag...
  512. return proxyTag(tag,tag.substring(0,tag.length-2)+'>','');
  513. }
  514. function proxyTag(element,openTag,code) {
  515. var src = SRC_ATTR(openTag),
  516. type = TYPE_ATTR(openTag) || '',
  517. lang = LANG_ATTR(openTag) || '',
  518. isJs = (!type && !lang) || // no type or lang assumes JS
  519. type.toLowerCase().indexOf('javascript') !== -1 ||
  520. lang.toLowerCase().indexOf('javascript') !== -1;
  521.  
  522. logDebug('replace',src,element);
  523.  
  524. if(!isJs) {
  525. return element;
  526. }
  527.  
  528. var id = newCallback(queueScript), divId = DIV_PREFIX + id,
  529. run, context = { target: '#' + divId, parent: parentContext };
  530.  
  531. function queueScript() {
  532. queue.push(run);
  533. }
  534.  
  535. if(src) {
  536. // fix for the inline script that writes a script tag with encoded
  537. // ampersands hack (more comon than you'd think)
  538. src = fixUrls(src);
  539.  
  540. openTag = openTag.replace(SRC_REGEX,'');
  541. if(isXDomain(src)) {
  542. // will load async via script tag injection (eval()'d on
  543. // it's own)
  544. run = loadXDomain;
  545. } else {
  546. // can be loaded then eval()d
  547. if(getOption('asyncAll',options)) {
  548. run = loadAsync();
  549. } else {
  550. run = loadSync;
  551. }
  552. }
  553. } else {
  554. // just eval code and be done
  555. run = runInline;
  556.  
  557. }
  558. function runInline() {
  559. captureHtml(code);
  560. }
  561. function loadSync() {
  562. $.ajax({
  563. url: src,
  564. type: 'GET',
  565. dataType: 'text',
  566. async: false,
  567. success: function(html) {
  568. captureHtml(html);
  569. }
  570. });
  571. }
  572. function logAjaxError(xhr,status,error) {
  573. logError("<XHR for "+src+">",error);
  574. queue.resume();
  575. }
  576. function setupResume() {
  577. return newCallbackTag(function() {
  578. queue.resume();
  579. });
  580. }
  581. function loadAsync() {
  582. var ready, scriptText;
  583. function captureAndResume(script,status) {
  584. if(!ready) {
  585. // loaded before queue run, cache text
  586. scriptText = script;
  587. return;
  588. }
  589. try {
  590. captureHtml(script, setupResume());
  591. } catch(e) {
  592. logError(script,e);
  593. }
  594. }
  595. // start loading the text
  596. $.ajax({
  597. url: src,
  598. type: 'GET',
  599. dataType: 'text',
  600. async: true,
  601. success: captureAndResume,
  602. error: logAjaxError
  603. });
  604. return function() {
  605. ready = true;
  606. if(scriptText) {
  607. // already loaded, so don't pause the queue and don't resume!
  608. captureHtml(scriptText);
  609. } else {
  610. queue.pause();
  611. }
  612. };
  613. }
  614. function loadXDomain(cb) {
  615. var state = capture(context,options);
  616. queue.pause(); // pause the queue while the script loads
  617. logDebug('pause',src);
  618.  
  619. doXDomainLoad(context.target,src,captureAndResume);
  620.  
  621. function captureAndResume(xhr,st,error) {
  622. logDebug('out', src, state.out);
  623. html(uncapture(state),
  624. newCallbackTag(state.finish) + setupResume());
  625. logDebug('resume',src);
  626. }
  627. }
  628. function captureHtml(script, cb) {
  629. var state = captureWrite(script,context,options);
  630. cb = newCallbackTag(state.finish) + (cb || '');
  631. html(state.out,cb);
  632. }
  633. function safeOpts(options) {
  634. var copy = {};
  635. for(var i in options) {
  636. if(options.hasOwnProperty(i)) {
  637. copy[i] = options[i];
  638. }
  639. }
  640. delete copy.done;
  641. return copy;
  642. }
  643. function html(markup,cb) {
  644. $.replaceWith(context.target,sanitize(markup,safeOpts(options),queue,context) + (cb || ''));
  645. }
  646. return '<div style="display: none" id="'+divId+'"></div>' + openTag +
  647. TEMPLATE.replace(/%d/,id) + '</script>';
  648. }
  649. }
  650.  
  651. function doXDomainLoad(target,url,success) {
  652. // TODO what about scripts that fail to load? bad url, etc.?
  653. var script = document.createElement("script");
  654. script.src = url;
  655.  
  656. target = $.$(target);
  657.  
  658. var done = false, parent = target.parentNode;
  659.  
  660. // Attach handlers for all browsers
  661. script.onload = script.onreadystatechange = function(){
  662. if ( !done && (!this.readyState ||
  663. this.readyState == "loaded" || this.readyState == "complete") ) {
  664. done = true;
  665. success();
  666.  
  667. // Handle memory leak in IE
  668. script.onload = script.onreadystatechange = null;
  669. parent.removeChild( script );
  670. }
  671. };
  672.  
  673. parent.insertBefore(script,target);
  674. }
  675.  
  676. /**
  677. * Sanitizes all the given fragments and calls action with the HTML.
  678. * The next fragment is not started until the previous fragment
  679. * has executed completely.
  680. *
  681. * @param {Array} fragments array of objects like this:
  682. * {
  683. * html: '<p>My html with a <script...',
  684. * action: function(safeHtml,frag) { doSomethingToInject(safeHtml); },
  685. * options: {} // optional, see #sanitize
  686. * }
  687. * Where frag is the object.
  688. *
  689. * @param {Function} [done] Optional. Called when all fragments are done.
  690. */
  691. function sanitizeSerial(fragments,done) {
  692. // create a queue for these fragments and make it the parent of each
  693. // sanitize call
  694. var queue = GLOBAL_Q;
  695. each(fragments, function (f) {
  696. queue.push(run);
  697. function run() {
  698. f.action(sanitize(f.html,f.options,queue),f);
  699. }
  700. });
  701. if(done) {
  702. queue.push(done);
  703. }
  704. }
  705.  
  706. function findLastChild(el) {
  707. var n = el;
  708. while(n && n.nodeType === 1) {
  709. el = n;
  710. n = n.lastChild;
  711. // last child may not be an element
  712. while(n && n.nodeType !== 1) {
  713. n = n.previousSibling;
  714. }
  715. }
  716. return el;
  717. }
  718.  
  719. /**
  720. * Experimental - automatically captures document.write calls and
  721. * defers them untill after page load.
  722. * @param {Function} [done] optional callback for when all the
  723. * captured content has been loaded.
  724. */
  725. function autoCapture(done) {
  726. var write = doc.write,
  727. writeln = doc.writeln,
  728. currentScript,
  729. autoQ = [];
  730. doc.writeln = function(s) {
  731. doc.write(s+'\n');
  732. };
  733. var state;
  734. doc.write = function(s) {
  735. var scriptEl = findLastChild(doc.body);
  736. if(scriptEl !== currentScript) {
  737. currentScript = scriptEl;
  738. autoQ.push(state = {
  739. el: scriptEl,
  740. out: []
  741. });
  742. }
  743. state.out.push(s);
  744. };
  745. $.onLoad(function() {
  746. // for each script, append a div immediately after it,
  747. // then replace the div with the sanitized output
  748. var el, div, out, safe, doneFn;
  749. done = normalizeOptions(done);
  750. doneFn = done.done;
  751. done.done = function() {
  752. doc.write = write;
  753. doc.writeln = writeln;
  754. if(doneFn) doneFn();
  755. };
  756. for(var i = 0, len = autoQ.length; i < len; i++ ) {
  757. el = autoQ[i].el;
  758. div = doc.createElement('div');
  759. el.parentNode.insertBefore( div, el.nextSibling );
  760. out = autoQ[i].out.join('');
  761. // only the last snippet gets passed the callback
  762. safe = len - i === 1 ? sanitize(out,done) : sanitize(out);
  763. $.replaceWith(div,safe);
  764. }
  765. });
  766. }
  767.  
  768. function extsrc(cb) {
  769. var scripts = document.getElementsByTagName('script'),
  770. s,o, html, q, ext, async, doneCount = 0,
  771. done = cb ? newCallbackTag(function() {
  772. if(++doneCount >= exts.length) {
  773. cb();
  774. }
  775. }) : '',
  776. exts = [];
  777.  
  778. for(var i = 0, len = scripts.length; i < len; i++) {
  779. s = scripts[i];
  780. ext = s.getAttribute('extsrc');
  781. async = s.getAttribute('asyncsrc');
  782. if(ext || async) {
  783. exts.push({ext:ext,async:async,s:s});
  784. }
  785. }
  786.  
  787. for(i = 0, len = exts.length; i < len; i++) {
  788. o = exts[i];
  789. if(o.ext) {
  790. html = '<script type="text/javascript" src="'+o.ext+'"> </script>';
  791. $.replaceWith(o.s,sanitize(html) + done);
  792. } else if(o.async) {
  793. html = '<script type="text/javascript" src="'+o.async+'"> </script>';
  794. $.replaceWith(o.s,sanitize(html,{asyncAll:true}, new Q()) + done);
  795. }
  796. }
  797. }
  798.  
  799. var name = 'writeCapture';
  800. var self = global[name] = {
  801. _original: global[name],
  802. support: $,
  803. /**
  804. */
  805. fixUrls: function(src) {
  806. return src.replace(/&/g,'&');
  807. },
  808. noConflict: function() {
  809. global[name] = this._original;
  810. return this;
  811. },
  812. debug: debug,
  813. /**
  814. * Enables a fun little hack that replaces document.getElementById and
  815. * creates temporary elements for the calling code to use.
  816. */
  817. proxyGetElementById: false,
  818. // this is only for testing, please don't use these
  819. _forTest: {
  820. Q: Q,
  821. GLOBAL_Q: GLOBAL_Q,
  822. $: $,
  823. matchAttr: matchAttr,
  824. slice: slice,
  825. capture: capture,
  826. uncapture: uncapture,
  827. captureWrite: captureWrite
  828. },
  829. replaceWith: function(selector,content,options) {
  830. $.replaceWith(selector,sanitize(content,options));
  831. },
  832. html: function(selector,content,options) {
  833. var el = $.$(selector);
  834. el.innerHTML ='<span/>';
  835. $.replaceWith(el.firstChild,sanitize(content,options));
  836. },
  837. load: function(selector,url,options) {
  838. $.ajax({
  839. url: url,
  840. dataType: 'text',
  841. type: "GET",
  842. success: function(content) {
  843. self.html(selector,content,options);
  844. }
  845. });
  846. },
  847. extsrc: extsrc,
  848. autoAsync: autoCapture,
  849. sanitize: sanitize,
  850. sanitizeSerial: sanitizeSerial
  851. };
  852.  
  853. })(this.writeCaptureSupport,this);
Add Comment
Please, Sign In to add comment