parchment.debug.js 54 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423
  1. /*
  2. Parchment
  3. =========
  4. Built: 2014-10-05
  5. Copyright (c) 2008-2014 The Parchment Contributors
  6. BSD licenced
  7. https://github.com/curiousdannii/parchment
  8. */
  9. /*
  10. Simple JavaScript Inheritance
  11. =============================
  12. By John Resig
  13. Released into the public domain?
  14. http://ejohn.org/blog/simple-javascript-inheritance/
  15. Changes from Dannii: support toString in IE8
  16. */
  17. (function(){'use strict';
  18. var initializing = 0;
  19. // Determine if functions can be serialized
  20. var fnTest = /xyz/.test( function() { xyz; } ) ? /\b_super\b/ : /.*/;
  21. // Check whether for in will iterate toString
  22. var iterate_toString, name;
  23. for ( name in { toString: 1 } ) { iterate_toString = 1; }
  24. // Create a new Class that inherits from this class
  25. Object.subClass = function( prop )
  26. {
  27. var _super = this.prototype,
  28. proto,
  29. name,
  30. Class;
  31. var prop_toString = !/native code/.test( '' + prop.toString ) && prop.toString;
  32. // Make the magical _super() function work
  33. var make_super = function( name, fn )
  34. {
  35. return function()
  36. {
  37. var tmp = this._super,
  38. ret;
  39. // Add a new ._super() method that is the same method
  40. // but on the super-class
  41. this._super = _super[name];
  42. // The method only need to be bound temporarily, so we
  43. // remove it when we're done executing
  44. ret = fn.apply( this, arguments );
  45. this._super = tmp;
  46. return ret;
  47. };
  48. };
  49. // Instantiate a base class (but only create the instance,
  50. // don't run the init constructor)
  51. initializing = 1;
  52. proto = new this;
  53. initializing = 0;
  54. // Copy the properties over onto the new prototype
  55. for ( name in prop )
  56. {
  57. // Check if we're overwriting an existing function
  58. proto[name] = typeof prop[name] == "function" && typeof _super[name] == "function" && fnTest.test( prop[name] )
  59. ? make_super( name, prop[name] ) : prop[name];
  60. }
  61. // Handle toString in IE8
  62. if ( !iterate_toString && prop_toString )
  63. {
  64. proto.toString = fnTest.test( prop_toString ) ? make_super( 'toString', prop_toString ) : prop_toString;
  65. }
  66. // The dummy class constructor
  67. Class = proto.init ? function()
  68. {
  69. // All construction is actually done in the init method
  70. if ( !initializing )
  71. {
  72. this.init.apply( this, arguments );
  73. }
  74. } : function(){};
  75. // Populate our constructed prototype object
  76. Class.prototype = proto;
  77. // Enforce the constructor to be what we expect
  78. Class.constructor = Class;
  79. // And make this class extendable
  80. Class.subClass = Object.subClass;
  81. return Class;
  82. };
  83. window.Class = Object;
  84. })();
  85. /*
  86. Interchange File Format library
  87. ===============================
  88. Copyright (c) 2008-2011 The Parchment Contributors
  89. BSD licenced
  90. http://code.google.com/p/parchment
  91. */
  92. (function(){
  93. // Get a 32 bit number from a byte array, and vice versa
  94. function num_from(s, offset)
  95. {
  96. return s[offset] << 24 | s[offset + 1] << 16 | s[offset + 2] << 8 | s[offset + 3];
  97. }
  98. function num_to_word(n)
  99. {
  100. return [(n >> 24) & 0xFF, (n >> 16) & 0xFF, (n >> 8) & 0xFF, n & 0xFF];
  101. }
  102. // Get a 4 byte string ID from a byte array, and vice versa
  103. function text_from(s, offset)
  104. {
  105. return String.fromCharCode( s[offset], s[offset + 1], s[offset + 2], s[offset + 3] );
  106. }
  107. function text_to_word(t)
  108. {
  109. return [t.charCodeAt(0), t.charCodeAt(1), t.charCodeAt(2), t.charCodeAt(3)];
  110. }
  111. // IFF file class
  112. // Parses an IFF file stored in a byte array
  113. var IFF = Object.subClass({
  114. // Parse a byte array or construct an empty IFF file
  115. init: function parse_iff(data)
  116. {
  117. this.type = '';
  118. this.chunks = [];
  119. if (data)
  120. {
  121. // Check this is an IFF file
  122. if (text_from(data, 0) != 'FORM')
  123. throw new Error("Not an IFF file");
  124. // Parse the file
  125. this.type = text_from(data, 8);
  126. var i = 12, l = data.length;
  127. while (i < l)
  128. {
  129. var chunk_length = num_from(data, i + 4);
  130. if (chunk_length < 0 || (chunk_length + i) > l)
  131. // FIXME: do something sensible here
  132. throw new Error("IFF: Chunk out of range");
  133. this.chunks.push({
  134. type: text_from(data, i),
  135. offset: i,
  136. data: data.slice(i + 8, i + 8 + chunk_length)
  137. });
  138. i += 8 + chunk_length;
  139. if (chunk_length % 2) i++;
  140. }
  141. }
  142. },
  143. // Write out the IFF into a byte array
  144. write: function write_iff()
  145. {
  146. // Start with the IFF type
  147. var out = text_to_word(this.type);
  148. // Go through the chunks and write them out
  149. for (var i = 0, l = this.chunks.length; i < l; i++)
  150. {
  151. var chunk = this.chunks[i], data = chunk.data, len = data.length;
  152. out = out.concat(text_to_word(chunk.type), num_to_word(len), data);
  153. if (len % 2)
  154. out.push(0);
  155. }
  156. // Add the header and return
  157. return text_to_word('FORM').concat(num_to_word(out.length), out);
  158. }
  159. });
  160. // Expose the class and helper functions
  161. IFF.num_from = num_from;
  162. IFF.num_to_word = num_to_word;
  163. IFF.text_from = text_from;
  164. IFF.text_to_word = text_to_word;
  165. window.IFF = IFF;
  166. })();
  167. /*
  168. StructIO intro
  169. ==============
  170. Copyright (c) 2012 The Parchment Contributors
  171. BSD licenced
  172. http://code.google.com/p/parchment
  173. */
  174. /*
  175. TODO:
  176. Calculate bodylineheight with the rest of the metrics?
  177. */
  178. (function( window, $, undefined ){
  179. ;;; })();
  180. var extend = function( old, add )
  181. {
  182. for ( var name in add )
  183. {
  184. old[name] = add[name];
  185. }
  186. return old;
  187. },
  188. rBadBackground = /inh|tra|(\d+, ?){3}0/,
  189. $window = $( window ),
  190. $doc = $( document ),
  191. $body,
  192. bodylineheight;
  193. $(function()
  194. {
  195. $body = $( 'body' );
  196. // Calculate the body line-height
  197. var elem = $( '<span>&nbsp;</span>' ).appendTo( $body );
  198. bodylineheight = elem.height();
  199. elem.remove();
  200. });
  201. extend( $.cssHooks, {
  202. // Hooks for messing around with background colours
  203. bgcolor: {
  204. // Get the resolved colour - no inherits or transparents allowed!
  205. get: function( elem )
  206. {
  207. var $elem = $( elem ),
  208. background = $elem.css( 'background-color' );
  209. // Getting the current background colour is hard: go through the parent elements until one with a real colour is found
  210. if ( rBadBackground.test( background ) )
  211. {
  212. return $elem.parent().css( 'bgcolor' );
  213. }
  214. return background;
  215. },
  216. // Set the background colour of all elements up the tree until one is found with a proper colour
  217. set: function( elem, value )
  218. {
  219. var $elem = $( elem ),
  220. parent = $elem.parent();
  221. $elem.css( 'background-color', value );
  222. // Recurse up the tree
  223. if ( rBadBackground.test( parent.css( 'background-color' ) ) )
  224. {
  225. parent.css( 'bgcolor', value );
  226. }
  227. }
  228. }
  229. });
  230. /*
  231. Text Input
  232. ==========
  233. Copyright (c) 2008-2011 The Parchment Contributors
  234. BSD licenced
  235. http://code.google.com/p/parchment
  236. */
  237. /*
  238. TODO:
  239. Add labels to prompts for screen readers?
  240. Is an input actually needed for char input? Just listen on the doc?
  241. -> mobiles might need one.
  242. Page up/down doesn't work in Chrome
  243. Support input when some is given already
  244. Adjust styles so that the padding belongs to the input and the window scrolls all the way to the bottom when focused
  245. Cache @window.height - let StructIO update it for us
  246. */
  247. // window.scrollByPages() compatibility
  248. var scrollPages = window.scrollByPages || function( pages )
  249. {
  250. // From Mozilla's nsGfxScrollFrame.cpp
  251. // delta = viewportHeight - Min( 10%, lineHeight * 2 )
  252. var height = document.documentElement.clientHeight,
  253. delta = height - Math.min( height / 10, bodylineheight * 2 );
  254. scrollBy( 0, delta * pages );
  255. },
  256. // getSelection compatibility-ish. We only care about the text value of a selection
  257. selection = window.getSelection ||
  258. function() { return document.selection ? document.selection.createRange().text : '' },
  259. // A generic text input class
  260. // Will handle both line and character input
  261. TextInput = Object.subClass({
  262. // Set up the text inputs with a container
  263. // container is the greatest domain for which this instance should control input
  264. init: function( container )
  265. {
  266. var self = this,
  267. // The input element
  268. input = $( '<input>', {
  269. 'class': 'TextInput',
  270. autocapitalize: 'off',
  271. keydown: function( event )
  272. {
  273. var keyCode = self.keyCode = event.which,
  274. cancel;
  275. if ( self.mode != 'line' )
  276. {
  277. return;
  278. }
  279. // Check for up/down to use the command history
  280. if ( keyCode == 38 ) // up -> prev
  281. {
  282. self.prev_next( 1 );
  283. cancel = 1;
  284. }
  285. if ( keyCode == 40 ) // down -> next
  286. {
  287. self.prev_next( -1 );
  288. cancel = 1;
  289. }
  290. // Trigger page up/down on the body
  291. if ( keyCode == 33 ) // Up
  292. {
  293. scrollPages(-1);
  294. cancel = 1;
  295. }
  296. if ( keyCode == 34 ) // Down
  297. {
  298. scrollPages(1);
  299. cancel = 1;
  300. }
  301. // Accept line input
  302. if ( keyCode == 13 )
  303. {
  304. self.submitLine();
  305. cancel = 1;
  306. }
  307. // Don't propagate the event
  308. event.stopPropagation();
  309. // Don't do the default browser action
  310. // (For example in Mac OS pressing up will force the cursor to the beginning of a line)
  311. if ( cancel )
  312. {
  313. return false;
  314. }
  315. },
  316. // Submit a character input event
  317. keypress: function( event )
  318. {
  319. if ( self.mode == 'char' )
  320. {
  321. self.charCode = event.which;
  322. self.submitChar();
  323. return false;
  324. }
  325. },
  326. // Backup for browsers like Chrome which don't send keypress events for non-characters
  327. keyup: function()
  328. {
  329. if ( self.mode == 'char' )
  330. {
  331. self.submitChar();
  332. }
  333. }
  334. });
  335. // A marker for the last input
  336. self.lastinput = $( '<span class="lastinput"/>' )
  337. .appendTo( container );
  338. // Focus document clicks and keydowns
  339. $doc.on( 'click.TextInput keydown.TextInput', function( ev )
  340. {
  341. // Only intercept on things that aren't inputs and if the user isn't selecting text
  342. if ( ev.target.nodeName != 'INPUT' && selection() == '' )
  343. {
  344. // If the input box is close to the viewport then focus it
  345. if ( $window.scrollTop() + $window.height() - input.offset().top > -60 )
  346. {
  347. window.scrollTo( 0, 9e9 );
  348. // Manually reset the target incase focus/trigger don't - we don't want the trigger to recurse
  349. ev.target = input[0];
  350. input.focus()
  351. .trigger( ev );
  352. // Stop propagating after re-triggering it, so that the trigger will work for all keys
  353. ev.stopPropagation();
  354. }
  355. // Intercept the backspace key if not
  356. else if ( ev.type == 'keydown' && ev.which == 8 )
  357. {
  358. return false;
  359. }
  360. }
  361. });
  362. // Command history
  363. self.history = [];
  364. // current and mutable_history are set in .get()
  365. self.input = input;
  366. self.container = container;
  367. self.statuswin = $( '<div>' );
  368. // Find the element which we calculate scroll offsets from
  369. // For now just decide by browser
  370. self.scrollParent = /webkit/i.test( navigator.userAgent ) ? $body : $( 'html' );
  371. },
  372. // Cleanup so we can deconstruct
  373. die: function()
  374. {
  375. $doc.off( '.TextInput' );
  376. },
  377. // Scroll to the beginning of the last set of output
  378. scroll: function()
  379. {
  380. this.scrollParent.scrollTop(
  381. // The last input relative to the top of the document
  382. this.lastinput.offset().top
  383. // Minus the height of the top window
  384. - this.statuswin.height()
  385. // Minus one further line
  386. - bodylineheight
  387. );
  388. },
  389. // Get some input
  390. getLine: function( order )
  391. {
  392. var laststruct = order.target.children().last(),
  393. input = this.input,
  394. prompt;
  395. this.order = order;
  396. this.mode = 'line';
  397. // Set up the mutable history
  398. this.current = 0;
  399. this.mutable_history = this.history.slice();
  400. this.mutable_history.unshift( '' );
  401. // Extract the prompt
  402. prompt = /^([\s\S]+<br>)(.+?)$/.exec( laststruct.html() );
  403. if ( prompt )
  404. {
  405. laststruct.html( prompt[1] );
  406. prompt = laststruct.clone()
  407. .html( prompt[2] )
  408. .appendTo( laststruct );
  409. }
  410. else
  411. {
  412. prompt = laststruct;
  413. }
  414. // Adjust the input's width and ensure it's empty
  415. input
  416. .width( 20 )
  417. .val( '' )
  418. .appendTo( prompt )
  419. .width( order.target.offset().left + order.target.width() - input.offset().left );
  420. this.scroll();
  421. },
  422. // Submit the input data
  423. submitLine: function()
  424. {
  425. var command = this.input.val();
  426. // Attach the last input marker
  427. this.lastinput.appendTo( this.input.parent() );
  428. // Hide the <input>
  429. this.input.detach();
  430. // Add this command to the history, as long as it's not the same as the last, and not blank
  431. if ( command != this.history[0] && /\S/.test( command ) )
  432. {
  433. this.history.unshift( command );
  434. }
  435. // Trigger a custom event for anyone listening in for commands
  436. $doc.trigger({
  437. type: 'TextInput',
  438. mode: 'line',
  439. input: command
  440. });
  441. this.mode = 0;
  442. this.order.response = command;
  443. this.order.terminator = 13;
  444. this.callback( this.order );
  445. },
  446. // Get the previous/next command from history
  447. // change = 1 for previous and -1 for next
  448. prev_next: function( change )
  449. {
  450. var input = this.input,
  451. mutable_history = this.mutable_history,
  452. current = this.current,
  453. new_current = current + change;
  454. // Check it's within range
  455. if ( new_current < mutable_history.length && new_current >= 0 )
  456. {
  457. mutable_history[current] = input.val();
  458. input.val( mutable_history[new_current] );
  459. this.current = new_current;
  460. }
  461. },
  462. // Get some input
  463. getChar: function( order )
  464. {
  465. this.order = order;
  466. this.mode = 'char';
  467. this.keyCode = this.charCode = 0;
  468. // Add the <input>
  469. this.input.addClass( 'CharInput' )
  470. .appendTo( this.container );
  471. this.scroll();
  472. },
  473. // Submit the input data
  474. submitChar: function()
  475. {
  476. var keyCode = this.keyCode,
  477. charCode = this.charCode,
  478. input = {
  479. keyCode: keyCode,
  480. charCode: charCode
  481. };
  482. // Do we have anything to submit?
  483. if ( !keyCode && !charCode )
  484. {
  485. return;
  486. }
  487. // Hide the <input>
  488. this.input.detach()
  489. .removeClass( 'CharInput' );
  490. // Trigger a custom event for anyone listening in for key strokes
  491. $doc.trigger({
  492. type: 'TextInput',
  493. mode: 'char',
  494. input: input
  495. });
  496. this.mode = 0;
  497. this.order.response = input;
  498. this.callback( this.order );
  499. }
  500. });
  501. /*
  502. Text grid (ie, status) windows
  503. ==============================
  504. Copyright (c) 2012 The Parchment Contributors
  505. BSD licenced
  506. http://code.google.com/p/parchment
  507. */
  508. /*
  509. TODO:
  510. Check cursor column is correct?
  511. */
  512. var TextGrid = Object.subClass({
  513. // Set up the class, and attach a stream handler
  514. init: function( elem, io )
  515. {
  516. var self = this;
  517. this.elem = elem
  518. .addClass( 'TextGrid' )
  519. .on( 'stream', function( e )
  520. {
  521. self.stream( e.order.data );
  522. return false;
  523. })
  524. .css( 'bgcolor', 'inherit' );
  525. this.lineheight = io.env.charheight;
  526. this.io = io;
  527. io.TextInput.statuswin = this.elem;
  528. this.lines = [];
  529. this.styles = [];
  530. this.cursor = [0, 0]; // row, col
  531. },
  532. // Accept a stream of text grid orders
  533. stream: function( orders )
  534. {
  535. var order, code, i, j,
  536. elem = this.elem,
  537. row = this.cursor[0],
  538. col = this.cursor[1],
  539. lines = this.lines,
  540. styles = this.styles,
  541. env = this.io.env,
  542. line, text, temp,
  543. stylecode,
  544. oldheight = lines.length;
  545. // Process the orders
  546. for ( i = 0; i < orders.length; i++ )
  547. {
  548. order = orders[i];
  549. code = order.code;
  550. // Adjust the height of the grid
  551. if ( code == 'height' )
  552. {
  553. // Increase the height
  554. while ( order.lines > lines.length )
  555. {
  556. this.addline();
  557. }
  558. // Decrease the height, and handle box quotations
  559. if ( order.lines < lines.length )
  560. {
  561. if ( order.lines != 0 )
  562. {
  563. // Fix bad heights (that would split a multi-line status) by increasing the requested height to the first blank line
  564. while ( order.lines < lines.length && /\S/.test( lines[order.lines].join( '' ) ) )
  565. {
  566. order.lines++;
  567. }
  568. // Add the floating box
  569. temp = $( '<div>' )
  570. .addClass( 'box' )
  571. .prependTo( this.io.target );
  572. // Position it where it would have been if it was part of the grid
  573. // Scroll to the bottom just in case
  574. window.scrollTo( 0, 9e9 );
  575. temp.css({
  576. top: $window.scrollTop() + this.lineheight * order.lines,
  577. // Account for .main's added 1px padding
  578. left: temp.offset().left - 1
  579. });
  580. // Fill it with the lines we'll be removing
  581. this.write( temp, lines.slice( order.lines ), styles.slice( order.lines ) );
  582. }
  583. lines.length = order.lines;
  584. styles.length = order.lines;
  585. if ( row > order.lines - 1 )
  586. {
  587. row = 0;
  588. col = 0;
  589. }
  590. }
  591. }
  592. // Empty the grid, but don't change it's size
  593. if ( code == 'clear' )
  594. {
  595. j = 0;
  596. while ( j < lines.length )
  597. {
  598. this.addline( j++ );
  599. }
  600. row = 0;
  601. col = 0;
  602. }
  603. // Set the cursor position
  604. // Not that our coordinates are -1 compared to the Z-Machine
  605. if ( code == 'cursor' )
  606. {
  607. row = order.to[0];
  608. col = order.to[1];
  609. // It is illegal to position the cursor outside the window, but some games do (ex, Lost Pig's Hints)
  610. if ( row < 0 )
  611. {
  612. row = 0;
  613. }
  614. if ( col < 0 )
  615. {
  616. col = 0;
  617. }
  618. // Add a row(s) if needed
  619. while ( row >= lines.length )
  620. {
  621. this.addline();
  622. }
  623. }
  624. if ( code == 'get_cursor' )
  625. {
  626. order.pos = [row, col];
  627. this.io.input( order );
  628. }
  629. // Add text to the grid
  630. if ( code == 'stream' )
  631. {
  632. // Add a row(s) if needed
  633. while ( row >= lines.length )
  634. {
  635. this.addline();
  636. }
  637. // Calculate the style attribute for this set of text
  638. stylecode = '';
  639. if ( order.props )
  640. {
  641. temp = $( '<tt>', order.props )
  642. .appendTo( elem );
  643. text = temp.attr( 'style' );
  644. if ( text )
  645. {
  646. stylecode += ' style="' + text + '"';
  647. }
  648. text = temp.attr( 'class' );
  649. if ( text )
  650. {
  651. stylecode += ' class="' + text + '"';
  652. }
  653. }
  654. if ( stylecode === '' )
  655. {
  656. stylecode = undefined;
  657. }
  658. // The <tt> will be removed in .write()
  659. // Add the text to the arrays
  660. text = order.text;
  661. j = 0;
  662. while ( j < text.length )
  663. {
  664. temp = text.charAt( j++ );
  665. // Regular character
  666. if ( temp != '\r' )
  667. {
  668. lines[row][col] = temp;
  669. styles[row][col++] = stylecode;
  670. }
  671. // New line, or end of a line
  672. if ( temp == '\r' || col == env.width )
  673. {
  674. row++;
  675. col = 0;
  676. // Add a row if needed, ie. we must still have text to go
  677. if ( row >= lines.length && j < text.length )
  678. {
  679. this.addline();
  680. }
  681. }
  682. }
  683. }
  684. if ( code == 'eraseline' )
  685. {
  686. for ( j = col; j < env.width; j++ )
  687. {
  688. lines[row][j] = ' ';
  689. styles[row][j] = undefined;
  690. }
  691. }
  692. }
  693. // Update the cursor
  694. this.cursor = [row, col];
  695. // Update the HTML
  696. this.write( elem, lines, styles );
  697. // Try to adjust the main window's padding - for now guess what the window's class is
  698. if ( lines.length != oldheight )
  699. {
  700. $( '.main' )
  701. .css( 'padding-top', elem.height() );
  702. }
  703. },
  704. // Update the HTML
  705. write: function( elem, lines, styles )
  706. {
  707. var result = '',
  708. i = 0, j,
  709. text,
  710. style;
  711. // Go through the lines and styles array, constructing a <tt> whenever the styles change
  712. while ( i < lines.length )
  713. {
  714. text = '';
  715. style = styles[i][0];
  716. for ( j = 0; j < lines[i].length; j++ )
  717. {
  718. if ( styles[i][j] == style )
  719. {
  720. text += lines[i][j];
  721. }
  722. else
  723. {
  724. result += '<tt' + ( style || '' ) + '>' + text + '</tt>';
  725. style = styles[i][j];
  726. text = lines[i][j];
  727. }
  728. }
  729. result += '<tt' + ( style || '' ) + '>' + text + '</tt>';
  730. if ( ++i < lines.length )
  731. {
  732. result += '<br>';
  733. }
  734. }
  735. elem.html( result );
  736. },
  737. // Add a blank line
  738. addline: function( row )
  739. {
  740. var width = this.io.env.width,
  741. line = [],
  742. i = 0;
  743. row = row || this.lines.length;
  744. while ( i++ < width )
  745. {
  746. line.push( ' ' );
  747. }
  748. this.lines[row] = line;
  749. this.styles[row] = Array( width );
  750. }
  751. });
  752. /*
  753. StructIO
  754. ========
  755. Copyright (c) 2012 The Parchment Contributors
  756. BSD licenced
  757. http://code.google.com/p/parchment
  758. */
  759. /*
  760. TODO:
  761. Timed input
  762. input terminators
  763. Listen for the window being resized to smaller than the current width
  764. Allow the window to be drag-resized
  765. Detect that position: fixed doesn't work
  766. */
  767. // Root stream handler. Some structures (like text grids) could have alternative handlers
  768. var basic_stream_handler = function( e )
  769. {
  770. var order = e.order,
  771. struct = e.io.structures[order.name] || { node: 'span' },
  772. node = order.node || ( order.props && order.props.node ) || struct.node,
  773. // Create the new element and set everything that needs to be set
  774. elem = $( '<' + node + '>', order.props || {} )
  775. .appendTo( e.target );
  776. if ( order.name )
  777. {
  778. elem.addClass( order.name );
  779. }
  780. if ( order.text )
  781. {
  782. elem.text( order.text.replace( /\r/g, '\n' ) );
  783. }
  784. // If we have a custom function to run, do so
  785. if ( struct.func )
  786. {
  787. struct.func( elem, e.io );
  788. }
  789. return false;
  790. };
  791. // The public API
  792. // .input() must be set by whatever uses StructIO
  793. StructIO = Object.subClass({
  794. init: function( env )
  795. {
  796. env = extend( {}, env );
  797. this.env = env;
  798. var element = $( env.container ),
  799. // Calculate the width we want
  800. measureelem = $( '<tt>00000</tt>' )
  801. .appendTo( element ),
  802. charheight = measureelem.height(),
  803. charwidth = measureelem.width() / 5,
  804. widthinchars = Math.min( Math.floor( element.width() / charwidth ), env.width || 80 );
  805. measureelem.remove();
  806. extend( env, {
  807. charheight: charheight,
  808. charwidth: charwidth,
  809. width: widthinchars,
  810. fgcolour: element.css( 'color' ),
  811. bgcolour: element.css( 'bgcolor' )
  812. });
  813. // Set the container's width: +2 to account for the 1px of padding the structures inside will receive to hide obnoxious serifs
  814. element.width( widthinchars * charwidth + 2 );
  815. this.container = element
  816. this.target = element;
  817. element.on( 'stream', basic_stream_handler );
  818. this.TextInput = new TextInput( element );
  819. // Default structures
  820. this.structures = {
  821. main: {
  822. node: 'div'
  823. },
  824. status: {
  825. node: 'div',
  826. func: function( elem, io ) { new TextGrid( elem, io ); }
  827. }
  828. };
  829. },
  830. // Process some output events
  831. event: function( orders )
  832. {
  833. var order, code, i,
  834. target = this.target,
  835. TextInput = this.TextInput,
  836. temp;
  837. // Process the orders
  838. for ( i = 0; i < orders.length; i++ )
  839. {
  840. order = orders[i];
  841. code = order.code;
  842. // Specify the elements to use for various structures
  843. // All structures must specify at least the node to use
  844. if ( code == 'structures' )
  845. {
  846. order.code = undefined;
  847. $.extend( this.structures, order );
  848. }
  849. // Find a new target element
  850. if ( code == 'find' )
  851. {
  852. this.target = target = $( '.' + order.name );
  853. }
  854. // Add a structure
  855. if ( code == 'stream' )
  856. {
  857. // .to will let you temporarily stream to something else
  858. ( order.to ? $( '.' + order.to ) : target )
  859. .trigger({
  860. type: 'stream',
  861. io: this,
  862. order: order
  863. });
  864. }
  865. if ( code == 'clear' )
  866. {
  867. var oldbg,
  868. bg = order.bg,
  869. temp = order.name ? $( '.' + order.name ) : target;
  870. temp.empty();
  871. // Set the background colour
  872. if ( typeof bg !== 'undefined' )
  873. {
  874. // If we're clearing the main window, then change <body> instead
  875. if ( order.name == 'main' )
  876. {
  877. temp = $body;
  878. }
  879. // First remove an old background colour class
  880. oldbg = /zvm-bg-\d+/.exec( temp.attr( 'class' ) );
  881. if ( oldbg )
  882. {
  883. temp.removeClass( oldbg[0] );
  884. }
  885. // Add style
  886. if ( isNaN( bg ) )
  887. {
  888. temp.css( 'background-color', bg );
  889. }
  890. else
  891. {
  892. temp.addClass( 'zvm-bg-' + bg );
  893. }
  894. }
  895. }
  896. // Line input
  897. if ( code == 'read' )
  898. {
  899. order.target = target;
  900. TextInput.getLine( order );
  901. }
  902. // Character input
  903. if ( code == 'char' )
  904. {
  905. TextInput.getChar( order );
  906. }
  907. // When quitting, scroll to the bottom in case something was printed since the last input
  908. if ( code == 'quit' )
  909. {
  910. TextInput.scroll();
  911. }
  912. }
  913. }
  914. });
  915. /*
  916. StructIO outro
  917. ==============
  918. Copyright (c) 2011 The Parchment Contributors
  919. BSD licenced
  920. http://code.google.com/p/parchment
  921. */
  922. ;;; (function( window, $, undefined ){
  923. // Expose
  924. window.StructIO = StructIO;
  925. StructIO.TextInput = TextInput;
  926. })( window, jQuery );
  927. /*
  928. StructIO runner
  929. ===============
  930. Copyright (c) 2011 The Parchment Contributors
  931. BSD licenced
  932. http://code.google.com/p/parchment
  933. */
  934. /*
  935. Runners are Parchment's glue: they connect an engine to it's IO system and to the Library
  936. Not all runners are subclassed from Runner - there might be too little common code to make that worthwhile
  937. All runners do however need to support the same basic API:
  938. init( env, engine )
  939. env = parchment.options
  940. engine = the VM class's name, if given in the definition
  941. fromParchment( event )
  942. Needs to handle these events: load, restart, save, restore
  943. toParchment( event ) -> Will be added by the Parchment Library
  944. TODO:
  945. Support Workers
  946. Support errors in the Worker-like protocol
  947. */
  948. // A basic StructIO runner
  949. var Runner = Object.subClass({
  950. init: function( env, engine )
  951. {
  952. var self = this;
  953. // engine is only a class name, so make an instance now
  954. engine = window.engine = this.e = new window[engine]();
  955. this.io = new StructIO( env );
  956. // Set the appropriate event handlers
  957. this.toEngine = this.io.TextInput.callback = function( event ) { engine.inputEvent( event ); };
  958. engine.outputEvent = function( event ) { self.fromEngine( event ); };
  959. },
  960. // Handler for events from Parchment
  961. fromParchment: function( event )
  962. {
  963. var code = event.code;
  964. // Load the story file
  965. if ( code == 'load' )
  966. {
  967. event.env = this.io.env;
  968. }
  969. // Restart, save, restore -> just return to the engine
  970. this.toEngine( event );
  971. },
  972. // Handler for output events from the VM
  973. fromEngine: function( orders )
  974. {
  975. var engine = this.e,
  976. i = 0,
  977. order, code,
  978. sendevent;
  979. // Send the orders to StructIO
  980. this.io.event( orders );
  981. // Go through the orders for anything non-StructIO
  982. for ( ; i < orders.length; i++ )
  983. {
  984. order = orders[i];
  985. code = order.code;
  986. if ( code == 'quit' )
  987. {
  988. return;
  989. }
  990. if ( code == 'save' || code == 'restore' )
  991. {
  992. this.toParchment( order );
  993. }
  994. if ( code == 'restart' )
  995. {
  996. // Reset the IO structures
  997. this.io.target = this.io.container.empty();
  998. sendevent = 1;
  999. }
  1000. // Tick - ie, do nothing
  1001. if ( code == 'tick' )
  1002. {
  1003. sendevent = 1;
  1004. }
  1005. }
  1006. if ( sendevent )
  1007. {
  1008. this.toEngine( order );
  1009. }
  1010. }
  1011. });
  1012. /*
  1013. Parchment
  1014. =========
  1015. Copyright (c) 2013 The Parchment Contributors
  1016. BSD licenced
  1017. https://github.com/curiousdannii/parchment
  1018. */
  1019. if ( typeof DEBUG === 'undefined' )
  1020. {
  1021. DEBUG = true;
  1022. }
  1023. // Wrap all of Parchment in a closure/namespace, and enable strict mode
  1024. (function( window, $ ){ 'use strict';
  1025. // Don't append a timestamp to XHR requests
  1026. // Converter for use with the binary dataType prefilter in file.js
  1027. jQuery.ajaxSetup({
  1028. cache: 1,
  1029. converters: {
  1030. '* binary': true
  1031. }
  1032. });
  1033. // Don't use XHR for local files
  1034. // Limit to Chrome?
  1035. jQuery.ajaxPrefilter( 'script', function( options /*, originalOptions, jqXHR*/ )
  1036. {
  1037. if ( options.isLocal )
  1038. {
  1039. options.crossDomain = 1;
  1040. }
  1041. });
  1042. // The home for Parchment to live in
  1043. window.parchment = {
  1044. // The default parchment options
  1045. options: {
  1046. // A selector for the top HTML element which we will have complete control over
  1047. container: '#parchment',
  1048. // Should no ?story= be given, run this
  1049. // May be an array, in which case [0] is the .z5/.zblorb and [1] is a backup legacy .js file
  1050. //default_story: [ 'stories/troll.z5', 'stories/troll.z5.js' ],
  1051. // Where shall we find the lib .js files?
  1052. lib_path: 'lib/',
  1053. // Don't allow people to specify additional options in the query string
  1054. //lock_options: 0,
  1055. // Lock Parchment so it will only run the default story, which must be provided!
  1056. //lock_story: 0,
  1057. // Set to 0 if you don't want Parchment to overwrite your <title>
  1058. page_title: 1,
  1059. // Front page panels to display if no default story
  1060. panels: [ 'search', 'url', 'about' ],
  1061. // URL of proxy server to use for files we can't directly load
  1062. proxy_url: 'http://zcode.appspot.com/proxy/'
  1063. },
  1064. // Classes etc
  1065. lib: {}
  1066. };
  1067. // Isolate the query string options we have
  1068. var urloptions = (function( options ) {
  1069. var i = 0, result = {}, temp;
  1070. if ( options[0] == '' )
  1071. {
  1072. i++;
  1073. }
  1074. while ( i < options.length )
  1075. {
  1076. temp = /([^=]+)(=(.*))?/.exec( options[i++] );
  1077. result[temp[1]] = temp[3] ? unescape( temp[3] ) : true;
  1078. }
  1079. return result;
  1080. } )( location.search.slice(1).split( /[&;]/g ) );
  1081. (function($){
  1082. window.FatalError = function(message) {
  1083. this.message = message;
  1084. this.traceback = ''; //this._makeTraceback(arguments.callee);
  1085. this.onError(this);
  1086. // Hide load indicator
  1087. if ( $('.load').length > 0 )
  1088. {
  1089. //self.hidden_load_indicator = 1;
  1090. //self.library.load_indicator.detach();
  1091. $('.load').detach();
  1092. }
  1093. };
  1094. FatalError.prototype = {
  1095. onError: function(e) {
  1096. var message = e.message;
  1097. //if (typeof e.message == "string")
  1098. // message = message.entityify();
  1099. $( '#parchment' ).append('<div class="error">An error occurred:<br/>' +
  1100. '<pre>' + message + '\n\n' + e.traceback +
  1101. '</pre></div>');
  1102. if ( window.console )
  1103. {
  1104. console.error( message );
  1105. }
  1106. },
  1107. _makeTraceback: function(procs) {
  1108. // This function was taken from gnusto-engine.js and modified.
  1109. var procstring = '';
  1110. var loop_count = 0;
  1111. var loop_max = 100;
  1112. while (procs != null && loop_count < loop_max) {
  1113. var name = procs.toString();
  1114. if (!name) {
  1115. procstring = '\n (anonymous function)'+procstring;
  1116. } else {
  1117. var r = name.match(/function (\w*)/);
  1118. if (!r || !r[1]) {
  1119. procstring = '\n (anonymous function)' + procstring;
  1120. } else {
  1121. procstring = '\n ' + r[1] + procstring;
  1122. }
  1123. }
  1124. try {
  1125. procs = procs.caller;
  1126. } catch (e) {
  1127. // A permission denied error may have just been raised,
  1128. // perhaps because the caller is a chrome function that we
  1129. // can't have access to.
  1130. procs = null;
  1131. }
  1132. loop_count++;
  1133. }
  1134. if (loop_count==loop_max) {
  1135. procstring = '...' + procstring;
  1136. }
  1137. return "Traceback (most recent call last):\n" + procstring;
  1138. }
  1139. };
  1140. })(jQuery);
  1141. /*
  1142. File functions and classes
  1143. ==========================
  1144. Copyright (c) 2008-2014 The Parchment Contributors
  1145. Licenced under the BSD
  1146. http://code.google.com/p/parchment
  1147. */
  1148. /*
  1149. TODO:
  1150. Consider whether it's worth having cross domain requests to things other than the proxy
  1151. Add transport for XDR
  1152. Access buffer if possible (don't change encodings)
  1153. Is the native base64_decode function still useful?
  1154. If such a time comes when everyone has native atob(), then always expose the decoded text in process_binary_XHR()
  1155. If we know we have a string which is latin1 (say from atob()), would it be faster to have a separate text_to_array() that doesn't need to &0xFF?
  1156. Consider combining the eNs together first, then shifting to get the cNs (for the base64 decoder)
  1157. */
  1158. (function(window, $){
  1159. // VBScript code
  1160. if ( window.execScript )
  1161. {
  1162. execScript(
  1163. // Idea from http://stackoverflow.com/questions/1919972/#3050364
  1164. // Convert a byte array (xhr.responseBody) into a 16-bit characters string
  1165. // Javascript code will separate the characters back into 8-bit numbers again
  1166. 'Function VBCStr(x)\n' +
  1167. 'VBCStr=CStr(x)\n' +
  1168. 'End Function\n' +
  1169. // If the byte array has an odd length, this function is needed to get the last byte
  1170. 'Function VBLastAsc(x)\n' +
  1171. 'Dim l\n' +
  1172. 'l=LenB(x)\n' +
  1173. 'If l mod 2 Then\n' +
  1174. 'VBLastAsc=AscB(MidB(x,l,1))\n' +
  1175. 'Else\n' +
  1176. 'VBLastAsc=-1\n' +
  1177. 'End If\n' +
  1178. 'End Function'
  1179. , 'VBScript' );
  1180. }
  1181. var chrome = /chrome\/(\d+)/i.exec( navigator.userAgent ),
  1182. chrome_no_file = chrome && parseInt( chrome[1] ) > 4,
  1183. // Turn Windows-1252 into ISO-8859-1
  1184. // There are only 27 differences, so this is an reasonable strategy
  1185. // If only we could override with ISO-8859-1...
  1186. fixWindows1252 = function( string )
  1187. {
  1188. return string
  1189. .replace( /\u20ac/g, '\x80' ).replace( /\u201a/g, '\x82' ).replace( /\u0192/g, '\x83' )
  1190. .replace( /\u201e/g, '\x84' ).replace( /\u2026/g, '\x85' ).replace( /\u2020/g, '\x86' )
  1191. .replace( /\u2021/g, '\x87' ).replace( /\u02c6/g, '\x88' ).replace( /\u2030/g, '\x89' )
  1192. .replace( /\u0160/g, '\x8a' ).replace( /\u2039/g, '\x8b' ).replace( /\u0152/g, '\x8c' )
  1193. .replace( /\u017d/g, '\x8e' ).replace( /\u2018/g, '\x91' ).replace( /\u2019/g, '\x92' )
  1194. .replace( /\u201c/g, '\x93' ).replace( /\u201d/g, '\x94' ).replace( /\u2022/g, '\x95' )
  1195. .replace( /\u2013/g, '\x96' ).replace( /\u2014/g, '\x97' ).replace( /\u02dc/g, '\x98' )
  1196. .replace( /\u2122/g, '\x99' ).replace( /\u0161/g, '\x9a' ).replace( /\u203a/g, '\x9b' )
  1197. .replace( /\u0153/g, '\x9c' ).replace( /\u017e/g, '\x9e' ).replace( /\u0178/g, '\x9f' );
  1198. },
  1199. // Text to byte array and vice versa
  1200. text_to_array = function(text, array)
  1201. {
  1202. var array = array || [], i = 0, l;
  1203. for (l = text.length % 8; i < l; ++i)
  1204. array.push(text.charCodeAt(i) & 0xff);
  1205. for (l = text.length; i < l;)
  1206. // Unfortunately unless text is cast to a String object there is no shortcut for charCodeAt,
  1207. // and if text is cast to a String object, it's considerably slower.
  1208. array.push(text.charCodeAt(i++) & 0xff, text.charCodeAt(i++) & 0xff, text.charCodeAt(i++) & 0xff, text.charCodeAt(i++) & 0xff,
  1209. text.charCodeAt(i++) & 0xff, text.charCodeAt(i++) & 0xff, text.charCodeAt(i++) & 0xff, text.charCodeAt(i++) & 0xff);
  1210. return array;
  1211. },
  1212. array_to_text = function(array, text)
  1213. {
  1214. // String.fromCharCode can be given an array of numbers if we call apply on it!
  1215. return ( text || '' ) + String.fromCharCode.apply( 1, array );
  1216. },
  1217. // Base64 encoding and decoding
  1218. // Use the native base64 functions if available
  1219. // Run this little function to build the decoder array
  1220. encoder = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',
  1221. decoder = (function()
  1222. {
  1223. var out = [], i = 0;
  1224. for (; i < encoder.length; i++)
  1225. out[encoder.charAt(i)] = i;
  1226. return out;
  1227. })(),
  1228. base64_decode = function(data, out)
  1229. {
  1230. if ( window.atob )
  1231. {
  1232. return text_to_array( atob( data ), out );
  1233. }
  1234. var out = out || [],
  1235. c1, c2, c3, e1, e2, e3, e4,
  1236. i = 0, l = data.length;
  1237. while (i < l)
  1238. {
  1239. e1 = decoder[data.charAt(i++)];
  1240. e2 = decoder[data.charAt(i++)];
  1241. e3 = decoder[data.charAt(i++)];
  1242. e4 = decoder[data.charAt(i++)];
  1243. c1 = (e1 << 2) + (e2 >> 4);
  1244. c2 = ((e2 & 15) << 4) + (e3 >> 2);
  1245. c3 = ((e3 & 3) << 6) + e4;
  1246. out.push(c1, c2, c3);
  1247. }
  1248. if (e4 == 64)
  1249. out.pop();
  1250. if (e3 == 64)
  1251. out.pop();
  1252. return out;
  1253. },
  1254. base64_encode = function(data, out)
  1255. {
  1256. if ( window.btoa )
  1257. {
  1258. return btoa( array_to_text( data, out ) );
  1259. }
  1260. var out = out || '',
  1261. c1, c2, c3, e1, e2, e3, e4,
  1262. i = 0, l = data.length;
  1263. while (i < l)
  1264. {
  1265. c1 = data[i++];
  1266. c2 = data[i++];
  1267. c3 = data[i++];
  1268. e1 = c1 >> 2;
  1269. e2 = ((c1 & 3) << 4) + (c2 >> 4);
  1270. e3 = ((c2 & 15) << 2) + (c3 >> 6);
  1271. e4 = c3 & 63;
  1272. // Consider other string concatenation methods?
  1273. out += (encoder.charAt(e1) + encoder.charAt(e2) + encoder.charAt(e3) + encoder.charAt(e4));
  1274. }
  1275. if (isNaN(c2))
  1276. out = out.slice(0, -2) + '==';
  1277. else if (isNaN(c3))
  1278. out = out.slice(0, -1) + '=';
  1279. return out;
  1280. },
  1281. // Convert IE's byte array to an array we can use
  1282. bytearray_to_array = function( bytearray )
  1283. {
  1284. // VBCStr will convert the byte array into a string, with two bytes combined into one character
  1285. var text = VBCStr( bytearray ),
  1286. // VBLastAsc will return the last character, if the string is of odd length
  1287. last = VBLastAsc( bytearray ),
  1288. result = [],
  1289. i = 0,
  1290. l = text.length % 4,
  1291. thischar;
  1292. while ( i < l )
  1293. {
  1294. result.push(
  1295. ( thischar = text.charCodeAt(i++) ) & 0xff, thischar >> 8
  1296. );
  1297. }
  1298. l = text.length;
  1299. while ( i < l )
  1300. {
  1301. result.push(
  1302. ( thischar = text.charCodeAt(i++) ) & 0xff, thischar >> 8,
  1303. ( thischar = text.charCodeAt(i++) ) & 0xff, thischar >> 8,
  1304. ( thischar = text.charCodeAt(i++) ) & 0xff, thischar >> 8,
  1305. ( thischar = text.charCodeAt(i++) ) & 0xff, thischar >> 8
  1306. );
  1307. }
  1308. if ( last > -1 )
  1309. {
  1310. result.push( last );
  1311. }
  1312. return result;
  1313. },
  1314. // XMLHttpRequest feature support
  1315. xhr = jQuery.ajaxSettings.xhr(),
  1316. support = {
  1317. binary: xhr.overrideMimeType ? 'charset' : ( 'responseBody' in xhr ? 'responseBody' : 0 )
  1318. },
  1319. // Process a binary XHR
  1320. process_binary_XHR = function( data, textStatus, jqXHR )
  1321. {
  1322. var array, buffer, text;
  1323. data = $.trim( data );
  1324. // Decode base64
  1325. if ( jqXHR.mode == 'base64' )
  1326. {
  1327. if ( window.atob )
  1328. {
  1329. text = atob( data );
  1330. array = text_to_array( text );
  1331. }
  1332. else
  1333. {
  1334. array = base64_decode( data );
  1335. }
  1336. }
  1337. // Binary support through charset=windows-1252
  1338. else if ( jqXHR.mode == 'charset' )
  1339. {
  1340. text = fixWindows1252( data );
  1341. array = text_to_array( text );
  1342. }
  1343. // Access responseBody
  1344. else
  1345. {
  1346. array = bytearray_to_array( jqXHR.xhr.responseBody );
  1347. }
  1348. jqXHR.responseArray = array;
  1349. jqXHR.responseText = text;
  1350. };
  1351. // Clean-up the temp XHR used above
  1352. xhr = undefined;
  1353. // Prefilters for binary ajax
  1354. $.ajaxPrefilter( 'binary', function( options, originalOptions, jqXHR )
  1355. {
  1356. // Chrome > 4 doesn't allow file:// to file:// XHR
  1357. // It should however work for the rest of the world, so we have to test here, rather than when first checking for binary support
  1358. var binary = options.isLocal && !options.crossDomain && chrome_no_file ? 0 : support.binary,
  1359. // Expose the real XHR object onto the jqXHR
  1360. XHRFactory = options.xhr;
  1361. options.xhr = function()
  1362. {
  1363. return jqXHR.xhr = XHRFactory.apply( options );
  1364. };
  1365. // Set up the options and jqXHR
  1366. options.binary = binary;
  1367. jqXHR.done( process_binary_XHR );
  1368. // Options for jsonp, which may not be used if we redirect to 'text'
  1369. options.jsonp = false;
  1370. options.jsonpCallback = 'processBase64Zcode';
  1371. jqXHR.mode = 'base64';
  1372. // Load a legacy file
  1373. if ( options.url.slice( -3 ).toLowerCase() == '.js' )
  1374. {
  1375. return 'jsonp';
  1376. }
  1377. // Binary support and same domain: use a normal text handler
  1378. // Encoding stuff is done in the text prefilter below
  1379. if ( binary && !options.crossDomain )
  1380. {
  1381. return 'text';
  1382. }
  1383. // Use a backup legacy file if provided
  1384. if ( options.legacy )
  1385. {
  1386. options.url = options.legacy;
  1387. return 'jsonp';
  1388. }
  1389. // Use the proxy when no binary support || cross domain request
  1390. options.data = 'url=' + options.url;
  1391. options.url = parchment.options.proxy_url;
  1392. if ( binary && $.support.cors )
  1393. {
  1394. return 'text';
  1395. }
  1396. options.data += '&encode=base64&callback=pproxy';
  1397. options.jsonpCallback = 'pproxy';
  1398. return 'jsonp';
  1399. });
  1400. // Set options for binary requests
  1401. $.ajaxPrefilter( 'text', function( options, originalOptions, jqXHR )
  1402. {
  1403. jqXHR.mode = options.binary;
  1404. if ( jqXHR.mode == 'charset' )
  1405. {
  1406. options.mimeType = 'text/plain; charset=windows-1252';
  1407. }
  1408. });
  1409. // Converters are set in intro.js
  1410. /* DEBUG */
  1411. // Download a file to a byte array
  1412. // Note: no longer used by library.js
  1413. function download_to_array( url, callback )
  1414. {
  1415. // Request the file with the binary type
  1416. $.ajax( url, { dataType: 'binary' } )
  1417. .success(function( data, textStatus, jqXHR )
  1418. {
  1419. callback( jqXHR.responseArray );
  1420. });
  1421. }
  1422. /* ENDDEBUG */
  1423. /*
  1424. // Images made from byte arrays
  1425. file.image = base2.Base.extend({
  1426. // Initialise the image with a byte array
  1427. constructor: function init_image(chunk)
  1428. {
  1429. this.chunk = chunk;
  1430. this.dataURI = function create_dataURI()
  1431. {
  1432. // Only create the image when first requested, the encoding could be quite slow
  1433. // Would be good to replace with a getter if it can be done reliably
  1434. var encoded = encode_base64(this.chunk.data);
  1435. if (this.chunk.type == 'PNG ')
  1436. this.URI = 'data:image/png;base64,' + encoded;
  1437. else if (this.chunk.type == 'JPEG')
  1438. this.URI = 'data:image/jpeg;base64,' + encoded;
  1439. this.dataURI = function() {return this.URI;};
  1440. return this.URI;
  1441. };
  1442. }
  1443. });
  1444. */
  1445. // Expose
  1446. window.file = {
  1447. text_to_array: text_to_array,
  1448. array_to_text: array_to_text,
  1449. base64_decode: base64_decode,
  1450. base64_encode: base64_encode,
  1451. support: support
  1452. };
  1453. ;;; window.file.download_to_array = download_to_array;
  1454. })(window, jQuery);
  1455. /*
  1456. Parchment UI
  1457. ============
  1458. Copyright (c) 2008-2011 The Parchment Contributors
  1459. BSD licenced
  1460. http://code.google.com/p/parchment
  1461. */
  1462. /*
  1463. TODO:
  1464. Fix the stylesheets implementation to actually allow enabling/disabling in IE
  1465. */
  1466. (function($){
  1467. var window = this,
  1468. // Map results callback
  1469. results_link = '<p><a href="' + location.href + '?story=http://mirror.ifarchive.org/',
  1470. map_results_callback = function( story )
  1471. {
  1472. return results_link + story.path + '">' + story.desc + '</a></p>';
  1473. };
  1474. // The main UI class
  1475. parchment.lib.UI = Object.subClass({
  1476. init: function( library )
  1477. {
  1478. this.library = library;
  1479. this.panels = {};
  1480. // Load indicator
  1481. this.load_indicator = $( '<div class="dialog load"><p>Parchment is loading.<p>&gt; <blink>_</blink></div>' );
  1482. },
  1483. // Stylesheet management
  1484. // Add some stylesheets, disabled at first
  1485. stylesheet_add: function( /* title, url, ... */ )
  1486. {
  1487. var args = arguments, i;
  1488. for ( i = 1; i < args.length; i++ )
  1489. {
  1490. // The IE way...
  1491. if ( document.createStyleSheet )
  1492. {
  1493. document.createStyleSheet( args[i] );
  1494. }
  1495. // The better way
  1496. else
  1497. {
  1498. $( '<link>', {
  1499. rel: 'alternate stylesheet',
  1500. href: args[i],
  1501. title: args[0],
  1502. type: 'text/css'
  1503. })
  1504. .appendTo( 'head' )
  1505. [0].disabled = true;
  1506. }
  1507. }
  1508. },
  1509. // Switch on/off a stylesheet
  1510. stylesheet_switch: function( title, enable )
  1511. {
  1512. $( 'link[rel*="stylesheet"][title="' + title + '"]' )
  1513. .each( function(){
  1514. this.disabled = !enable;
  1515. });
  1516. },
  1517. // Load panels for the front page
  1518. load_panels: function()
  1519. {
  1520. var panels = parchment.options.panels,
  1521. search_data, search_input, search_results,
  1522. // Perform a search of the archive
  1523. dosearch = function()
  1524. {
  1525. // Filter the archive
  1526. var key = RegExp( search_input.val().replace( ' ', '( )?' ), 'i' ),
  1527. results = $.grep( search_data, function( story ){
  1528. return key.test( story.path + story.desc );
  1529. });
  1530. // Limit to 30 results
  1531. results = results.slice( 0, 30 );
  1532. // Fill the results div
  1533. search_results.html( $.map( results, map_results_callback ).join('') );
  1534. };
  1535. // A search box
  1536. if ( $.inArray( 'search', panels ) != -1 )
  1537. {
  1538. this.panels.search = $( '<div class="panel search"><label for="panel_search">Search the IF Archive for games you can play with Parchment. You might also like to search the <a href="http://ifdb.tads.org">IFDB</a> or the <a href="http://ifwiki.org">IF Wiki</a>.</label><input id="panel_search"><div></div></div>' );
  1539. search_input = this.panels.search.find( 'input' );
  1540. search_results = search_input.next();
  1541. // Load the archive json file
  1542. search_input.keydown(function(){
  1543. search_input.unbind( 'keydown' );
  1544. $.getJSON( 'stories/if-archive.json' )
  1545. .done(function( data ){
  1546. search_data = data;
  1547. // Attach the real handler once the archive's been downloaded, and then run it once
  1548. search_input.keyup( dosearch );
  1549. dosearch();
  1550. });
  1551. });
  1552. }
  1553. // A form to load any story file
  1554. if ( $.inArray( 'url', panels ) != -1 )
  1555. {
  1556. this.panels.url = $( '<form class="panel url"><label for="panel_url">You may use Parchment to play any story file on the internet, simply copy its address here:</label><input id="panel_url" name="story"></form>' );
  1557. }
  1558. this.library.container.append( this.panels[ panels[0] ] );
  1559. this.panels.active = panels[0];
  1560. }
  1561. });
  1562. })(jQuery);
  1563. /*
  1564. The Parchment Library
  1565. =====================
  1566. Copyright (c) 2008-2011 The Parchment Contributors
  1567. BSD licenced
  1568. http://code.google.com/p/parchment
  1569. */
  1570. /*
  1571. TODO:
  1572. Display a more specific error if one was given by the proxy
  1573. */
  1574. (function(window, $){
  1575. var rtitle = /([-\w\s_]+)(\.[\w]+(\.js)?)?$/,
  1576. rjs = /\.js$/,
  1577. // Callback to show an error when the story file wasn't loaded
  1578. story_get_fail = function(){
  1579. throw new FatalError( 'Parchment could not load the story. Check your connection, and that the URL is correct.' );
  1580. },
  1581. // Launcher. Will be run by jQuery.when(). jqXHR is args[2]
  1582. launch_callback = function( args )
  1583. {
  1584. // Hide the load indicator
  1585. $( '.load' ).detach();
  1586. // Create a runner
  1587. var runner = window.runner = new ( window[args[2].vm.runner] || Runner )(
  1588. parchment.options,
  1589. args[2].vm.engine
  1590. ),
  1591. savefile = location.hash;
  1592. // Add the callback
  1593. runner.toParchment = function( event ) { args[2].library.fromRunner( runner, event ); };
  1594. // Load it up!
  1595. runner.fromParchment({
  1596. code: 'load',
  1597. data: ( new parchment.lib.Story( args[2].responseArray ) ).data
  1598. });
  1599. // Restore if we have a savefile
  1600. if ( savefile && savefile != '#' ) // IE will set location.hash for an empty fragment, FF won't
  1601. {
  1602. runner.fromParchment({
  1603. code: 'restore',
  1604. data: file.base64_decode( savefile.slice( 1 ) )
  1605. });
  1606. }
  1607. // Restart if we don't
  1608. else
  1609. {
  1610. runner.fromParchment({ code: 'restart' });
  1611. }
  1612. };
  1613. // Callback to show an error if a VM's dependant scripts could be successfully loaded
  1614. // Currently not usable as errors are not detected :(
  1615. /*scripts_fail = function(){
  1616. throw new FatalError( 'Parchment could not load everything it needed to run this story. Check your connection and try refreshing the page.' );
  1617. };*/
  1618. // A story file
  1619. parchment.lib.Story = IFF.subClass({
  1620. // Parse a zblorb or naked zcode story file
  1621. init: function parse_zblorb(data, story_name)
  1622. {
  1623. this.title = story_name;
  1624. // Check for naked zcode
  1625. // FIXME: This check is way too simple. We should look at
  1626. // some of the other fields as well for sanity-checking.
  1627. if (data[0] < 9)
  1628. {
  1629. //this.filetype = 'zcode';
  1630. this._super();
  1631. this.chunks.push({
  1632. type: 'ZCOD',
  1633. data: data
  1634. });
  1635. this.data = data;
  1636. }
  1637. // Check for naked glulx
  1638. else if (IFF.text_from(data, 0) == 'Glul')
  1639. {
  1640. //this.filetype = 'glulx';
  1641. this._super();
  1642. this.chunks.push({
  1643. type: 'GLUL',
  1644. data: data
  1645. });
  1646. this.data = data;
  1647. }
  1648. // Check for potential zblorb
  1649. else if (IFF.text_from(data, 0) == 'FORM')
  1650. {
  1651. this._super(data);
  1652. if (this.type == 'IFRS')
  1653. {
  1654. // We have Blorb!
  1655. // this.images = [];
  1656. // this.resources = [];
  1657. // Go through the chunks and extract the useful ones
  1658. for (var i = 0, l = this.chunks.length; i < l; i++)
  1659. {
  1660. var type = this.chunks[i].type;
  1661. /*
  1662. if (type == 'RIdx')
  1663. // The Resource Index Chunk, used by parchment for numbering images correctly
  1664. for (var j = 0, c = IFF.num_from(this.chunks[i].data, 0); j < c; j++)
  1665. this.resources.push({
  1666. usage: IFF.text_from(this.chunks[i].data, 4 + j * 12),
  1667. number: IFF.num_from(this.chunks[i].data, 8 + j * 12),
  1668. start: IFF.num_from(this.chunks[i].data, 12 + j * 12)
  1669. });
  1670. */
  1671. // Parchment uses the first ZCOD/GLUL chunk it finds, but the Blorb spec says the RIdx chunk should be used
  1672. if ( type == 'ZCOD' && !this.zcode )
  1673. {
  1674. this.data = this.chunks[i].data;
  1675. }
  1676. else if ( type == 'GLUL' && !this.glulx )
  1677. {
  1678. this.data = this.chunks[i].data;
  1679. }
  1680. else if (type == 'IFmd')
  1681. {
  1682. // Treaty of Babel metadata
  1683. // Will most likely break UTF-8
  1684. this.metadata = file.array_to_text(this.chunks[i].data);
  1685. var metadataDOM = $(this.metadata);
  1686. if (metadataDOM)
  1687. {
  1688. //this.metadataDOM = metadataDOM;
  1689. // Extract some useful info
  1690. if ($('title', metadataDOM))
  1691. this.title = $('title', metadataDOM).text();
  1692. if ($('ifid', metadataDOM))
  1693. this.ifid = $('ifid', metadataDOM).text();
  1694. if ($('release', metadataDOM))
  1695. this.release = $('release', metadataDOM).text();
  1696. }
  1697. }
  1698. /*
  1699. else if (type == 'PNG ' || type == 'JPEG')
  1700. for (var j = 0, c = this.resources.length; j < c; j++)
  1701. {
  1702. if (this.resources[j].usage == 'Pict' && this.resources[j].start == this.chunks[i].offset)
  1703. // A numbered image!
  1704. this.images[this.resources[j].number] = new image(this.chunks[i]);
  1705. }
  1706. else if (type == 'Fspc')
  1707. this.frontispiece = IFF.num_from(this.chunks[i].data, 0);
  1708. */
  1709. }
  1710. /* if (this.zcode)
  1711. this.filetype = 'ok story blorbed zcode';
  1712. else
  1713. this.filetype = 'error: no zcode in blorb';
  1714. */ }
  1715. /* // Not a blorb
  1716. else if (this.type == 'IFZS')
  1717. this.filetype = 'error: trying to load a Quetzal savefile';
  1718. else
  1719. this.filetype = 'error unknown iff';
  1720. */ }
  1721. /* else
  1722. // Not a story file
  1723. this.filetype = 'error unknown general';
  1724. */ }
  1725. });
  1726. // Story file cache
  1727. var StoryCache = Object.subClass({
  1728. // Add a story to the cache
  1729. add: function(story)
  1730. {
  1731. this[story.ifid] = story;
  1732. if (story.url)
  1733. this.url[story.url] = story;
  1734. },
  1735. url: {}
  1736. }),
  1737. // The Parchment Library class
  1738. Library = Object.subClass({
  1739. // Set up the library
  1740. init: function()
  1741. {
  1742. // Keep a reference to our container
  1743. this.container = $( parchment.options.container );
  1744. this.ui = new parchment.lib.UI( this );
  1745. },
  1746. // Load a story or savefile
  1747. load: function( id )
  1748. {
  1749. var self = this,
  1750. options = parchment.options,
  1751. storyfile = urloptions.story,
  1752. storyName,
  1753. url,
  1754. vm = urloptions.vm,
  1755. i = 0;
  1756. // Run the default story only
  1757. if ( options.lock_story )
  1758. {
  1759. // Locked to the default story
  1760. storyfile = options.default_story;
  1761. if ( !storyfile )
  1762. {
  1763. throw new FatalError( 'Story file not specified' );
  1764. }
  1765. }
  1766. // Load the requested story or the default story
  1767. else if ( options.default_story || storyfile )
  1768. {
  1769. // Load from URL, or the default story
  1770. storyfile = storyfile || options.default_story;
  1771. }
  1772. // Show the library
  1773. else
  1774. {
  1775. return this.ui.load_panels();
  1776. }
  1777. // Hide the #about, until we can do something more smart with it
  1778. $('#about').remove();
  1779. // Show the load indicator
  1780. $( 'body' ).append( self.ui.load_indicator );
  1781. // Normalise the storyfile array
  1782. if ( !$.isArray( storyfile ) )
  1783. {
  1784. storyfile = [ storyfile, 0 ];
  1785. }
  1786. url = storyfile[0];
  1787. self.url = url;
  1788. storyName = rtitle.exec( url );
  1789. storyName = storyName ? storyName[1] + " - Parchment" : "Parchment";
  1790. // Change the page title
  1791. if ( options.page_title )
  1792. {
  1793. window.document.title = storyName;
  1794. }
  1795. // Check the story cache first
  1796. //if ( self.stories.url[url] )
  1797. // var story = self.stories.url[url];
  1798. // We will have to download it
  1799. //else
  1800. //{
  1801. // If a VM was explicitly specified, use it
  1802. if ( vm )
  1803. {
  1804. vm = parchment.vms[ vm ];
  1805. }
  1806. // Otherwise test each in turn
  1807. else
  1808. {
  1809. for ( ; i < parchment.vms.length; i++ )
  1810. {
  1811. if ( parchment.vms[i].match.test( url ) )
  1812. {
  1813. vm = parchment.vms[i];
  1814. break;
  1815. }
  1816. }
  1817. }
  1818. // Raise an error if we have no VM
  1819. if ( !vm )
  1820. {
  1821. throw new FatalError( 'File type is not supported!' );
  1822. }
  1823. // Launch the story with the VM
  1824. try
  1825. {
  1826. this.launch( vm, storyfile );
  1827. }
  1828. catch (e)
  1829. {
  1830. throw new FatalError( e );
  1831. }
  1832. //}
  1833. },
  1834. // Get all the required files and launch the VM
  1835. launch: function( vm, storyfile )
  1836. {
  1837. var self = this,
  1838. // Load the story file
  1839. actions = [
  1840. $.ajax( storyfile[0], { dataType: 'binary', legacy: storyfile[1] } )
  1841. // Attach the library for the launcher to use (yay for chaining)
  1842. .done( function( data, textStatus, jqXHR )
  1843. {
  1844. jqXHR.library = self;
  1845. jqXHR.vm = vm;
  1846. })
  1847. // Some error in downloading
  1848. .fail( story_get_fail )
  1849. ],
  1850. // Get the scripts if they haven't been loaded already
  1851. /* DEBUG */
  1852. scripts = [$.Deferred()],
  1853. script_callback = function()
  1854. {
  1855. if ( vm.files.length == 0 )
  1856. {
  1857. scripts[0].resolve();
  1858. return;
  1859. }
  1860. var dependency = parchment.options.lib_path + vm.files.shift();
  1861. if ( rjs.test( dependency ) )
  1862. {
  1863. $.getScript( dependency, script_callback );
  1864. }
  1865. // CSS
  1866. else
  1867. {
  1868. parchment.library.ui.stylesheet_add( vm.id, dependency );
  1869. script_callback();
  1870. }
  1871. },
  1872. /* ELSEDEBUG
  1873. scripts = [],
  1874. /* ENDDEBUG */
  1875. i = 0,
  1876. dependency;
  1877. if ( !vm.loaded )
  1878. {
  1879. vm.loaded = 1;
  1880. /* DEBUG */
  1881. script_callback();
  1882. /* ELSEDEBUG
  1883. while ( i < vm.files.length )
  1884. {
  1885. dependency = parchment.options.lib_path + vm.files[i++];
  1886. // JS
  1887. if ( rjs.test( dependency ) )
  1888. {
  1889. scripts.push( $.getScript( dependency ) );
  1890. }
  1891. // CSS
  1892. else
  1893. {
  1894. this.ui.stylesheet_add( vm.id, dependency );
  1895. }
  1896. }
  1897. /* ENDDEBUG */
  1898. // Use jQuery.when() to get a promise for all of the scripts
  1899. actions[1] = $.when.apply( 1, scripts );
  1900. //.fail( scripts_fail );
  1901. }
  1902. // Add the launcher callback
  1903. $.when.apply( 1, actions )
  1904. .done( launch_callback );
  1905. },
  1906. // An event from a runner
  1907. fromRunner: function( runner, event )
  1908. {
  1909. var code = event.code,
  1910. savefile = location.hash;
  1911. if ( code == 'save' )
  1912. {
  1913. location.hash = file.base64_encode( event.data );
  1914. }
  1915. if ( code == 'restore' )
  1916. {
  1917. if ( savefile && savefile != '#' )
  1918. {
  1919. event.data = file.base64_decode( savefile.slice( 1 ) );
  1920. }
  1921. }
  1922. runner.fromParchment( event );
  1923. },
  1924. // Loaded stories and savefiles
  1925. stories: new StoryCache(),
  1926. savefiles: {}
  1927. });
  1928. parchment.lib.Library = Library;
  1929. // VM definitions
  1930. parchment.vms = [];
  1931. parchment.add_vm = function( defn )
  1932. {
  1933. parchment.vms.push( defn );
  1934. parchment.vms[defn.id] = defn;
  1935. };
  1936. })(window, jQuery);
  1937. /*
  1938. Quixe definition
  1939. ================
  1940. Copyright (c) 2013 The Parchment Contributors
  1941. BSD licenced
  1942. https://github.com/curiousdannii/parchment
  1943. */
  1944. parchment.add_vm({
  1945. id: 'quixe',
  1946. // File pattern
  1947. match: /(ulx|glb|(g|glulx.+)(blorb|blb))(.js)?$/i,
  1948. // Files to load
  1949. files: DEBUG ? [
  1950. '../src/quixe/prototype-1.6.1.js',
  1951. 'glkote.debug.js',
  1952. 'quixe.debug.js',
  1953. 'glkote.debug.css'
  1954. ] : [
  1955. 'prototype.min.js',
  1956. 'glkote.min.js',
  1957. 'quixe.min.js',
  1958. 'glkote.min.css'
  1959. ],
  1960. runner: 'QuixeRunner'
  1961. });
  1962. /*
  1963. The ifvms.js VM definitions
  1964. ===========================
  1965. Copyright (c) 2013 The Parchment Contributors
  1966. BSD licenced
  1967. https://github.com/curiousdannii/parchment
  1968. */
  1969. parchment.add_vm({
  1970. id: 'zvm',
  1971. // File pattern
  1972. match: /(z[58]|zlb|(z|zcode.+)(blorb|blb))(.js)?$/i,
  1973. // Files to load
  1974. files: DEBUG ? [ 'zvm.debug.js' ] : [ 'zvm.min.js' ],
  1975. engine: 'ZVM'
  1976. });
  1977. /*
  1978. Gnusto definition
  1979. =================
  1980. Copyright (c) 2013 The Parchment Contributors
  1981. BSD licenced
  1982. https://github.com/curiousdannii/parchment
  1983. */
  1984. parchment.add_vm({
  1985. id: 'gnusto',
  1986. // File pattern
  1987. match: /(z[1-8]|zlb|(z|zcode.+)(blorb|blb))(.js)?$/i,
  1988. // Files to load
  1989. files: DEBUG ? [ 'gnusto.debug.js' ] : [ 'gnusto.min.js' ],
  1990. runner: 'GnustoRunner'
  1991. });
  1992. /*
  1993. Parchment load scripts
  1994. ======================
  1995. Copyright (c) 2008-2011 The Parchment Contributors
  1996. BSD licenced
  1997. http://code.google.com/p/parchment
  1998. */
  1999. // Load Parchment, start it all up!
  2000. $(function()
  2001. {
  2002. var library;
  2003. // Check for any customised options
  2004. if ( window.parchment_options )
  2005. {
  2006. $.extend( parchment.options, parchment_options );
  2007. }
  2008. // Load additional options from the query string
  2009. // Is a try/catch needed?
  2010. if ( !parchment.options.lock_options && urloptions.options )
  2011. {
  2012. $.extend( parchment.options, $.parseJSON( urloptions.options ) );
  2013. }
  2014. // Some extra debug options
  2015. /* DEBUG */
  2016. parchment.options.debug = urloptions.debug;
  2017. /* ENDDEBUG */
  2018. // Load the library
  2019. library = new parchment.lib.Library();
  2020. parchment.library = library;
  2021. library.load();
  2022. // Add the Analytics tracker, but only if we're at iplayif.com
  2023. if ( location.href.indexOf( 'iplayif.com' ) != -1 )
  2024. {
  2025. $.getScript( 'http://google-analytics.com/ga.js', function(){_gat._getTracker( 'UA-7949545-3' )._trackPageview();} );
  2026. }
  2027. });
  2028. })( this, jQuery );