1
0

MDwiki.js 123 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873
  1. (function () {
  2. /**
  3. * Block-Level Grammar
  4. */
  5. var block = {
  6. newline: /^\n+/,
  7. code: /^( {4}[^\n]+\n*)+/,
  8. fences: noop,
  9. hr: /^( *[-*_]){3,} *(?:\n+|$)/,
  10. heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
  11. nptable: noop,
  12. lheading: /^([^\n]+)\n *(=|-){3,} *\n*/,
  13. blockquote: /^( *>[^\n]+(\n[^\n]+)*\n*)+/,
  14. list: /^( *)(bull) [\s\S]+?(?:hr|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
  15. html: /^ *(?:comment|closed|closing) *(?:\n{2,}|\s*$)/,
  16. def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
  17. table: noop,
  18. paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
  19. text: /^[^\n]+/,
  20. };
  21. block.bullet = /(?:[*+-]|\d+\.)/;
  22. block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
  23. block.item = replace(block.item, "gm")(/bull/g, block.bullet)();
  24. block.list = replace(block.list)(/bull/g, block.bullet)("hr", /\n+(?=(?: *[-*_]){3,} *(?:\n+|$))/)();
  25. block._tag =
  26. "(?!(?:" +
  27. "a|em|strong|small|s|cite|q|dfn|abbr|data|time|code" +
  28. "|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo" +
  29. "|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|@)\\b";
  30. block.html = replace(block.html)("comment", /<!--[\s\S]*?-->/)("closed", /<(tag)[\s\S]+?<\/\1>/)(
  31. "closing",
  32. /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/
  33. )(/tag/g, block._tag)();
  34. block.paragraph = replace(block.paragraph)("hr", block.hr)("heading", block.heading)("lheading", block.lheading)(
  35. "blockquote",
  36. block.blockquote
  37. )("tag", "<" + block._tag)("def", block.def)();
  38. /**
  39. * Normal Block Grammar
  40. */
  41. block.normal = merge({}, block);
  42. /**
  43. * GFM Block Grammar
  44. */
  45. block.gfm = merge({}, block.normal, {
  46. fences: /^ *(`{3,}|~{3,}) *(\S+)? *\n([\s\S]+?)\s*\1 *(?:\n+|$)/,
  47. paragraph: /^/,
  48. });
  49. block.gfm.paragraph = replace(block.paragraph)(
  50. "(?!",
  51. "(?!" + block.gfm.fences.source.replace("\\1", "\\2") + "|"
  52. )();
  53. /**
  54. * GFM + Tables Block Grammar
  55. */
  56. block.tables = merge({}, block.gfm, {
  57. nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
  58. table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/,
  59. });
  60. /**
  61. * Block Lexer
  62. */
  63. function Lexer(options) {
  64. this.tokens = [];
  65. this.tokens.links = {};
  66. this.options = options || marked.defaults;
  67. this.rules = block.normal;
  68. if (this.options.gfm) {
  69. if (this.options.tables) {
  70. this.rules = block.tables;
  71. } else {
  72. this.rules = block.gfm;
  73. }
  74. }
  75. }
  76. /**
  77. * Expose Block Rules
  78. */
  79. Lexer.rules = block;
  80. /**
  81. * Static Lex Method
  82. */
  83. Lexer.lex = function (src, options) {
  84. var lexer = new Lexer(options);
  85. return lexer.lex(src);
  86. };
  87. /**
  88. * Preprocessing
  89. */
  90. Lexer.prototype.lex = function (src) {
  91. src = src
  92. .replace(/\r\n|\r/g, "\n")
  93. .replace(/\t/g, " ")
  94. .replace(/\u00a0/g, " ")
  95. .replace(/\u2424/g, "\n");
  96. return this.token(src, true);
  97. };
  98. /**
  99. * Lexing
  100. */
  101. Lexer.prototype.token = function (src, top) {
  102. var src = src.replace(/^ +$/gm, ""),
  103. next,
  104. loose,
  105. cap,
  106. bull,
  107. b,
  108. item,
  109. space,
  110. i,
  111. l;
  112. while (src) {
  113. // newline
  114. if ((cap = this.rules.newline.exec(src))) {
  115. src = src.substring(cap[0].length);
  116. if (cap[0].length > 1) {
  117. this.tokens.push({
  118. type: "space",
  119. });
  120. }
  121. }
  122. // code
  123. if ((cap = this.rules.code.exec(src))) {
  124. src = src.substring(cap[0].length);
  125. cap = cap[0].replace(/^ {4}/gm, "");
  126. this.tokens.push({
  127. type: "code",
  128. text: !this.options.pedantic ? cap.replace(/\n+$/, "") : cap,
  129. });
  130. continue;
  131. }
  132. // fences (gfm)
  133. if ((cap = this.rules.fences.exec(src))) {
  134. src = src.substring(cap[0].length);
  135. this.tokens.push({
  136. type: "code",
  137. lang: cap[2],
  138. text: cap[3],
  139. });
  140. continue;
  141. }
  142. // heading
  143. if ((cap = this.rules.heading.exec(src))) {
  144. src = src.substring(cap[0].length);
  145. this.tokens.push({
  146. type: "heading",
  147. depth: cap[1].length,
  148. text: cap[2],
  149. });
  150. continue;
  151. }
  152. // table no leading pipe (gfm)
  153. if (top && (cap = this.rules.nptable.exec(src))) {
  154. src = src.substring(cap[0].length);
  155. item = {
  156. type: "table",
  157. header: cap[1].replace(/^ *| *\| *$/g, "").split(/ *\| */),
  158. align: cap[2].replace(/^ *|\| *$/g, "").split(/ *\| */),
  159. cells: cap[3].replace(/\n$/, "").split("\n"),
  160. };
  161. for (i = 0; i < item.align.length; i++) {
  162. if (/^ *-+: *$/.test(item.align[i])) {
  163. item.align[i] = "right";
  164. } else if (/^ *:-+: *$/.test(item.align[i])) {
  165. item.align[i] = "center";
  166. } else if (/^ *:-+ *$/.test(item.align[i])) {
  167. item.align[i] = "left";
  168. } else {
  169. item.align[i] = null;
  170. }
  171. }
  172. for (i = 0; i < item.cells.length; i++) {
  173. item.cells[i] = item.cells[i].split(/ *\| */);
  174. }
  175. this.tokens.push(item);
  176. continue;
  177. }
  178. // lheading
  179. if ((cap = this.rules.lheading.exec(src))) {
  180. src = src.substring(cap[0].length);
  181. this.tokens.push({
  182. type: "heading",
  183. depth: cap[2] === "=" ? 1 : 2,
  184. text: cap[1],
  185. });
  186. continue;
  187. }
  188. // hr
  189. if ((cap = this.rules.hr.exec(src))) {
  190. src = src.substring(cap[0].length);
  191. this.tokens.push({
  192. type: "hr",
  193. });
  194. continue;
  195. }
  196. // blockquote
  197. if ((cap = this.rules.blockquote.exec(src))) {
  198. src = src.substring(cap[0].length);
  199. this.tokens.push({
  200. type: "blockquote_start",
  201. });
  202. cap = cap[0].replace(/^ *> ?/gm, "");
  203. // Pass `top` to keep the current
  204. // "toplevel" state. This is exactly
  205. // how markdown.pl works.
  206. this.token(cap, top);
  207. this.tokens.push({
  208. type: "blockquote_end",
  209. });
  210. continue;
  211. }
  212. // list
  213. if ((cap = this.rules.list.exec(src))) {
  214. src = src.substring(cap[0].length);
  215. bull = cap[2];
  216. this.tokens.push({
  217. type: "list_start",
  218. ordered: bull.length > 1,
  219. });
  220. // Get each top-level item.
  221. cap = cap[0].match(this.rules.item);
  222. next = false;
  223. l = cap.length;
  224. i = 0;
  225. for (; i < l; i++) {
  226. item = cap[i];
  227. // Remove the list item's bullet
  228. // so it is seen as the next token.
  229. space = item.length;
  230. item = item.replace(/^ *([*+-]|\d+\.) +/, "");
  231. // Outdent whatever the
  232. // list item contains. Hacky.
  233. if (~item.indexOf("\n ")) {
  234. space -= item.length;
  235. item = !this.options.pedantic
  236. ? item.replace(new RegExp("^ {1," + space + "}", "gm"), "")
  237. : item.replace(/^ {1,4}/gm, "");
  238. }
  239. // Determine whether the next list item belongs here.
  240. // Backpedal if it does not belong in this list.
  241. if (this.options.smartLists && i !== l - 1) {
  242. b = block.bullet.exec(cap[i + 1])[0];
  243. if (bull !== b && !(bull.length > 1 && b.length > 1)) {
  244. src = cap.slice(i + 1).join("\n") + src;
  245. i = l - 1;
  246. }
  247. }
  248. // Determine whether item is loose or not.
  249. // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
  250. // for discount behavior.
  251. loose = next || /\n\n(?!\s*$)/.test(item);
  252. if (i !== l - 1) {
  253. next = item[item.length - 1] === "\n";
  254. if (!loose) loose = next;
  255. }
  256. this.tokens.push({
  257. type: loose ? "loose_item_start" : "list_item_start",
  258. });
  259. // Recurse.
  260. this.token(item, false);
  261. this.tokens.push({
  262. type: "list_item_end",
  263. });
  264. }
  265. this.tokens.push({
  266. type: "list_end",
  267. });
  268. continue;
  269. }
  270. // html
  271. if ((cap = this.rules.html.exec(src))) {
  272. src = src.substring(cap[0].length);
  273. this.tokens.push({
  274. type: this.options.sanitize ? "paragraph" : "html",
  275. pre: cap[1] === "pre" || cap[1] === "script",
  276. text: cap[0],
  277. });
  278. continue;
  279. }
  280. // def
  281. if (top && (cap = this.rules.def.exec(src))) {
  282. src = src.substring(cap[0].length);
  283. this.tokens.links[cap[1].toLowerCase()] = {
  284. href: cap[2],
  285. title: cap[3],
  286. };
  287. continue;
  288. }
  289. // table (gfm)
  290. if (top && (cap = this.rules.table.exec(src))) {
  291. src = src.substring(cap[0].length);
  292. item = {
  293. type: "table",
  294. header: cap[1].replace(/^ *| *\| *$/g, "").split(/ *\| */),
  295. align: cap[2].replace(/^ *|\| *$/g, "").split(/ *\| */),
  296. cells: cap[3].replace(/(?: *\| *)?\n$/, "").split("\n"),
  297. };
  298. for (i = 0; i < item.align.length; i++) {
  299. if (/^ *-+: *$/.test(item.align[i])) {
  300. item.align[i] = "right";
  301. } else if (/^ *:-+: *$/.test(item.align[i])) {
  302. item.align[i] = "center";
  303. } else if (/^ *:-+ *$/.test(item.align[i])) {
  304. item.align[i] = "left";
  305. } else {
  306. item.align[i] = null;
  307. }
  308. }
  309. for (i = 0; i < item.cells.length; i++) {
  310. item.cells[i] = item.cells[i].replace(/^ *\| *| *\| *$/g, "").split(/ *\| */);
  311. }
  312. this.tokens.push(item);
  313. continue;
  314. }
  315. // top-level paragraph
  316. if (top && (cap = this.rules.paragraph.exec(src))) {
  317. src = src.substring(cap[0].length);
  318. this.tokens.push({
  319. type: "paragraph",
  320. text: cap[1][cap[1].length - 1] === "\n" ? cap[1].slice(0, -1) : cap[1],
  321. });
  322. continue;
  323. }
  324. // text
  325. if ((cap = this.rules.text.exec(src))) {
  326. // Top-level should never reach here.
  327. src = src.substring(cap[0].length);
  328. this.tokens.push({
  329. type: "text",
  330. text: cap[0],
  331. });
  332. continue;
  333. }
  334. if (src) {
  335. throw new Error("Infinite loop on byte: " + src.charCodeAt(0));
  336. }
  337. }
  338. return this.tokens;
  339. };
  340. /**
  341. * Inline-Level Grammar
  342. */
  343. var inline = {
  344. escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
  345. autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
  346. url: noop,
  347. tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
  348. link: /^!?\[(inside)\]\(href\)/,
  349. reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
  350. nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
  351. strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
  352. em: /^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
  353. code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
  354. br: /^ {2,}\n(?!\s*$)/,
  355. del: noop,
  356. text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/,
  357. };
  358. inline._inside = /(?:\[[^\]]*\]|[^\]]|\](?=[^\[]*\]))*/;
  359. inline._href = /\s*<?(.*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
  360. inline.link = replace(inline.link)("inside", inline._inside)("href", inline._href)();
  361. inline.reflink = replace(inline.reflink)("inside", inline._inside)();
  362. /**
  363. * Normal Inline Grammar
  364. */
  365. inline.normal = merge({}, inline);
  366. /**
  367. * Pedantic Inline Grammar
  368. */
  369. inline.pedantic = merge({}, inline.normal, {
  370. strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
  371. em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/,
  372. });
  373. /**
  374. * GFM Inline Grammar
  375. */
  376. inline.gfm = merge({}, inline.normal, {
  377. escape: replace(inline.escape)("])", "~|])")(),
  378. url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
  379. del: /^~~(?=\S)([\s\S]*?\S)~~/,
  380. text: replace(inline.text)("]|", "~]|")("|", "|https?://|")(),
  381. });
  382. /**
  383. * GFM + Line Breaks Inline Grammar
  384. */
  385. inline.breaks = merge({}, inline.gfm, {
  386. br: replace(inline.br)("{2,}", "*")(),
  387. text: replace(inline.gfm.text)("{2,}", "*")(),
  388. });
  389. /**
  390. * Inline Lexer & Compiler
  391. */
  392. function InlineLexer(links, options) {
  393. this.options = options || marked.defaults;
  394. this.links = links;
  395. this.rules = inline.normal;
  396. if (!this.links) {
  397. throw new Error("Tokens array requires a `links` property.");
  398. }
  399. if (this.options.gfm) {
  400. if (this.options.breaks) {
  401. this.rules = inline.breaks;
  402. } else {
  403. this.rules = inline.gfm;
  404. }
  405. } else if (this.options.pedantic) {
  406. this.rules = inline.pedantic;
  407. }
  408. }
  409. /**
  410. * Expose Inline Rules
  411. */
  412. InlineLexer.rules = inline;
  413. /**
  414. * Static Lexing/Compiling Method
  415. */
  416. InlineLexer.output = function (src, links, options) {
  417. var inline = new InlineLexer(links, options);
  418. return inline.output(src);
  419. };
  420. /**
  421. * Lexing/Compiling
  422. */
  423. InlineLexer.prototype.output = function (src) {
  424. var out = "",
  425. link,
  426. text,
  427. href,
  428. cap;
  429. while (src) {
  430. // escape
  431. if ((cap = this.rules.escape.exec(src))) {
  432. src = src.substring(cap[0].length);
  433. out += cap[1];
  434. continue;
  435. }
  436. // autolink
  437. if ((cap = this.rules.autolink.exec(src))) {
  438. src = src.substring(cap[0].length);
  439. if (cap[2] === "@") {
  440. text = cap[1][6] === ":" ? this.mangle(cap[1].substring(7)) : this.mangle(cap[1]);
  441. href = this.mangle("mailto:") + text;
  442. } else {
  443. text = escape(cap[1]);
  444. href = text;
  445. }
  446. out += '<a href="' + href + '">' + text + "</a>";
  447. continue;
  448. }
  449. // url (gfm)
  450. if ((cap = this.rules.url.exec(src))) {
  451. src = src.substring(cap[0].length);
  452. text = escape(cap[1]);
  453. href = text;
  454. out += '<a href="' + href + '">' + text + "</a>";
  455. continue;
  456. }
  457. // tag
  458. if ((cap = this.rules.tag.exec(src))) {
  459. src = src.substring(cap[0].length);
  460. out += this.options.sanitize ? escape(cap[0]) : cap[0];
  461. continue;
  462. }
  463. // link
  464. if ((cap = this.rules.link.exec(src))) {
  465. src = src.substring(cap[0].length);
  466. out += this.outputLink(cap, {
  467. href: cap[2],
  468. title: cap[3],
  469. });
  470. continue;
  471. }
  472. // reflink, nolink
  473. if ((cap = this.rules.reflink.exec(src)) || (cap = this.rules.nolink.exec(src))) {
  474. src = src.substring(cap[0].length);
  475. link = (cap[2] || cap[1]).replace(/\s+/g, " ");
  476. link = this.links[link.toLowerCase()];
  477. if (!link || !link.href) {
  478. out += cap[0][0];
  479. src = cap[0].substring(1) + src;
  480. continue;
  481. }
  482. out += this.outputLink(cap, link);
  483. continue;
  484. }
  485. // strong
  486. if ((cap = this.rules.strong.exec(src))) {
  487. src = src.substring(cap[0].length);
  488. out += "<strong>" + this.output(cap[2] || cap[1]) + "</strong>";
  489. continue;
  490. }
  491. // em
  492. if ((cap = this.rules.em.exec(src))) {
  493. src = src.substring(cap[0].length);
  494. out += "<em>" + this.output(cap[2] || cap[1]) + "</em>";
  495. continue;
  496. }
  497. // code
  498. if ((cap = this.rules.code.exec(src))) {
  499. src = src.substring(cap[0].length);
  500. out += "<code>" + escape(cap[2], true) + "</code>";
  501. continue;
  502. }
  503. // br
  504. if ((cap = this.rules.br.exec(src))) {
  505. src = src.substring(cap[0].length);
  506. out += "<br>";
  507. continue;
  508. }
  509. // del (gfm)
  510. if ((cap = this.rules.del.exec(src))) {
  511. src = src.substring(cap[0].length);
  512. out += "<del>" + this.output(cap[1]) + "</del>";
  513. continue;
  514. }
  515. // text
  516. if ((cap = this.rules.text.exec(src))) {
  517. src = src.substring(cap[0].length);
  518. out += escape(cap[0]);
  519. continue;
  520. }
  521. if (src) {
  522. throw new Error("Infinite loop on byte: " + src.charCodeAt(0));
  523. }
  524. }
  525. return out;
  526. };
  527. /**
  528. * Compile Link
  529. */
  530. InlineLexer.prototype.outputLink = function (cap, link) {
  531. if (cap[0][0] !== "!") {
  532. return (
  533. '<a href="' +
  534. escape(link.href) +
  535. '"' +
  536. (link.title ? ' title="' + escape(link.title) + '"' : "") +
  537. ">" +
  538. this.output(cap[1]) +
  539. "</a>"
  540. );
  541. } else {
  542. return (
  543. '<img src="' +
  544. escape(link.href) +
  545. '" alt="' +
  546. escape(cap[1]) +
  547. '"' +
  548. (link.title ? ' title="' + escape(link.title) + '"' : "") +
  549. ">"
  550. );
  551. }
  552. };
  553. /**
  554. * Smartypants Transformations
  555. */
  556. InlineLexer.prototype.smartypants = function (text) {
  557. if (!this.options.smartypants) return text;
  558. return text
  559. .replace(/--/g, "—")
  560. .replace(/'([^']*)'/g, "‘$1’")
  561. .replace(/"([^"]*)"/g, "“$1”")
  562. .replace(/\.{3}/g, "…");
  563. };
  564. /**
  565. * Mangle Links
  566. */
  567. InlineLexer.prototype.mangle = function (text) {
  568. var out = "",
  569. l = text.length,
  570. i = 0,
  571. ch;
  572. for (; i < l; i++) {
  573. ch = text.charCodeAt(i);
  574. if (Math.random() > 0.5) {
  575. ch = "x" + ch.toString(16);
  576. }
  577. out += "&#" + ch + ";";
  578. }
  579. return out;
  580. };
  581. /**
  582. * Parsing & Compiling
  583. */
  584. function Parser(options) {
  585. this.tokens = [];
  586. this.token = null;
  587. this.options = options || marked.defaults;
  588. }
  589. /**
  590. * Static Parse Method
  591. */
  592. Parser.parse = function (src, options) {
  593. var parser = new Parser(options);
  594. return parser.parse(src);
  595. };
  596. /**
  597. * Parse Loop
  598. */
  599. Parser.prototype.parse = function (src) {
  600. this.inline = new InlineLexer(src.links, this.options);
  601. this.tokens = src.reverse();
  602. var out = "";
  603. while (this.next()) {
  604. out += this.tok();
  605. }
  606. return out;
  607. };
  608. /**
  609. * Next Token
  610. */
  611. Parser.prototype.next = function () {
  612. return (this.token = this.tokens.pop());
  613. };
  614. /**
  615. * Preview Next Token
  616. */
  617. Parser.prototype.peek = function () {
  618. return this.tokens[this.tokens.length - 1] || 0;
  619. };
  620. /**
  621. * Parse Text Tokens
  622. */
  623. Parser.prototype.parseText = function () {
  624. var body = this.token.text;
  625. while (this.peek().type === "text") {
  626. body += "\n" + this.next().text;
  627. }
  628. return this.inline.output(body);
  629. };
  630. /**
  631. * Parse Current Token
  632. */
  633. Parser.prototype.tok = function () {
  634. switch (this.token.type) {
  635. case "space": {
  636. return "";
  637. }
  638. case "hr": {
  639. return "<hr>\n";
  640. }
  641. case "heading": {
  642. return (
  643. "<h" +
  644. this.token.depth +
  645. ">" +
  646. this.inline.output(this.token.text) +
  647. "</h" +
  648. this.token.depth +
  649. ">\n"
  650. );
  651. }
  652. case "code": {
  653. if (this.options.highlight) {
  654. var code = this.options.highlight(this.token.text, this.token.lang);
  655. if (code != null && code !== this.token.text) {
  656. this.token.escaped = true;
  657. this.token.text = code;
  658. }
  659. }
  660. if (!this.token.escaped) {
  661. this.token.text = escape(this.token.text, true);
  662. }
  663. return (
  664. "<pre><code" +
  665. (this.token.lang ? ' class="' + this.options.langPrefix + this.token.lang + '"' : "") +
  666. ">" +
  667. this.token.text +
  668. "</code></pre>\n"
  669. );
  670. }
  671. case "table": {
  672. var body = "",
  673. heading,
  674. i,
  675. row,
  676. cell,
  677. j;
  678. // header
  679. body += "<thead>\n<tr>\n";
  680. for (i = 0; i < this.token.header.length; i++) {
  681. heading = this.inline.output(this.token.header[i]);
  682. body += this.token.align[i]
  683. ? '<th align="' + this.token.align[i] + '">' + heading + "</th>\n"
  684. : "<th>" + heading + "</th>\n";
  685. }
  686. body += "</tr>\n</thead>\n";
  687. // body
  688. body += "<tbody>\n";
  689. for (i = 0; i < this.token.cells.length; i++) {
  690. row = this.token.cells[i];
  691. body += "<tr>\n";
  692. for (j = 0; j < row.length; j++) {
  693. cell = this.inline.output(row[j]);
  694. body += this.token.align[j]
  695. ? '<td align="' + this.token.align[j] + '">' + cell + "</td>\n"
  696. : "<td>" + cell + "</td>\n";
  697. }
  698. body += "</tr>\n";
  699. }
  700. body += "</tbody>\n";
  701. return "<table>\n" + body + "</table>\n";
  702. }
  703. case "blockquote_start": {
  704. var body = "";
  705. while (this.next().type !== "blockquote_end") {
  706. body += this.tok();
  707. }
  708. return "<blockquote>\n" + body + "</blockquote>\n";
  709. }
  710. case "list_start": {
  711. var type = this.token.ordered ? "ol" : "ul",
  712. body = "";
  713. while (this.next().type !== "list_end") {
  714. body += this.tok();
  715. }
  716. return "<" + type + ">\n" + body + "</" + type + ">\n";
  717. }
  718. case "list_item_start": {
  719. var body = "";
  720. while (this.next().type !== "list_item_end") {
  721. body += this.token.type === "text" ? this.parseText() : this.tok();
  722. }
  723. return "<li>" + body + "</li>\n";
  724. }
  725. case "loose_item_start": {
  726. var body = "";
  727. while (this.next().type !== "list_item_end") {
  728. body += this.tok();
  729. }
  730. return "<li>" + body + "</li>\n";
  731. }
  732. case "html": {
  733. return !this.token.pre && !this.options.pedantic
  734. ? this.inline.output(this.token.text)
  735. : this.token.text;
  736. }
  737. case "paragraph": {
  738. return "<p>" + this.inline.output(this.token.text) + "</p>\n";
  739. }
  740. case "text": {
  741. return "<p>" + this.parseText() + "</p>\n";
  742. }
  743. }
  744. };
  745. /**
  746. * Helpers
  747. */
  748. function escape(html, encode) {
  749. return html
  750. .replace(!encode ? /&(?!#?\w+;)/g : /&/g, "&amp;")
  751. .replace(/</g, "&lt;")
  752. .replace(/>/g, "&gt;")
  753. .replace(/"/g, "&quot;")
  754. .replace(/'/g, "&#39;");
  755. }
  756. function replace(regex, opt) {
  757. regex = regex.source;
  758. opt = opt || "";
  759. return function self(name, val) {
  760. if (!name) return new RegExp(regex, opt);
  761. val = val.source || val;
  762. val = val.replace(/(^|[^\[])\^/g, "$1");
  763. regex = regex.replace(name, val);
  764. return self;
  765. };
  766. }
  767. function noop() {}
  768. noop.exec = noop;
  769. function merge(obj) {
  770. var i = 1,
  771. target,
  772. key;
  773. for (; i < arguments.length; i++) {
  774. target = arguments[i];
  775. for (key in target) {
  776. if (Object.prototype.hasOwnProperty.call(target, key)) {
  777. obj[key] = target[key];
  778. }
  779. }
  780. }
  781. return obj;
  782. }
  783. /**
  784. * Marked
  785. */
  786. function marked(src, opt, callback) {
  787. if (callback || typeof opt === "function") {
  788. if (!callback) {
  789. callback = opt;
  790. opt = null;
  791. }
  792. if (opt) opt = merge({}, marked.defaults, opt);
  793. var tokens = Lexer.lex(tokens, opt),
  794. highlight = opt.highlight,
  795. pending = 0,
  796. l = tokens.length,
  797. i = 0;
  798. if (!highlight || highlight.length < 3) {
  799. return callback(null, Parser.parse(tokens, opt));
  800. }
  801. var done = function () {
  802. delete opt.highlight;
  803. var out = Parser.parse(tokens, opt);
  804. opt.highlight = highlight;
  805. return callback(null, out);
  806. };
  807. for (; i < l; i++) {
  808. (function (token) {
  809. if (token.type !== "code") return;
  810. pending++;
  811. return highlight(token.text, token.lang, function (err, code) {
  812. if (code == null || code === token.text) {
  813. return --pending || done();
  814. }
  815. token.text = code;
  816. token.escaped = true;
  817. --pending || done();
  818. });
  819. })(tokens[i]);
  820. }
  821. return;
  822. }
  823. try {
  824. if (opt) opt = merge({}, marked.defaults, opt);
  825. return Parser.parse(Lexer.lex(src, opt), opt);
  826. } catch (e) {
  827. e.message += "\nPlease report this to https://github.com/chjj/marked.";
  828. if ((opt || marked.defaults).silent) {
  829. return "<p>An error occured:</p><pre>" + escape(e.message + "", true) + "</pre>";
  830. }
  831. throw e;
  832. }
  833. }
  834. /**
  835. * Options
  836. */
  837. marked.options = marked.setOptions = function (opt) {
  838. merge(marked.defaults, opt);
  839. return marked;
  840. };
  841. marked.defaults = {
  842. gfm: true,
  843. tables: true,
  844. breaks: false,
  845. pedantic: false,
  846. sanitize: false,
  847. smartLists: false,
  848. silent: false,
  849. highlight: null,
  850. langPrefix: "lang-",
  851. };
  852. /**
  853. * Expose
  854. */
  855. marked.Parser = Parser;
  856. marked.parser = Parser.parse;
  857. marked.Lexer = Lexer;
  858. marked.lexer = Lexer.lex;
  859. marked.InlineLexer = InlineLexer;
  860. marked.inlineLexer = InlineLexer.output;
  861. marked.parse = marked;
  862. if (typeof exports === "object") {
  863. module.exports = marked;
  864. } else if (typeof define === "function" && define.amd) {
  865. define(function () {
  866. return marked;
  867. });
  868. } else {
  869. this.marked = marked;
  870. }
  871. }).call(
  872. (function () {
  873. return this || (typeof window !== "undefined" ? window : global);
  874. })()
  875. );
  876. (function ($) {
  877. "use strict";
  878. // hide the whole page so we dont see the DOM flickering
  879. // will be shown upon page load complete or error
  880. $("html").addClass("md-hidden-load");
  881. // register our $.md object
  882. $.md = function (method) {
  883. if ($.md.publicMethods[method]) {
  884. return $.md.publicMethods[method].apply(this, Array.prototype.slice.call(arguments, 1));
  885. } else {
  886. $.error("Method " + method + " does not exist on jquery.md");
  887. }
  888. };
  889. // default config
  890. $.md.config = {
  891. title: null,
  892. useSideMenu: true,
  893. lineBreaks: "gfm",
  894. additionalFooterText: "",
  895. anchorCharacter: "&para;",
  896. tocAnchor: "[ &uarr; ]",
  897. };
  898. $.md.gimmicks = [];
  899. $.md.stages = [];
  900. // the location of the main markdown file we display
  901. $.md.mainHref = "";
  902. // the in-page anchor that is specified after the !
  903. $.md.inPageAnchor = "";
  904. $.md.loglevel = {
  905. TRACE: 10,
  906. DEBUG: 20,
  907. INFO: 30,
  908. WARN: 40,
  909. ERROR: 50,
  910. FATAL: 60,
  911. };
  912. // $.md.logThreshold = $.md.loglevel.DEBUG;
  913. $.md.logThreshold = $.md.loglevel.WARN;
  914. })(jQuery);
  915. (function ($) {
  916. "use strict";
  917. $.md.getLogger = function () {
  918. var loglevel = $.md.loglevel;
  919. var log = function (logtarget) {
  920. var self = this;
  921. var level = loglevel[logtarget];
  922. return function (msg) {
  923. if ($.md.logThreshold <= level) {
  924. console.log("[" + logtarget + "] " + msg);
  925. }
  926. };
  927. };
  928. var logger = {};
  929. logger.trace = log("TRACE");
  930. logger.debug = log("DEBUG");
  931. logger.info = log("INFO");
  932. logger.warn = log("WARN");
  933. logger.error = log("ERROR");
  934. logger.fatal = log("FATAL");
  935. return logger;
  936. };
  937. })(jQuery);
  938. (function ($) {
  939. "use strict";
  940. var log = $.md.getLogger();
  941. $.Stage = function (name) {
  942. var self = $.extend($.Deferred(), {});
  943. self.name = name;
  944. self.events = [];
  945. self.started = false;
  946. self.reset = function () {
  947. self.complete = $.Deferred();
  948. self.outstanding = [];
  949. };
  950. self.reset();
  951. self.subscribe = function (fn) {
  952. if (self.started) {
  953. $.error("Subscribing to stage which already started!");
  954. }
  955. self.events.push(fn);
  956. };
  957. self.unsubscribe = function (fn) {
  958. self.events.remove(fn);
  959. };
  960. self.executeSubscribedFn = function (fn) {
  961. var d = $.Deferred();
  962. self.outstanding.push(d);
  963. // display an error if our done() callback is not called
  964. $.md.util.wait(2500).done(function () {
  965. if (d.state() !== "resolved") {
  966. log.fatal(
  967. "Timeout reached for done callback in stage: " +
  968. self.name +
  969. ". Did you forget a done() call in a .subscribe() ?"
  970. );
  971. log.fatal("stage " + name + " failed running subscribed function: " + fn);
  972. }
  973. });
  974. var done = function () {
  975. d.resolve();
  976. };
  977. fn(done);
  978. };
  979. self.run = function () {
  980. self.started = true;
  981. $(self.events).each(function (i, fn) {
  982. self.executeSubscribedFn(fn);
  983. });
  984. // if no events are in our queue, we resolve immediately
  985. if (self.outstanding.length === 0) {
  986. self.resolve();
  987. }
  988. // we resolve when all our registered events have completed
  989. $.when
  990. .apply($, self.outstanding)
  991. .done(function () {
  992. self.resolve();
  993. })
  994. .fail(function () {
  995. self.resolve();
  996. });
  997. };
  998. self.done(function () {
  999. log.debug("stage " + self.name + " completed successfully.");
  1000. });
  1001. self.fail(function () {
  1002. log.debug("stage " + self.name + " completed with errors!");
  1003. });
  1004. return self;
  1005. };
  1006. })(jQuery);
  1007. (function ($) {
  1008. "use strict";
  1009. var log = $.md.getLogger();
  1010. function init() {
  1011. $.md.stages = [
  1012. $.Stage("init"),
  1013. // loads config, initial markdown and navigation
  1014. $.Stage("load"),
  1015. // will transform the markdown to html
  1016. $.Stage("transform"),
  1017. // HTML transformation finished
  1018. $.Stage("ready"),
  1019. // after we have a polished html skeleton
  1020. $.Stage("skel_ready"),
  1021. // will bootstrapify the skeleton
  1022. $.Stage("bootstrap"),
  1023. // before we run any gimmicks
  1024. $.Stage("pregimmick"),
  1025. // after we have bootstrapified the skeleton
  1026. $.Stage("gimmick"),
  1027. // postprocess
  1028. $.Stage("postgimmick"),
  1029. $.Stage("all_ready"),
  1030. // used for integration tests, not intended to use in MDwiki itself
  1031. $.Stage("final_tests"),
  1032. ];
  1033. $.md.stage = function (name) {
  1034. var m = $.grep($.md.stages, function (e, i) {
  1035. return e.name === name;
  1036. });
  1037. if (m.length === 0) {
  1038. $.error("A stage by name " + name + " does not exist");
  1039. } else {
  1040. return m[0];
  1041. }
  1042. };
  1043. }
  1044. init();
  1045. function resetStages() {
  1046. var old_stages = $.md.stages;
  1047. $.md.stages = [];
  1048. $(old_stages).each(function (i, e) {
  1049. $.md.stages.push($.Stage(e.name));
  1050. });
  1051. }
  1052. var publicMethods = {};
  1053. $.md.publicMethods = $.extend({}, $.md.publicMethods, publicMethods);
  1054. function transformMarkdown(markdown) {
  1055. var options = {
  1056. gfm: true,
  1057. tables: true,
  1058. breaks: true,
  1059. };
  1060. if ($.md.config.lineBreaks === "original") options.breaks = false;
  1061. else if ($.md.config.lineBreaks === "gfm") options.breaks = true;
  1062. marked.setOptions(options);
  1063. // get sample markdown
  1064. var uglyHtml = marked(markdown);
  1065. return uglyHtml;
  1066. }
  1067. function registerFetchMarkdown() {
  1068. var md = "";
  1069. $.md.stage("init").subscribe(function (done) {
  1070. var ajaxReq = {
  1071. url: $.md.mainHref,
  1072. dataType: "text",
  1073. };
  1074. // Request the md page
  1075. $.ajax(ajaxReq)
  1076. .done(function (data) {
  1077. md = data;
  1078. done();
  1079. })
  1080. // Failed to find the md page we were looking for
  1081. .fail(function () {
  1082. // Warn that this page wasn't found
  1083. var log = $.md.getLogger();
  1084. log.warn("Could not get " + $.md.mainHref);
  1085. // Attempt to gracefully recover by displaying a user defined 404 page
  1086. ajaxReq.url = "404.md";
  1087. $.ajax(ajaxReq)
  1088. .done(function (data) {
  1089. md = data;
  1090. done();
  1091. })
  1092. // The user has not defined a 404.md.
  1093. .fail(function (data) {
  1094. log.fatal("Could not get a user defined 404.md");
  1095. // Our last attempt to provide a good user expierence by proving a hard coded
  1096. // 'page not found' text.
  1097. md = "# Page Not Found";
  1098. done();
  1099. });
  1100. });
  1101. });
  1102. // find baseUrl
  1103. $.md.stage("transform").subscribe(function (done) {
  1104. var len = $.md.mainHref.lastIndexOf("/");
  1105. var baseUrl = $.md.mainHref.substring(0, len + 1);
  1106. $.md.baseUrl = baseUrl;
  1107. done();
  1108. });
  1109. $.md.stage("transform").subscribe(function (done) {
  1110. var uglyHtml = transformMarkdown(md);
  1111. $("#md-content").html(uglyHtml);
  1112. md = "";
  1113. var dfd = $.Deferred();
  1114. loadExternalIncludes(dfd);
  1115. dfd.always(function () {
  1116. done();
  1117. });
  1118. });
  1119. }
  1120. // load [include](/foo/bar.md) external links
  1121. function loadExternalIncludes(parent_dfd) {
  1122. function findExternalIncludes() {
  1123. return $("a").filter(function () {
  1124. var href = $(this).attr("href");
  1125. var text = $(this).toptext();
  1126. var isMarkdown = $.md.util.hasMarkdownFileExtension(href);
  1127. var isInclude = text === "include";
  1128. var isPreview = text.startsWith("preview:");
  1129. return (isInclude || isPreview) && isMarkdown;
  1130. });
  1131. }
  1132. function selectPreviewElements($jqcol, num_elements) {
  1133. function isTextNode(node) {
  1134. return node.nodeType === 3;
  1135. }
  1136. var count = 0;
  1137. var elements = [];
  1138. $jqcol.each(function (i, e) {
  1139. if (count < num_elements) {
  1140. elements.push(e);
  1141. if (!isTextNode(e)) count++;
  1142. }
  1143. });
  1144. return $(elements);
  1145. }
  1146. var external_links = findExternalIncludes();
  1147. // continue execution when all external resources are fully loaded
  1148. var latch = $.md.util.countDownLatch(external_links.length);
  1149. latch.always(function () {
  1150. parent_dfd.resolve();
  1151. });
  1152. external_links.each(function (i, e) {
  1153. var $el = $(e);
  1154. var href = $el.attr("href");
  1155. var text = $el.toptext();
  1156. $.ajax({
  1157. url: href,
  1158. dataType: "text",
  1159. })
  1160. .done(function (data) {
  1161. var $html = $(transformMarkdown(data));
  1162. if (text.startsWith("preview:")) {
  1163. // only insert the selected number of paragraphs; default 3
  1164. var num_preview_elements = parseInt(text.substring(8), 10) || 3;
  1165. var $preview = selectPreviewElements($html, num_preview_elements);
  1166. $preview.last().append('<a href="' + href + '"> ...read more &#10140;</a>');
  1167. $preview.insertBefore($el.parent("p").eq(0));
  1168. $el.remove();
  1169. } else {
  1170. $html.insertAfter($el.parents("p"));
  1171. $el.remove();
  1172. }
  1173. })
  1174. .always(function () {
  1175. latch.countDown();
  1176. });
  1177. });
  1178. }
  1179. function isSpecialLink(href) {
  1180. if (!href) return false;
  1181. if (href.lastIndexOf("data:") >= 0) return true;
  1182. if (href.startsWith("mailto:")) return true;
  1183. if (href.startsWith("file:")) return true;
  1184. if (href.startsWith("ftp:")) return true;
  1185. // TODO capture more special links: every non-http link with : like
  1186. // torrent:// etc.
  1187. }
  1188. // modify internal links so we load them through our engine
  1189. function processPageLinks(domElement, baseUrl) {
  1190. var html = $(domElement);
  1191. if (baseUrl === undefined) {
  1192. baseUrl = "";
  1193. }
  1194. // HACK against marked: empty links will have empy href attribute
  1195. // we remove the href attribute from the a tag
  1196. html.find("a")
  1197. .not("#md-menu a")
  1198. .filter(function () {
  1199. var $this = $(this);
  1200. var attr = $this.attr("href");
  1201. if (!attr || attr.length === 0) $this.removeAttr("href");
  1202. });
  1203. html.find("a, img").each(function (i, e) {
  1204. var link = $(e);
  1205. // link must be jquery collection
  1206. var isImage = false;
  1207. var hrefAttribute = "href";
  1208. if (!link.attr(hrefAttribute)) {
  1209. isImage = true;
  1210. hrefAttribute = "src";
  1211. }
  1212. var href = link.attr(hrefAttribute);
  1213. if (href && href.lastIndexOf("#!") >= 0) return;
  1214. if (isSpecialLink(href)) return;
  1215. if (!isImage && href.startsWith("#") && !href.startsWith("#!")) {
  1216. // in-page link
  1217. link.click(function (ev) {
  1218. ev.preventDefault();
  1219. $.md.scrollToInPageAnchor(href);
  1220. });
  1221. }
  1222. if (!$.md.util.isRelativeUrl(href)) return;
  1223. if (isImage && !$.md.util.isRelativePath(href)) return;
  1224. if (!isImage && $.md.util.isGimmickLink(link)) return;
  1225. function build_link(url) {
  1226. if ($.md.util.hasMarkdownFileExtension(url)) return "#!" + url;
  1227. else return url;
  1228. }
  1229. var newHref = baseUrl + href;
  1230. if (isImage) link.attr(hrefAttribute, newHref);
  1231. else if ($.md.util.isRelativePath(href)) link.attr(hrefAttribute, build_link(newHref));
  1232. else link.attr(hrefAttribute, build_link(href));
  1233. });
  1234. }
  1235. var navMD = "";
  1236. $.md.NavigationDfd = $.Deferred();
  1237. var ajaxReq = {
  1238. url: "navigation.md",
  1239. dataType: "text",
  1240. };
  1241. $.ajax(ajaxReq)
  1242. .done(function (data) {
  1243. navMD = data;
  1244. $.md.NavigationDfd.resolve();
  1245. })
  1246. .fail(function () {
  1247. $.md.NavigationDfd.reject();
  1248. });
  1249. function registerBuildNavigation() {
  1250. $.md.stage("init").subscribe(function (done) {
  1251. $.md.NavigationDfd.done(function () {
  1252. done();
  1253. }).fail(function () {
  1254. done();
  1255. });
  1256. });
  1257. $.md.stage("transform").subscribe(function (done) {
  1258. if (navMD === "") {
  1259. var log = $.md.getLogger();
  1260. log.info("no navgiation.md found, not using a navbar");
  1261. done();
  1262. return;
  1263. }
  1264. var navHtml = marked(navMD);
  1265. // TODO why are <script> tags from navHtml APPENDED to the jqcol?
  1266. var $h = $("<div>" + navHtml + "</div>");
  1267. // insert <scripts> from navigation.md into the DOM
  1268. $h.each(function (i, e) {
  1269. if (e.tagName === "SCRIPT") {
  1270. $("script").first().before(e);
  1271. }
  1272. });
  1273. // TODO .html() is evil!!!
  1274. var $navContent = $h.eq(0);
  1275. $navContent.find("p").each(function (i, e) {
  1276. var $el = $(e);
  1277. $el.replaceWith($el.html());
  1278. });
  1279. $("#md-menu").append($navContent.html());
  1280. done();
  1281. });
  1282. $.md.stage("bootstrap").subscribe(function (done) {
  1283. processPageLinks($("#md-menu"));
  1284. done();
  1285. });
  1286. $.md.stage("postgimmick").subscribe(function (done) {
  1287. var num_links = $("#md-menu a").length;
  1288. var has_header = $("#md-menu .navbar-brand").eq(0).toptext().trim().length > 0;
  1289. if (!has_header && num_links <= 1) $("#md-menu").hide();
  1290. done();
  1291. });
  1292. }
  1293. $.md.ConfigDfd = $.Deferred();
  1294. $.ajax({ url: "config.json", dataType: "text" })
  1295. .done(function (data) {
  1296. try {
  1297. var data_json = JSON.parse(data);
  1298. $.md.config = $.extend($.md.config, data_json);
  1299. log.info("Found a valid config.json file, using configuration");
  1300. } catch (err) {
  1301. log.error("config.json was not JSON parsable: " + err);
  1302. }
  1303. $.md.ConfigDfd.resolve();
  1304. })
  1305. .fail(function (err, textStatus) {
  1306. log.error("unable to retrieve config.json: " + textStatus);
  1307. $.md.ConfigDfd.reject();
  1308. });
  1309. function registerFetchConfig() {
  1310. $.md.stage("init").subscribe(function (done) {
  1311. // TODO 404 won't get cached, requesting it every reload is not good
  1312. // maybe use cookies? or disable re-loading of the page
  1313. //$.ajax('config.json').done(function(data){
  1314. $.md.ConfigDfd.done(function () {
  1315. done();
  1316. }).fail(function () {
  1317. var log = $.md.getLogger();
  1318. log.info("No config.json found, using default settings");
  1319. done();
  1320. });
  1321. });
  1322. }
  1323. function registerClearContent() {
  1324. $.md.stage("init").subscribe(function (done) {
  1325. $("#md-all").empty();
  1326. var skel =
  1327. '<div id="md-body"><div id="md-title"></div><div id="md-menu">' +
  1328. '</div><div id="md-content"></div></div>';
  1329. $("#md-all").prepend($(skel));
  1330. done();
  1331. });
  1332. }
  1333. function loadContent(href) {
  1334. if (href.startsWith("/")) {
  1335. // prevent cross-domain inclusions to prevent possible XSS
  1336. href = "/./" + href;
  1337. } else {
  1338. href = "./" + href;
  1339. }
  1340. $.md.mainHref = href;
  1341. registerFetchMarkdown();
  1342. registerClearContent();
  1343. // find out which link gimmicks we need
  1344. $.md.stage("ready").subscribe(function (done) {
  1345. $.md.initializeGimmicks();
  1346. $.md.registerLinkGimmicks();
  1347. done();
  1348. });
  1349. // wire up the load method of the modules
  1350. $.each($.md.gimmicks, function (i, module) {
  1351. if (module.load === undefined) {
  1352. return;
  1353. }
  1354. $.md.stage("load").subscribe(function (done) {
  1355. module.load();
  1356. done();
  1357. });
  1358. });
  1359. $.md.stage("ready").subscribe(function (done) {
  1360. $.md("createBasicSkeleton");
  1361. done();
  1362. });
  1363. $.md.stage("bootstrap").subscribe(function (done) {
  1364. $.mdbootstrap("bootstrapify");
  1365. processPageLinks($("#md-content"), $.md.baseUrl);
  1366. done();
  1367. });
  1368. runStages();
  1369. }
  1370. function runStages() {
  1371. // wire the stages up
  1372. $.md.stage("init").done(function () {
  1373. $.md.stage("load").run();
  1374. });
  1375. $.md.stage("load").done(function () {
  1376. $.md.stage("transform").run();
  1377. });
  1378. $.md.stage("transform").done(function () {
  1379. $.md.stage("ready").run();
  1380. });
  1381. $.md.stage("ready").done(function () {
  1382. $.md.stage("skel_ready").run();
  1383. });
  1384. $.md.stage("skel_ready").done(function () {
  1385. $.md.stage("bootstrap").run();
  1386. });
  1387. $.md.stage("bootstrap").done(function () {
  1388. $.md.stage("pregimmick").run();
  1389. });
  1390. $.md.stage("pregimmick").done(function () {
  1391. $.md.stage("gimmick").run();
  1392. });
  1393. $.md.stage("gimmick").done(function () {
  1394. $.md.stage("postgimmick").run();
  1395. });
  1396. $.md.stage("postgimmick").done(function () {
  1397. $.md.stage("all_ready").run();
  1398. });
  1399. $.md.stage("all_ready").done(function () {
  1400. $("html").removeClass("md-hidden-load");
  1401. // phantomjs hook when we are done
  1402. if (typeof window.callPhantom === "function") {
  1403. window.callPhantom({});
  1404. }
  1405. $.md.stage("final_tests").run();
  1406. });
  1407. $.md.stage("final_tests").done(function () {
  1408. // reset the stages for next iteration
  1409. resetStages();
  1410. // required by dalekjs so we can wait the element to appear
  1411. $("body").append('<span id="start-tests"></span>');
  1412. $("#start-tests").hide();
  1413. });
  1414. // trigger the whole process by runing the init stage
  1415. $.md.stage("init").run();
  1416. return;
  1417. }
  1418. function extractHashData() {
  1419. // first char is the # or #!
  1420. var href;
  1421. if (window.location.hash.startsWith("#!")) {
  1422. href = window.location.hash.substring(2);
  1423. } else {
  1424. href = window.location.hash.substring(1);
  1425. }
  1426. href = decodeURIComponent(href);
  1427. // extract possible in-page anchor
  1428. var ex_pos = href.indexOf("#");
  1429. if (ex_pos !== -1) {
  1430. $.md.inPageAnchor = href.substring(ex_pos + 1);
  1431. $.md.mainHref = href.substring(0, ex_pos);
  1432. } else {
  1433. $.md.mainHref = href;
  1434. }
  1435. }
  1436. function appendDefaultFilenameToHash() {
  1437. var newHashString = "";
  1438. var currentHashString = window.location.hash || "";
  1439. if (currentHashString === "" || currentHashString === "#" || currentHashString === "#!") {
  1440. newHashString = "#!index.md";
  1441. } else if (currentHashString.startsWith("#!") && currentHashString.endsWith("/")) {
  1442. newHashString = currentHashString + "index.md";
  1443. }
  1444. if (newHashString) window.location.hash = newHashString;
  1445. }
  1446. $(document).ready(function () {
  1447. // stage init stuff
  1448. registerFetchConfig();
  1449. registerBuildNavigation();
  1450. extractHashData();
  1451. appendDefaultFilenameToHash();
  1452. $(window).bind("hashchange", function () {
  1453. window.location.reload(false);
  1454. });
  1455. loadContent($.md.mainHref);
  1456. });
  1457. })(jQuery);
  1458. (function ($) {
  1459. var publicMethods = {
  1460. isRelativeUrl: function (url) {
  1461. if (url === undefined) {
  1462. return false;
  1463. }
  1464. // if there is :// in it, its considered absolute
  1465. // else its relative
  1466. if (url.indexOf("://") === -1) {
  1467. return true;
  1468. } else {
  1469. return false;
  1470. }
  1471. },
  1472. isRelativePath: function (path) {
  1473. if (path === undefined) return false;
  1474. if (path.startsWith("/")) return false;
  1475. return true;
  1476. },
  1477. isGimmickLink: function (domAnchor) {
  1478. if (domAnchor.toptext().indexOf("gimmick:") !== -1) {
  1479. return true;
  1480. } else {
  1481. return false;
  1482. }
  1483. },
  1484. hasMarkdownFileExtension: function (str) {
  1485. var markdownExtensions = [".md", ".markdown", ".mdown"];
  1486. var result = false;
  1487. var value = str.toLowerCase().split("#")[0];
  1488. $(markdownExtensions).each(function (i, ext) {
  1489. if (value.toLowerCase().endsWith(ext)) {
  1490. result = true;
  1491. }
  1492. });
  1493. return result;
  1494. },
  1495. wait: function (time) {
  1496. return $.Deferred(function (dfd) {
  1497. setTimeout(dfd.resolve, time);
  1498. });
  1499. },
  1500. };
  1501. $.md.util = $.extend({}, $.md.util, publicMethods);
  1502. if (typeof String.prototype.startsWith !== "function") {
  1503. String.prototype.startsWith = function (str) {
  1504. return this.slice(0, str.length) === str;
  1505. };
  1506. }
  1507. if (typeof String.prototype.endsWith !== "function") {
  1508. String.prototype.endsWith = function (str) {
  1509. return this.slice(this.length - str.length, this.length) === str;
  1510. };
  1511. }
  1512. $.fn.extend({
  1513. toptext: function () {
  1514. return this.clone().children().remove().end().text();
  1515. },
  1516. });
  1517. // adds a :icontains selector to jQuery that is case insensitive
  1518. $.expr[":"].icontains = $.expr.createPseudo(function (arg) {
  1519. return function (elem) {
  1520. return $(elem).toptext().toUpperCase().indexOf(arg.toUpperCase()) >= 0;
  1521. };
  1522. });
  1523. $.md.util.getInpageAnchorText = function (text) {
  1524. var subhash = text.replace(/ /g, "_");
  1525. // TODO remove more unwanted characters like ?/,- etc.
  1526. return subhash;
  1527. };
  1528. $.md.util.getInpageAnchorHref = function (text, href) {
  1529. href = href || $.md.mainHref;
  1530. var subhash = $.md.util.getInpageAnchorText(text);
  1531. return "#!" + href + "#" + subhash;
  1532. };
  1533. $.md.util.repeatUntil = function (interval, predicate, maxRepeats) {
  1534. maxRepeats = maxRepeats || 10;
  1535. var dfd = $.Deferred();
  1536. function recursive_repeat(interval, predicate, maxRepeats) {
  1537. if (maxRepeats === 0) {
  1538. dfd.reject();
  1539. return;
  1540. }
  1541. if (predicate()) {
  1542. dfd.resolve();
  1543. return;
  1544. } else {
  1545. $.md.util.wait(interval).always(function () {
  1546. recursive_repeat(interval, predicate, maxRepeats - 1);
  1547. });
  1548. }
  1549. }
  1550. recursive_repeat(interval, predicate, maxRepeats);
  1551. return dfd;
  1552. };
  1553. // a count-down latch as in Java7.
  1554. $.md.util.countDownLatch = function (capacity, min) {
  1555. min = min || 0;
  1556. var dfd = $.Deferred();
  1557. if (capacity <= min) dfd.resolve();
  1558. dfd.capacity = capacity;
  1559. dfd.countDown = function () {
  1560. dfd.capacity--;
  1561. if (dfd.capacity <= min) dfd.resolve();
  1562. };
  1563. return dfd;
  1564. };
  1565. })(jQuery);
  1566. (function ($) {
  1567. "use strict";
  1568. // PUBLIC API
  1569. $.md.registerGimmick = function (module) {
  1570. $.md.gimmicks.push(module);
  1571. return;
  1572. };
  1573. // registers a script for a gimmick, that is later dynamically loaded
  1574. // by the core.
  1575. // src may be an URL or direct javascript sourcecode. When options.callback
  1576. // is provided, the done() function is passed to the function and needs to
  1577. // be called.
  1578. $.md.registerScript = function (module, src, options) {
  1579. var scriptinfo = new ScriptInfo({
  1580. module: module,
  1581. src: src,
  1582. options: options,
  1583. });
  1584. registeredScripts.push(scriptinfo);
  1585. };
  1586. // same as registerScript but for css. Note that we do not provide a
  1587. // callback when the load finishes
  1588. $.md.registerCss = function (module, url, options) {
  1589. var license = options.license,
  1590. stage = options.stage || "skel_ready",
  1591. callback = options.callback;
  1592. checkLicense(license, module);
  1593. var tag = '<link rel="stylesheet" href="' + url + '" type="text/css"></link>';
  1594. $.md.stage(stage).subscribe(function (done) {
  1595. $("head").append(tag);
  1596. if (callback !== undefined) {
  1597. callback(done);
  1598. } else {
  1599. done();
  1600. }
  1601. });
  1602. };
  1603. // turns hostname/path links into http://hostname/path links
  1604. // we need to do this because if accessed by file:///, we need a different
  1605. // transport scheme for external resources (like http://)
  1606. $.md.prepareLink = function (link, options) {
  1607. options = options || {};
  1608. var ownProtocol = window.location.protocol;
  1609. if (options.forceSSL) return "https://" + link;
  1610. if (options.forceHTTP) return "http://" + link;
  1611. if (ownProtocol === "file:") {
  1612. return "http://" + link;
  1613. }
  1614. // default: use the same as origin resource
  1615. return "//" + link;
  1616. };
  1617. // associate a link trigger for a gimmick. i.e. [gimmick:foo]() then
  1618. // foo is the trigger and will invoke the corresponding gimmick
  1619. $.md.linkGimmick = function (module, trigger, callback, stage) {
  1620. if (stage === undefined) {
  1621. stage = "gimmick";
  1622. }
  1623. var linktrigger = new LinkTrigger({
  1624. trigger: trigger,
  1625. module: module,
  1626. stage: stage,
  1627. callback: callback,
  1628. });
  1629. linkTriggers.push(linktrigger);
  1630. };
  1631. $.md.triggerIsActive = function (trigger) {
  1632. if (activeLinkTriggers.indexOf(trigger) === -1) {
  1633. return false;
  1634. } else {
  1635. return true;
  1636. }
  1637. };
  1638. var initialized = false;
  1639. // TODO combine main.js and modules.js closure
  1640. $.md.initializeGimmicks = function () {
  1641. findActiveLinkTrigger();
  1642. runGimmicksOnce();
  1643. loadRequiredScripts();
  1644. };
  1645. // END PUBLIC API
  1646. var log = $.md.getLogger();
  1647. // triggers that we actually found on the page
  1648. // array of string
  1649. var activeLinkTriggers = [];
  1650. // array of ScriptInfo
  1651. var registeredScripts = [];
  1652. function ScriptInfo(initial) {
  1653. this.module = undefined;
  1654. this.options = {};
  1655. // can ba an URL or javascript sourcecode
  1656. this.src = "";
  1657. $.extend(this, initial);
  1658. }
  1659. // array of linkTriggers
  1660. var linkTriggers = [];
  1661. function LinkTrigger(initial) {
  1662. this.trigger = undefined;
  1663. this.module = undefined;
  1664. this.callback = undefined;
  1665. $.extend(this, initial);
  1666. }
  1667. // jQuery does some magic when inserting inline scripts, so better
  1668. // use vanilla JS. See:
  1669. // http://stackoverflow.com/questions/610995/jquery-cant-append-script-element
  1670. function insertInlineScript(src) {
  1671. // scripts always need to go directly into the DOM
  1672. var script = document.createElement("script");
  1673. script.type = "text/javascript";
  1674. script.text = src;
  1675. document.body.appendChild(script);
  1676. }
  1677. // since we are GPL, we have to be cautious what other scripts we load
  1678. // as delivering to the browser is considered delivering a derived work
  1679. var licenses = [
  1680. "MIT",
  1681. "BSD",
  1682. "GPL",
  1683. "GPL2",
  1684. "GPL3",
  1685. "LGPL",
  1686. "LGPL2",
  1687. "APACHE2",
  1688. "PUBLICDOMAIN",
  1689. "EXCEPTION",
  1690. "OTHER",
  1691. ];
  1692. function checkLicense(license, module) {
  1693. if ($.inArray(license, licenses) === -1) {
  1694. var availLicenses = JSON.stringify(licenses);
  1695. log.warn("license " + license + " is not known.");
  1696. log.warn("Known licenses:" + availLicenses);
  1697. } else if (license === "OTHER") {
  1698. log.warn(
  1699. "WARNING: Module " +
  1700. module.name +
  1701. " uses a script" +
  1702. " with unknown license. This may be a GPL license violation if" +
  1703. " this website is publically available!"
  1704. );
  1705. }
  1706. }
  1707. // will actually schedule the script load into the DOM.
  1708. function loadScript(scriptinfo) {
  1709. var module = scriptinfo.module,
  1710. src = scriptinfo.src,
  1711. options = scriptinfo.options;
  1712. var license = options.license || "OTHER",
  1713. loadstage = options.loadstage || "skel_ready",
  1714. finishstage = options.finishstage || "pregimmick",
  1715. callback = options.callback;
  1716. var loadDone = $.Deferred();
  1717. checkLicense(license, module);
  1718. // start script loading
  1719. log.debug("subscribing " + module.name + " to start: " + loadstage + " end in: " + finishstage);
  1720. $.md.stage(loadstage).subscribe(function (done) {
  1721. if (src.startsWith("//") || src.startsWith("http")) {
  1722. $.getScript(src, function () {
  1723. if (callback !== undefined) {
  1724. callback(done);
  1725. } else {
  1726. log.debug("module" + module.name + " script load done: " + src);
  1727. done();
  1728. }
  1729. loadDone.resolve();
  1730. });
  1731. } else {
  1732. // inline script that we directly insert
  1733. insertInlineScript(src);
  1734. log.debug("module" + module.name + " script inject done");
  1735. loadDone.resolve();
  1736. done();
  1737. }
  1738. });
  1739. // if loading is not yet finished in stage finishstage, wait
  1740. // for the loading to complete
  1741. $.md.stage(finishstage).subscribe(function (done) {
  1742. loadDone.done(function () {
  1743. done();
  1744. });
  1745. });
  1746. }
  1747. // finds out that kind of trigger words are acutally used on a given page
  1748. // this is most likely a very small subset of all available gimmicks
  1749. function findActiveLinkTrigger() {
  1750. var $gimmicks = $("a:icontains(gimmick:)");
  1751. $gimmicks.each(function (i, e) {
  1752. var parts = getGimmickLinkParts($(e));
  1753. if (activeLinkTriggers.indexOf(parts.trigger) === -1) {
  1754. activeLinkTriggers.push(parts.trigger);
  1755. }
  1756. });
  1757. log.debug("Scanning for required gimmick links: " + JSON.stringify(activeLinkTriggers));
  1758. }
  1759. function loadRequiredScripts() {
  1760. // find each module responsible for the link trigger
  1761. $.each(activeLinkTriggers, function (i, trigger) {
  1762. var module = findModuleByTrigger(trigger);
  1763. if (module === undefined) {
  1764. log.error('Gimmick link: "' + trigger + '" found but no suitable gimmick loaded');
  1765. return;
  1766. }
  1767. var scriptinfo = registeredScripts.filter(function (info) {
  1768. return info.module.name === module.name;
  1769. })[0];
  1770. // register to load the script
  1771. if (scriptinfo !== undefined) {
  1772. loadScript(scriptinfo);
  1773. }
  1774. });
  1775. }
  1776. function findModuleByTrigger(trigger) {
  1777. var ret;
  1778. $.each(linkTriggers, function (i, e) {
  1779. if (e.trigger === trigger) {
  1780. ret = e.module;
  1781. }
  1782. });
  1783. return ret;
  1784. }
  1785. function getGimmickLinkParts($link) {
  1786. var link_text = $.trim($link.toptext());
  1787. // returns linkTrigger, options, linkText
  1788. if (link_text.match(/gimmick:/i) === null) {
  1789. return null;
  1790. }
  1791. var href = $.trim($link.attr("href"));
  1792. var r = new RegExp(/gimmick:\s*([^(\s]*)\s*(\(\s*{?(.*)\s*}?\s*\))*/i);
  1793. var matches = r.exec(link_text);
  1794. if (matches === null || matches[1] === undefined) {
  1795. $.error("Error matching a gimmick: " + link_text);
  1796. return null;
  1797. }
  1798. var trigger = matches[1].toLowerCase();
  1799. var args = null;
  1800. // getting the parameters
  1801. if (matches[2] !== undefined) {
  1802. // remove whitespaces
  1803. var params = $.trim(matches[3].toString());
  1804. // remove the closing } if present
  1805. if (params.charAt(params.length - 1) === "}") {
  1806. params = params.substring(0, params.length - 1);
  1807. }
  1808. // add surrounding braces and paranthese
  1809. params = "({" + params + "})";
  1810. // replace any single quotes by double quotes
  1811. params = params.replace(/'/g, '"');
  1812. // finally, try if the json object is valid
  1813. try {
  1814. /*jshint -W061 */
  1815. args = eval(params);
  1816. } catch (err) {
  1817. log.error("error parsing argument of gimmick: " + link_text + "giving error: " + err);
  1818. }
  1819. }
  1820. return { trigger: trigger, options: args, href: href };
  1821. }
  1822. function runGimmicksOnce() {
  1823. // runs the once: callback for each gimmick within the init stage
  1824. $.each($.md.gimmicks, function (i, module) {
  1825. if (module.once === undefined) {
  1826. return;
  1827. }
  1828. module.once();
  1829. });
  1830. }
  1831. // activate all gimmicks on a page, that are contain the text gimmick:
  1832. // TODO make private / merge closures
  1833. $.md.registerLinkGimmicks = function () {
  1834. var $gimmick_links = $("a:icontains(gimmick:)");
  1835. $gimmick_links.each(function (i, e) {
  1836. var $link = $(e);
  1837. var gimmick_arguments = getGimmickLinkParts($link);
  1838. $.each(linkTriggers, function (i, linktrigger) {
  1839. if (gimmick_arguments.trigger === linktrigger.trigger) {
  1840. subscribeLinkTrigger($link, gimmick_arguments, linktrigger);
  1841. }
  1842. });
  1843. });
  1844. };
  1845. function subscribeLinkTrigger($link, args, linktrigger) {
  1846. log.debug("Subscribing gimmick " + linktrigger.module.name + " to stage: " + linktrigger.stage);
  1847. $.md.stage(linktrigger.stage).subscribe(function (done) {
  1848. args.options = args.options || {};
  1849. // it is possible that broken modules or any other transformation removed the $link
  1850. // from the dom in the meantime
  1851. if (!jQuery.contains(document.documentElement, $link[0])) {
  1852. log.error("LINK IS NOT IN THE DOM ANYMORE: ");
  1853. console.log($link);
  1854. }
  1855. log.debug("Running gimmick " + linktrigger.module.name);
  1856. linktrigger.callback($link, args.options, args.href, done);
  1857. // if the gimmick didn't call done, we trigger it here
  1858. done();
  1859. });
  1860. }
  1861. })(jQuery);
  1862. (function ($) {
  1863. var publicMethods = {
  1864. createBasicSkeleton: function () {
  1865. setPageTitle();
  1866. wrapParagraphText();
  1867. linkImagesToSelf();
  1868. groupImages();
  1869. removeBreaks();
  1870. addInpageAnchors();
  1871. $.md.stage("all_ready").subscribe(function (done) {
  1872. if ($.md.inPageAnchor !== "") {
  1873. $.md.util.wait(500).then(function () {
  1874. $.md.scrollToInPageAnchor($.md.inPageAnchor);
  1875. });
  1876. }
  1877. done();
  1878. });
  1879. return;
  1880. },
  1881. };
  1882. $.md.publicMethods = $.extend({}, $.md.publicMethods, publicMethods);
  1883. // set the page title to the browser document title, optionally picking
  1884. // the first h1 element as title if no title is given
  1885. function setPageTitle() {
  1886. var $pageTitle;
  1887. if ($.md.config.title) $("title").text($.md.config.title);
  1888. $pageTitle = $("#md-content h1").eq(0);
  1889. if ($.trim($pageTitle.toptext()).length > 0) {
  1890. $("#md-title").prepend($pageTitle);
  1891. var title = $pageTitle.toptext();
  1892. // document.title = title;
  1893. } else {
  1894. $("#md-title").remove();
  1895. }
  1896. }
  1897. function wrapParagraphText() {
  1898. // TODO is this true for marked.js?
  1899. // markdown gives us sometime paragraph that contain child tags (like img),
  1900. // but the containing text is not wrapped. Make sure to wrap the text in the
  1901. // paragraph into a <div>
  1902. // this also moves ANY child tags to the front of the paragraph!
  1903. $("#md-content p").each(function () {
  1904. var $p = $(this);
  1905. // nothing to do for paragraphs without text
  1906. if ($.trim($p.text()).length === 0) {
  1907. // make sure no whitespace are in the p and then exit
  1908. //$p.text ('');
  1909. return;
  1910. }
  1911. // children elements of the p
  1912. var children = $p.contents().filter(function () {
  1913. var $child = $(this);
  1914. // we extract images and hyperlinks with images out of the paragraph
  1915. if (this.tagName === "A" && $child.find("img").length > 0) {
  1916. return true;
  1917. }
  1918. if (this.tagName === "IMG") {
  1919. return true;
  1920. }
  1921. // else
  1922. return false;
  1923. });
  1924. var floatClass = getFloatClass($p);
  1925. $p.wrapInner('<div class="md-text" />');
  1926. // if there are no children, we are done
  1927. if (children.length === 0) {
  1928. return;
  1929. }
  1930. // move the children out of the wrapped div into the original p
  1931. children.prependTo($p);
  1932. // at this point, we now have a paragraph that holds text AND images
  1933. // we mark that paragraph to be a floating environment
  1934. // TODO determine floatenv left/right
  1935. $p.addClass("md-floatenv").addClass(floatClass);
  1936. });
  1937. }
  1938. function removeBreaks() {
  1939. // since we use non-markdown-standard line wrapping, we get lots of
  1940. // <br> elements we don't want.
  1941. // remove a leading <br> from floatclasses, that happen to
  1942. // get insertet after an image
  1943. $(".md-floatenv")
  1944. .find(".md-text")
  1945. .each(function () {
  1946. var $first = $(this).find("*").eq(0);
  1947. if ($first.is("br")) {
  1948. $first.remove();
  1949. }
  1950. });
  1951. // remove any breaks from image groups
  1952. $(".md-image-group").find("br").remove();
  1953. }
  1954. function getFloatClass(par) {
  1955. var $p = $(par);
  1956. var floatClass = "";
  1957. // reduce content of the paragraph to images
  1958. var nonTextContents = $p.contents().filter(function () {
  1959. if (this.tagName === "IMG" || this.tagName === "IFRAME") {
  1960. return true;
  1961. } else if (this.tagName === "A") {
  1962. return $(this).find("img").length > 0;
  1963. } else {
  1964. return $.trim($(this).text()).length > 0;
  1965. }
  1966. });
  1967. // check the first element - if its an image or a link with image, we go left
  1968. var elem = nonTextContents[0];
  1969. if (elem !== undefined && elem !== null) {
  1970. if (elem.tagName === "IMG" || elem.tagName === "IFRAME") {
  1971. floatClass = "md-float-left";
  1972. } else if (elem.tagName === "A" && $(elem).find("img").length > 0) {
  1973. floatClass = "md-float-left";
  1974. } else {
  1975. floatClass = "md-float-right";
  1976. }
  1977. }
  1978. return floatClass;
  1979. }
  1980. // images are put in the same image group as long as there is
  1981. // not separating paragraph between them
  1982. function groupImages() {
  1983. var par = $("p img").parents("p");
  1984. // add an .md-image-group class to the p
  1985. par.addClass("md-image-group");
  1986. }
  1987. // takes a standard <img> tag and adds a hyperlink to the image source
  1988. // needed since we scale down images via css and want them to be accessible
  1989. // in original format
  1990. function linkImagesToSelf() {
  1991. function selectNonLinkedImages() {
  1992. // only select images that do not have a non-empty parent link
  1993. $images = $("img").filter(function (index) {
  1994. var $parent_link = $(this).parents("a").eq(0);
  1995. if ($parent_link.length === 0) return true;
  1996. var attr = $parent_link.attr("href");
  1997. return attr && attr.length === 0;
  1998. });
  1999. return $images;
  2000. }
  2001. var $images = selectNonLinkedImages();
  2002. return $images.each(function () {
  2003. var $this = $(this);
  2004. var img_src = $this.attr("src");
  2005. var img_title = $this.attr("title");
  2006. if (img_title === undefined) {
  2007. img_title = "";
  2008. }
  2009. // wrap the <img> tag in an anchor and copy the title of the image
  2010. $this.wrap('<a class="md-image-selfref" href="' + img_src + '" title="' + img_title + '"/> ');
  2011. });
  2012. }
  2013. function addInpageAnchors() {
  2014. // adds a pilcrow (paragraph) character to heading with a link for the
  2015. // inpage anchor
  2016. function addPilcrow($heading, href) {
  2017. var c = $.md.config.anchorCharacter;
  2018. var $pilcrow = $('<span class="anchor-highlight"><a>' + c + "</a></span>");
  2019. $pilcrow.find("a").attr("href", href);
  2020. $pilcrow.hide();
  2021. var mouse_entered = false;
  2022. $heading.mouseenter(function () {
  2023. mouse_entered = true;
  2024. $.md.util.wait(300).then(function () {
  2025. if (!mouse_entered) return;
  2026. $pilcrow.fadeIn(200);
  2027. });
  2028. });
  2029. $heading.mouseleave(function () {
  2030. mouse_entered = false;
  2031. $pilcrow.fadeOut(200);
  2032. });
  2033. $pilcrow.appendTo($heading);
  2034. }
  2035. // adds a link to the navigation at the top of the page
  2036. function addJumpLinkToTOC($heading) {
  2037. if ($.md.config.useSideMenu === false) return;
  2038. if ($heading.prop("tagName") !== "H2") return;
  2039. var c = $.md.config.tocAnchor;
  2040. if (c === "") return;
  2041. var $jumpLink = $('<a class="visible-xs visible-sm jumplink" href="#md-page-menu">' + c + "</a>");
  2042. $jumpLink.click(function (ev) {
  2043. ev.preventDefault();
  2044. $("body").scrollTop($("#md-page-menu").position().top);
  2045. });
  2046. if ($heading.parents("#md-menu").length === 0) {
  2047. $jumpLink.insertAfter($heading);
  2048. }
  2049. }
  2050. // adds a page inline anchor to each h1,h2,h3,h4,h5,h6 element
  2051. // which can be accessed by the headings text
  2052. $("h1,h2,h3,h4,h5,h6")
  2053. .not("#md-title h1")
  2054. .each(function () {
  2055. var $heading = $(this);
  2056. $heading.addClass("md-inpage-anchor");
  2057. var text = $heading.clone().children(".anchor-highlight").remove().end().text();
  2058. var href = $.md.util.getInpageAnchorHref(text);
  2059. addPilcrow($heading, href);
  2060. //add jumplink to table of contents
  2061. addJumpLinkToTOC($heading);
  2062. });
  2063. }
  2064. $.md.scrollToInPageAnchor = function (anchortext) {
  2065. if (anchortext.startsWith("#")) anchortext = anchortext.substring(1, anchortext.length);
  2066. // we match case insensitive
  2067. var doBreak = false;
  2068. $(".md-inpage-anchor").each(function () {
  2069. if (doBreak) {
  2070. return;
  2071. }
  2072. var $this = $(this);
  2073. // don't use the text of any subnode
  2074. var text = $this.toptext();
  2075. var match = $.md.util.getInpageAnchorText(text);
  2076. if (anchortext === match) {
  2077. this.scrollIntoView(true);
  2078. var navbar_offset = $(".navbar-collapse").height() + 5;
  2079. window.scrollBy(0, -navbar_offset + 5);
  2080. doBreak = true;
  2081. }
  2082. });
  2083. };
  2084. })(jQuery);
  2085. (function ($) {
  2086. "use strict";
  2087. // call the gimmick
  2088. $.mdbootstrap = function (method) {
  2089. if ($.mdbootstrap.publicMethods[method]) {
  2090. return $.mdbootstrap.publicMethods[method].apply(this, Array.prototype.slice.call(arguments, 1));
  2091. } else {
  2092. $.error("Method " + method + " does not exist on jquery.mdbootstrap");
  2093. }
  2094. };
  2095. // simple wrapper around $().bind
  2096. $.mdbootstrap.events = [];
  2097. $.mdbootstrap.bind = function (ev, func) {
  2098. $(document).bind(ev, func);
  2099. $.mdbootstrap.events.push(ev);
  2100. };
  2101. $.mdbootstrap.trigger = function (ev) {
  2102. $(document).trigger(ev);
  2103. };
  2104. var navStyle = "";
  2105. // PUBLIC API functions that are exposed
  2106. var publicMethods = {
  2107. bootstrapify: function () {
  2108. createPageSkeleton();
  2109. buildMenu();
  2110. changeHeading();
  2111. replaceImageParagraphs();
  2112. $("table").addClass("table").addClass("table-bordered");
  2113. //pullRightBumper ();
  2114. // remove the margin for headings h1 and h2 that are the first
  2115. // on page
  2116. //if (navStyle == "sub" || (navStyle == "top" && $('#md-title').text ().trim ().length === 0))
  2117. // $(".md-first-heading").css ("margin-top", "0");
  2118. // external content should run after gimmicks were run
  2119. $.md.stage("pregimmick").subscribe(function (done) {
  2120. if ($.md.config.useSideMenu !== false) {
  2121. createPageContentMenu();
  2122. }
  2123. addAdditionalFooterText();
  2124. done();
  2125. });
  2126. $.md.stage("postgimmick").subscribe(function (done) {
  2127. adjustExternalContent();
  2128. highlightActiveLink();
  2129. done();
  2130. });
  2131. },
  2132. };
  2133. // register the public API functions
  2134. $.mdbootstrap.publicMethods = $.extend({}, $.mdbootstrap.publicMethods, publicMethods);
  2135. // PRIVATE FUNCTIONS:
  2136. function buildTopNav() {
  2137. // replace with the navbar skeleton
  2138. if ($("#md-menu").length <= 0) {
  2139. return;
  2140. }
  2141. navStyle = "top";
  2142. var $menuContent = $("#md-menu").children();
  2143. // $('#md-menu').addClass ('navbar navbar-default navbar-fixed-top');
  2144. // var menusrc = '';
  2145. // menusrc += '<div id="md-menu-inner" class="container">';
  2146. // menusrc += '<ul id="md-menu-ul" class="nav navbar-nav">';
  2147. // menusrc += '</ul></div>';
  2148. var navbar = "";
  2149. navbar += '<div id="md-main-navbar" class="navbar navbar-default navbar-fixed-top" role="navigation">';
  2150. navbar += '<div class="navbar-header">';
  2151. navbar +=
  2152. '<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-ex1-collapse">';
  2153. navbar += '<span class="sr-only">Toggle navigation</span>';
  2154. navbar += '<span class="icon-bar"></span>';
  2155. navbar += '<span class="icon-bar"></span>';
  2156. navbar += '<span class="icon-bar"></span>';
  2157. navbar += "</button>";
  2158. navbar += '<a class="navbar-brand" href="#"></a>';
  2159. navbar += "</div>";
  2160. navbar += '<div class="collapse navbar-collapse navbar-ex1-collapse">';
  2161. navbar += '<ul class="nav navbar-nav" />';
  2162. navbar += '<ul class="nav navbar-nav navbar-right" />';
  2163. navbar += "</div>";
  2164. navbar += "</div>";
  2165. var $navbar = $(navbar);
  2166. $navbar.appendTo("#md-menu");
  2167. // .eq(0) becase we dont want navbar-right to be appended to
  2168. $("#md-menu ul.nav").eq(0).append($menuContent);
  2169. // the menu should be the first element in the body
  2170. $("#md-menu").prependTo("#md-all");
  2171. var brand_text = $("#md-menu h1").toptext();
  2172. $("#md-menu h1").remove();
  2173. $("a.navbar-brand").text(brand_text);
  2174. // initial offset
  2175. $("#md-body").css("margin-top", "70px");
  2176. $.md.stage("pregimmick").subscribe(function (done) {
  2177. check_offset_to_navbar();
  2178. done();
  2179. });
  2180. }
  2181. // the navbar has different height depending on theme, number of navbar entries,
  2182. // and window/device width. Therefore recalculate on start and upon window resize
  2183. function set_offset_to_navbar() {
  2184. var height = $("#md-main-navbar").height() + 10;
  2185. $("#md-body").css("margin-top", height + "px");
  2186. }
  2187. function check_offset_to_navbar() {
  2188. // HACK this is VERY UGLY. When an external theme is used, we don't know when the
  2189. // css style will be finished loading - and we can only correctly calculate
  2190. // the height AFTER it has completely loaded.
  2191. var navbar_height = 0;
  2192. var dfd1 = $.md.util.repeatUntil(
  2193. 40,
  2194. function () {
  2195. navbar_height = $("#md-main-navbar").height();
  2196. return navbar_height > 35 && navbar_height < 481;
  2197. },
  2198. 25
  2199. );
  2200. dfd1.done(function () {
  2201. navbar_height = $("#md-main-navbar").height();
  2202. set_offset_to_navbar();
  2203. // now bootstrap changes this maybe after a while, again watch for changes
  2204. var dfd2 = $.md.util.repeatUntil(
  2205. 20,
  2206. function () {
  2207. return navbar_height !== $("#md-main-navbar").height();
  2208. },
  2209. 25
  2210. );
  2211. dfd2.done(function () {
  2212. // it changed, so we need to change it again
  2213. set_offset_to_navbar();
  2214. });
  2215. // and finally, for real slow computers, make sure it is changed if changin very late
  2216. $.md.util.wait(2000).done(function () {
  2217. set_offset_to_navbar();
  2218. });
  2219. });
  2220. }
  2221. function buildSubNav() {
  2222. // replace with the navbar skeleton
  2223. /* BROKEN CODE
  2224. if ($('#md-menu').length <= 0) {
  2225. return;
  2226. }
  2227. navStyle = 'sub';
  2228. var $menuContent = $('#md-menu').html ();
  2229. var menusrc = '';
  2230. menusrc += '<div id="md-menu-inner" class="subnav">';
  2231. menusrc += '<ul id="md-menu-ul" class="nav nav-pills">';
  2232. menusrc += $menuContent;
  2233. menusrc += '</ul></div>';
  2234. $('#md-menu').empty();
  2235. $('#md-menu').wrapInner($(menusrc));
  2236. $('#md-menu').addClass ('col-md-12');
  2237. $('#md-menu-container').insertAfter ($('#md-title-container'));
  2238. */
  2239. }
  2240. function buildMenu() {
  2241. if ($("#md-menu a").length === 0) {
  2242. return;
  2243. }
  2244. var h = $("#md-menu");
  2245. // make toplevel <a> a dropdown
  2246. h.find('> a[href=""]')
  2247. .attr("data-toggle", "dropdown")
  2248. .addClass("dropdown-toggle")
  2249. .attr("href", "")
  2250. .append('<b class="caret"/>');
  2251. h.find("ul").addClass("dropdown-menu");
  2252. h.find("ul li").addClass("dropdown");
  2253. // replace hr with dividers
  2254. $("#md-menu hr").each(function (i, e) {
  2255. var hr = $(e);
  2256. var prev = hr.prev();
  2257. var next = hr.next();
  2258. if (prev.is("ul") && prev.length >= 0) {
  2259. prev.append($('<li class="divider"/>'));
  2260. hr.remove();
  2261. if (next.is("ul")) {
  2262. next.find("li").appendTo(prev);
  2263. next.remove();
  2264. }
  2265. // next ul should now be empty
  2266. }
  2267. return;
  2268. });
  2269. // remove empty uls
  2270. $("#md-menu ul").each(function (i, e) {
  2271. var ul = $(e);
  2272. if (ul.find("li").length === 0) {
  2273. ul.remove();
  2274. }
  2275. });
  2276. $("#md-menu hr").replaceWith($('<li class="divider-vertical"/>'));
  2277. // wrap the toplevel links in <li>
  2278. $("#md-menu > a").wrap("<li />");
  2279. $("#md-menu ul").each(function (i, e) {
  2280. var ul = $(e);
  2281. ul.appendTo(ul.prev());
  2282. ul.parent("li").addClass("dropdown");
  2283. });
  2284. // submenu headers
  2285. $("#md-menu li.dropdown")
  2286. .find("h1, h2, h3")
  2287. .each(function (i, e) {
  2288. var $e = $(e);
  2289. var text = $e.toptext();
  2290. var header = $('<li class="dropdown-header" />');
  2291. header.text(text);
  2292. $e.replaceWith(header);
  2293. });
  2294. // call the user specifed menu function
  2295. buildTopNav();
  2296. }
  2297. function isVisibleInViewport(e) {
  2298. var el = $(e);
  2299. var top = $(window).scrollTop();
  2300. var bottom = top + $(window).height();
  2301. var eltop = el.offset().top;
  2302. var elbottom = eltop + el.height();
  2303. return elbottom <= bottom && eltop >= top;
  2304. }
  2305. function createPageContentMenu() {
  2306. // assemble the menu
  2307. var $headings = $("#md-content").find("h2").clone();
  2308. // we dont want the text of any child nodes
  2309. $headings.children().remove();
  2310. if ($headings.length <= 1) {
  2311. return;
  2312. }
  2313. $("#md-content").removeClass("col-md-12");
  2314. $("#md-content").addClass("col-md-9");
  2315. $("#md-content-row").prepend('<div class="col-md-3" id="md-left-column"/>');
  2316. var recalc_width = function () {
  2317. // if the page menu is affixed, it is not a child of the
  2318. // <md-left-column> anymore and therefore does not inherit
  2319. // its width. On every resize, change the class accordingly
  2320. var width_left_column = $("#md-left-column").css("width");
  2321. $("#md-page-menu").css("width", width_left_column);
  2322. };
  2323. $(window).scroll(function () {
  2324. recalc_width($("#md-page-menu"));
  2325. var $first;
  2326. $("*.md-inpage-anchor").each(function (i, e) {
  2327. if ($first === undefined) {
  2328. var h = $(e);
  2329. if (isVisibleInViewport(h)) {
  2330. $first = h;
  2331. }
  2332. }
  2333. });
  2334. // highlight in the right menu
  2335. $("#md-page-menu a").each(function (i, e) {
  2336. var $a = $(e);
  2337. if ($first && $a.toptext() === $first.toptext()) {
  2338. $("#md-page-menu a.active").removeClass("active");
  2339. //$a.parent('a').addClass('active');
  2340. $a.addClass("active");
  2341. }
  2342. });
  2343. });
  2344. var affixDiv = $('<div id="md-page-menu" />');
  2345. //var top_spacing = $('#md-menu').height() + 15;
  2346. var top_spacing = 70;
  2347. affixDiv.affix({
  2348. //offset: affix.position() - 50,
  2349. offset: 130,
  2350. });
  2351. affixDiv.css("top", top_spacing);
  2352. //affix.css('top','-250px');
  2353. var $pannel = $('<div class="panel panel-default"><ul class="list-group"/></div>');
  2354. var $ul = $pannel.find("ul");
  2355. affixDiv.append($pannel);
  2356. $headings.each(function (i, e) {
  2357. var $heading = $(e);
  2358. var $li = $('<li class="list-group-item" />');
  2359. var $a = $("<a />");
  2360. $a.attr("href", $.md.util.getInpageAnchorHref($heading.toptext()));
  2361. $a.click(function (ev) {
  2362. ev.preventDefault();
  2363. var $this = $(this);
  2364. var anchortext = $.md.util.getInpageAnchorText($this.toptext());
  2365. $.md.scrollToInPageAnchor(anchortext);
  2366. });
  2367. $a.text($heading.toptext());
  2368. $li.append($a);
  2369. $ul.append($li);
  2370. });
  2371. $(window).resize(function () {
  2372. recalc_width($("#md-page-menu"));
  2373. check_offset_to_navbar();
  2374. });
  2375. $.md.stage("postgimmick").subscribe(function (done) {
  2376. // recalc_width();
  2377. done();
  2378. });
  2379. //menu.css('width','100%');
  2380. $("#md-left-column").append(affixDiv);
  2381. }
  2382. function createPageSkeleton() {
  2383. $("#md-title").wrap('<div class="container" id="md-title-container"/>');
  2384. $("#md-title").wrap('<div class="row" id="md-title-row"/>');
  2385. $("#md-menu").wrap('<div class="container" id="md-menu-container"/>');
  2386. $("#md-menu").wrap('<div class="row" id="md-menu-row"/>');
  2387. $("#md-content").wrap('<div class="container" id="md-content-container"/>');
  2388. $("#md-content").wrap('<div class="row" id="md-content-row"/>');
  2389. $("#md-body").wrap('<div class="container" id="md-body-container"/>');
  2390. $("#md-body").wrap('<div class="row" id="md-body-row"/>');
  2391. $("#md-title").addClass("col-md-12");
  2392. $("#md-content").addClass("col-md-12");
  2393. }
  2394. function pullRightBumper() {
  2395. /* $("span.bumper").each (function () {
  2396. $this = $(this);
  2397. $this.prev().addClass ("pull-right");
  2398. });
  2399. $('span.bumper').addClass ('pull-right');
  2400. */
  2401. }
  2402. function changeHeading() {
  2403. // HEADING
  2404. var jumbo = $('<div class="page-header" />');
  2405. $("#md-title").wrapInner(jumbo);
  2406. }
  2407. function highlightActiveLink() {
  2408. // when no menu is used, return
  2409. if ($("#md-menu").find("li").length === 0) {
  2410. return;
  2411. }
  2412. var filename = window.location.hash;
  2413. if (filename.length === 0) {
  2414. filename = "#!index.md";
  2415. }
  2416. var selector = 'li:has(a[href="' + filename + '"])';
  2417. $("#md-menu").find(selector).addClass("active");
  2418. }
  2419. // replace all <p> around images with a <div class="thumbnail" >
  2420. function replaceImageParagraphs() {
  2421. // only select those paragraphs that have images in them
  2422. var $pars = $("p img").parents("p");
  2423. $pars.each(function () {
  2424. var $p = $(this);
  2425. var $images = $(this)
  2426. .find("img")
  2427. .filter(function () {
  2428. // only select those images that have no parent anchor
  2429. return $(this).parents("a").length === 0;
  2430. })
  2431. // add those anchors including images
  2432. .add($(this).find("img"))
  2433. .addClass("img-responsive")
  2434. .addClass("img-thumbnail");
  2435. // create a new url group at the fron of the paragraph
  2436. //$p.prepend($('<ul class="thumbnails" />'));
  2437. // move the images to the newly created ul
  2438. //$p.find('ul').eq(0).append($images);
  2439. // wrap each image with a <li> that limits their space
  2440. // the number of images in a paragraphs determines thei width / span
  2441. // if the image is a link, wrap around the link to avoid
  2442. function wrapImage($imgages, wrapElement) {
  2443. return $images.each(function (i, img) {
  2444. var $img = $(img);
  2445. var $parent_img = $img.parent("a");
  2446. if ($parent_img.length > 0) $parent_img.wrap(wrapElement);
  2447. else $img.wrap(wrapElement);
  2448. });
  2449. }
  2450. if ($p.hasClass("md-floatenv")) {
  2451. if ($images.length === 1) {
  2452. wrapImage($images, '<div class="col-sm-8" />');
  2453. } else if ($images.length === 2) {
  2454. wrapImage($images, '<div class="col-sm-4" />');
  2455. } else {
  2456. wrapImage($images, '<div class="col-sm-2" />');
  2457. }
  2458. } else {
  2459. // non-float => images are on their own single paragraph, make em larger
  2460. // but remember, our image resizing will make them only as large as they are
  2461. // but do no upscaling
  2462. // TODO replace by calculation
  2463. if ($images.length === 1) {
  2464. wrapImage($images, '<div class="col-sm-12" />');
  2465. } else if ($images.length === 2) {
  2466. wrapImage($images, '<div class="col-sm-6" />');
  2467. } else if ($images.length === 3) {
  2468. wrapImage($images, '<div class="col-sm-4" />');
  2469. } else if ($images.length === 4) {
  2470. wrapImage($images, '<div class="col-sm-3" />');
  2471. } else {
  2472. wrapImage($images, '<div class="col-sm-2" />');
  2473. }
  2474. }
  2475. $p.addClass("row");
  2476. // finally, every img gets its own wrapping thumbnail div
  2477. //$images.wrap('<div class="thumbnail" />');
  2478. });
  2479. // apply float to the ul thumbnails
  2480. //$('.md-floatenv.md-float-left ul').addClass ('pull-left');
  2481. //$('.md-floatenv.md-float-right ul').addClass ('pull-right');
  2482. }
  2483. function adjustExternalContent() {
  2484. // external content are usually iframes or divs that are integrated
  2485. // by gimmicks
  2486. // example: youtube iframes, google maps div canvas
  2487. // all external content are in the md-external class
  2488. $("iframe.md-external").not(".md-external-nowidth").attr("width", "450").css("width", "450px");
  2489. $("iframe.md-external").not(".md-external-noheight").attr("height", "280").css("height", "280px");
  2490. // make it appear like an image thumbnal
  2491. //$('.md-external').addClass('img-thumbnail');
  2492. //.wrap($("<ul class='thumbnails' />")).wrap($("<li class='col-md-6' />"));
  2493. $("div.md-external").not(".md-external-noheight").css("height", "280px");
  2494. $("div.md-external").not(".md-external-nowidth").css("width", "450px");
  2495. // // make it appear like an image thumbnal
  2496. // $("div.md-external").addClass("thumbnail").wrap($("<ul class='thumbnails' />")).wrap($("<li class='col-md-10' />"));
  2497. // $("div.md-external-large").css('width', "700px")
  2498. }
  2499. // note: the footer is part of the GPLv3 legal information
  2500. // and may not be removed or hidden to comply with licensing conditions.
  2501. function addFooter() {
  2502. var navbar = "";
  2503. navbar += '<hr><div class="scontainer">';
  2504. navbar += '<div class="pull-right md-copyright-footer"> ';
  2505. navbar += '<span id="md-footer-additional"></span>';
  2506. navbar += 'Website generated with <a href="http://www.mdwiki.info">MDwiki</a> ';
  2507. navbar += "&copy; Timo D&ouml;rr and contributors. ";
  2508. navbar += "</div>";
  2509. navbar += "</div>";
  2510. var $navbar = $(navbar);
  2511. $navbar.css("position", "relative");
  2512. $navbar.css("margin-top", "1em");
  2513. $("#md-all").append($navbar);
  2514. }
  2515. function addAdditionalFooterText() {
  2516. var text = $.md.config.additionalFooterText;
  2517. if (text) {
  2518. $(".md-copyright-footer #md-footer-additional").html(text);
  2519. }
  2520. }
  2521. })(jQuery);
  2522. (function ($) {
  2523. $.gimmicks = $.fn.gimmicks = function (method) {
  2524. if (method === undefined) {
  2525. return;
  2526. }
  2527. // call the gimmick
  2528. if ($.fn.gimmicks.methods[method]) {
  2529. return $.fn.gimmicks.methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
  2530. } else {
  2531. $.error("Gimmick " + method + " does not exist on jQuery.gimmicks");
  2532. }
  2533. };
  2534. // TODO underscores _ in Markdown links are not allowed! bug in our MD imlemenation
  2535. })(jQuery);
  2536. (function ($) {
  2537. //'use strict';
  2538. var alertsGimmick = {
  2539. name: "alerts",
  2540. // TODO
  2541. //version: $.md.version,
  2542. load: function () {
  2543. $.md.stage("bootstrap").subscribe(function (done) {
  2544. createAlerts();
  2545. done();
  2546. });
  2547. },
  2548. };
  2549. $.md.registerGimmick(alertsGimmick);
  2550. // takes a standard <img> tag and adds a hyperlink to the image source
  2551. // needed since we scale down images via css and want them to be accessible
  2552. // in original format
  2553. function createAlerts() {
  2554. var matches = $(select_paragraphs());
  2555. matches.each(function () {
  2556. var $p = $(this.p);
  2557. var type = this.alertType;
  2558. $p.addClass("alert");
  2559. if (type === "note") {
  2560. $p.addClass("alert-info");
  2561. } else if (type === "hint") {
  2562. $p.addClass("alert-success");
  2563. } else if (type === "warning") {
  2564. $p.addClass("alert-warning");
  2565. }
  2566. });
  2567. }
  2568. // picks out the paragraphs that start with a trigger word
  2569. function select_paragraphs() {
  2570. var note = ["note", "beachte"];
  2571. var warning = ["achtung", "attention", "warnung", "warning", "atención", "guarda", "advertimiento"];
  2572. var hint = ["hint", "tipp", "tip", "hinweis"];
  2573. var exp = note.concat(warning);
  2574. exp = exp.concat(hint);
  2575. var matches = [];
  2576. $("p").filter(function () {
  2577. var $par = $(this);
  2578. // check against each expression
  2579. $(exp).each(function (i, trigger) {
  2580. var txt = $par.text().toLowerCase();
  2581. // we match only paragrachps in which the 'trigger' expression
  2582. // is follow by a ! or :
  2583. var re = new RegExp(trigger + "(:|!)+.*", "i");
  2584. var alertType = "none";
  2585. if (txt.match(re) !== null) {
  2586. if ($.inArray(trigger, note) >= 0) {
  2587. alertType = "note";
  2588. } else if ($.inArray(trigger, warning) >= 0) {
  2589. alertType = "warning";
  2590. } else if ($.inArray(trigger, hint) >= 0) {
  2591. alertType = "hint";
  2592. }
  2593. matches.push({
  2594. p: $par,
  2595. alertType: alertType,
  2596. });
  2597. }
  2598. });
  2599. });
  2600. return matches;
  2601. }
  2602. })(jQuery);
  2603. (function ($) {
  2604. // makes trouble, find out why
  2605. //'use strict';
  2606. var colorboxGimmick = {
  2607. name: "colorbox",
  2608. load: function () {
  2609. $.md.stage("gimmick").subscribe(function (done) {
  2610. $.gimmicks("colorbox");
  2611. done();
  2612. });
  2613. },
  2614. };
  2615. $.md.registerGimmick(colorboxGimmick);
  2616. var methods = {
  2617. // takes a standard <img> tag and adds a hyperlink to the image source
  2618. // needed since we scale down images via css and want them to be accessible
  2619. // in original format
  2620. colorbox: function () {
  2621. var $image_groups;
  2622. if (!(this instanceof jQuery)) {
  2623. // select the image groups of the page
  2624. $image_groups = $(".md-image-group");
  2625. } else {
  2626. $image_groups = $(this);
  2627. }
  2628. // operate on md-image-group, which holds one
  2629. // or more images that are to be colorbox'ed
  2630. var counter = 0;
  2631. return $image_groups.each(function () {
  2632. var $this = $(this);
  2633. // each group requires a unique name
  2634. var gal_group = "gallery-group-" + counter++;
  2635. // create a hyperlink around the image
  2636. $this
  2637. .find("a.md-image-selfref img")
  2638. // filter out images that already are a hyperlink
  2639. // (so won't be part of the gallery)
  2640. // apply colorbox on their parent anchors
  2641. .parents("a")
  2642. .colorbox({
  2643. rel: gal_group,
  2644. opacity: 0.75,
  2645. slideshow: true,
  2646. maxWidth: "95%",
  2647. maxHeight: "95%",
  2648. scalePhotos: true,
  2649. photo: true,
  2650. slideshowAuto: false,
  2651. });
  2652. });
  2653. },
  2654. };
  2655. $.gimmicks.methods = $.extend({}, $.fn.gimmicks.methods, methods);
  2656. })(jQuery);
  2657. (function ($) {
  2658. "use strict";
  2659. var themeChooserGimmick = {
  2660. name: "Themes",
  2661. version: $.md.version,
  2662. once: function () {
  2663. $.md.linkGimmick(this, "carousel", carousel);
  2664. },
  2665. };
  2666. $.md.registerGimmick(themeChooserGimmick);
  2667. function carousel($link, opt, href) {
  2668. var $c = $('<div id="myCarousel" class="carousel slide"></div>');
  2669. var $d = $('<div class="carousel-inner"/>');
  2670. $c.append('<ol class="carousel-indicators" />');
  2671. var imageUrls = [];
  2672. var i = 0;
  2673. $.each(href.split(","), function (i, e) {
  2674. imageUrls.push($.trim(e));
  2675. $c.find("ol").append('<li data-target="#myCarousel" data-slide-to="' + i + '" class="active" /');
  2676. var div;
  2677. if (i === 0) {
  2678. div = '<div class="active item"/>';
  2679. } else {
  2680. div = '<div class="item"/>';
  2681. }
  2682. $d.append($(div).append('<img src="' + e + '"/>'));
  2683. });
  2684. $c.append($d);
  2685. $c.append('<a class="carousel-control left" href="#myCarousel" data-slide="prev">&lsaquo;</a>');
  2686. $c.append('<a class="carousel-control right" href="#myCarousel" data-slide="next">&rsaquo;</a>');
  2687. $link.replaceWith($c);
  2688. }
  2689. })(jQuery);
  2690. (function ($) {
  2691. "use strict";
  2692. var gistGimmick = {
  2693. name: "gist",
  2694. once: function () {
  2695. $.md.linkGimmick(this, "gist", gist);
  2696. },
  2697. };
  2698. $.md.registerGimmick(gistGimmick);
  2699. function gist($links, opt, href) {
  2700. $().lazygist("init");
  2701. return $links.each(function (i, link) {
  2702. var default_options = {
  2703. scheme: "https",
  2704. path: "gist.github.com/",
  2705. };
  2706. var options = $.extend(default_options, opt);
  2707. var $link = $(link);
  2708. var gistDiv = $('<div class="gist_here" data-id="' + href + '" />');
  2709. $link.replaceWith(gistDiv);
  2710. gistDiv.lazygist({
  2711. // we dont want a specific file so modify the url template
  2712. url_template: "{scheme}://{path}{id}.js"
  2713. .replace(/\{scheme\}/g, options.scheme)
  2714. .replace(/\{path\}/g, options.path),
  2715. });
  2716. });
  2717. }
  2718. })(jQuery);
  2719. /**
  2720. * Lazygist v0.2pre
  2721. *
  2722. * a jQuery plugin that will lazy load your gists.
  2723. *
  2724. * since jQuery 1.7.2
  2725. * https://github.com/tammo/jquery-lazy-gist
  2726. *
  2727. * Copyright, Tammo Pape
  2728. * http://tammopape.de
  2729. *
  2730. * Licensed under the MIT license.
  2731. */
  2732. (function ($, window, document, undefined) {
  2733. "use strict";
  2734. //
  2735. // note:
  2736. // this plugin is not stateful
  2737. // and will not communicate with own instances at different elements
  2738. //
  2739. var pluginName = "lazygist",
  2740. version = "0.2pre",
  2741. defaults = {
  2742. // adding the ?file parameter to choose a file
  2743. url_template: "https://gist.github.com/{id}.js?file={file}",
  2744. // if these are strings, the attributes will be read from the element
  2745. id: "data-id",
  2746. file: "data-file",
  2747. },
  2748. options,
  2749. // will be replaced
  2750. /*jshint -W060 */
  2751. originwrite = document.write,
  2752. // stylesheet urls found in document.write calls
  2753. // they are cached to write them once to the document,
  2754. // not three times for three gists
  2755. stylesheets = [],
  2756. // cache gist-ids to know which are already appended to the dom
  2757. ids_dom = [],
  2758. // remember gist-ids if their javascript is already loaded
  2759. ids_ajax = [],
  2760. methods = {
  2761. /**
  2762. * Standard init function
  2763. * No magic here
  2764. */
  2765. init: function (options_input) {
  2766. // default options are default
  2767. options = $.extend({}, defaults, options_input);
  2768. // can be reset
  2769. /*jshint -W061 */
  2770. document.write = _write;
  2771. $.each(options, function (index, value) {
  2772. if (typeof value !== "string") {
  2773. throw new TypeError(value + " (" + typeof value + ") is not a string");
  2774. }
  2775. });
  2776. return this.lazygist("load");
  2777. },
  2778. /**
  2779. * Load the gists
  2780. */
  2781. load: function () {
  2782. // (1) iterate over gist anchors
  2783. // (2) append the gist-html through the new document.write func (see _write)
  2784. // (1)
  2785. return this.filter("[" + options.id + "]").each(function () {
  2786. var id = $(this).attr(options.id),
  2787. file = $(this).attr(options.file),
  2788. src;
  2789. if (id !== undefined) {
  2790. if ($.inArray(id, ids_ajax) !== -1) {
  2791. // just do nothin, if gist is already ajaxed
  2792. return;
  2793. }
  2794. ids_ajax.push(id);
  2795. src = options.url_template.replace(/\{id\}/g, id).replace(/\{file\}/g, file);
  2796. // (2) this will trigger our _write function
  2797. $.getScript(src, function () {});
  2798. }
  2799. });
  2800. },
  2801. /**
  2802. * Just reset the write function
  2803. */
  2804. reset_write: function () {
  2805. document.write = originwrite;
  2806. return this;
  2807. },
  2808. };
  2809. /**
  2810. * private special document.write function
  2811. *
  2812. * Filters the css file from github.com to add it to the head - once -
  2813. *
  2814. * It has a fallback to keep flexibility with other scripts as high as possible
  2815. * (create a ticket if it messes things up!)
  2816. *
  2817. * Keep in mind, that a call to this function happens after
  2818. * an ajax call by jQuery. One *cannot* know which gist-anchor
  2819. * to use. You can only read the id from the content.
  2820. */
  2821. function _write(content) {
  2822. var expression, // for regexp results
  2823. href, // from the url
  2824. id; // from the content
  2825. if (content.indexOf('rel="stylesheet"') !== -1) {
  2826. href = $(content).attr("href");
  2827. // check if stylesheet is already inserted
  2828. if ($.inArray(href, stylesheets) === -1) {
  2829. $("head").append(content);
  2830. stylesheets.push(href);
  2831. }
  2832. } else if (content.indexOf('id="gist') !== -1) {
  2833. // This is the newer gist URL style, ignoring the hostname for GitHub EE instances
  2834. expression = /https?:\/\/gist.*?\/.*\/(.*)#/.exec(content);
  2835. if (expression !== null) {
  2836. id = expression[1];
  2837. } else {
  2838. // This will catch older versions of GitHub EE
  2839. expression = /gist\/.+?\/([a-f0-9]+)\/raw/g.exec(content);
  2840. if (expression !== null) {
  2841. id = expression[1];
  2842. }
  2843. }
  2844. if (id !== undefined) {
  2845. // test if id is already loaded
  2846. if ($.inArray(id, ids_dom) !== -1) {
  2847. // just do nothin, if gist is already attached to the dom
  2848. return;
  2849. }
  2850. ids_dom.push(id);
  2851. $(".gist_here[data-id=" + id + "]").append(content);
  2852. }
  2853. } else {
  2854. // this is a fallback for interoperability
  2855. originwrite.apply(document, arguments);
  2856. }
  2857. }
  2858. // method invocation - from jQuery.com
  2859. $.fn[pluginName] = function (method) {
  2860. if (methods[method]) {
  2861. return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
  2862. } else if (typeof method === "object" || !method) {
  2863. return methods.init.apply(this, arguments);
  2864. } else {
  2865. $.error("Method " + method + " does not exist on jQuery.lazygist");
  2866. }
  2867. };
  2868. // expose version for your interest
  2869. $.fn[pluginName].version = version;
  2870. })(jQuery, window, document);
  2871. (function ($) {
  2872. "use strict";
  2873. var iframeGimmick = {
  2874. name: "iframe",
  2875. version: $.md.version,
  2876. once: function () {
  2877. $.md.linkGimmick(this, "iframe", create_iframe);
  2878. },
  2879. };
  2880. $.md.registerGimmick(iframeGimmick);
  2881. function create_iframe($links, opt, text) {
  2882. return $links.each(function (i, link) {
  2883. var $link = $(link);
  2884. var href = $link.attr("href");
  2885. var $iframe = $('<iframe class="col-md-12" style="border: 0px solid red; height: 650px;"></iframe>');
  2886. $iframe.attr("src", href);
  2887. $link.replaceWith($iframe);
  2888. if (opt.width) $iframe.css("width", opt.width);
  2889. if (opt.height) $iframe.css("height", opt.height);
  2890. else {
  2891. var updateSizeFn = function () {
  2892. var offset = $iframe.offset();
  2893. var winHeight = $(window).height();
  2894. var newHeight = winHeight - offset.top - 5;
  2895. $iframe.height(newHeight);
  2896. };
  2897. $iframe.load(function (done) {
  2898. updateSizeFn();
  2899. });
  2900. $(window).resize(function () {
  2901. updateSizeFn();
  2902. });
  2903. }
  2904. });
  2905. }
  2906. })(jQuery);
  2907. (function ($) {
  2908. var mathGimmick = {
  2909. name: "math",
  2910. once: function () {
  2911. $.md.linkGimmick(this, "math", load_mathjax);
  2912. },
  2913. };
  2914. $.md.registerGimmick(mathGimmick);
  2915. function load_mathjax($links, opt, ref) {
  2916. $links.remove();
  2917. var script = document.createElement("script");
  2918. script.type = "text/javascript";
  2919. script.src = $.md.prepareLink("cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML", {
  2920. forceSSL: true,
  2921. });
  2922. document.getElementsByTagName("head")[0].appendChild(script);
  2923. }
  2924. })(jQuery);
  2925. (function ($) {
  2926. var prismGimmick = {
  2927. name: "prism",
  2928. load: function () {
  2929. $.md.stage("gimmick").subscribe(function (done) {
  2930. prism_highlight();
  2931. done();
  2932. });
  2933. },
  2934. };
  2935. var supportedLangs = [
  2936. "abap",
  2937. "actionscript",
  2938. "apacheconf",
  2939. "apl",
  2940. "applescript",
  2941. "asciidoc",
  2942. "aspnet",
  2943. "autohotkey",
  2944. "autoit",
  2945. "bash",
  2946. "basic",
  2947. "batch",
  2948. "bison",
  2949. "brainfuck",
  2950. "c",
  2951. "clike",
  2952. "coffeescript",
  2953. "core",
  2954. "cpp",
  2955. "crystal",
  2956. "csharp",
  2957. "css",
  2958. "css",
  2959. "d",
  2960. "dart",
  2961. "diff",
  2962. "docker",
  2963. "eiffel",
  2964. "elixir",
  2965. "erlang",
  2966. "fortran",
  2967. "fsharp",
  2968. "gherkin",
  2969. "git",
  2970. "glsl",
  2971. "go",
  2972. "groovy",
  2973. "haml",
  2974. "handlebars",
  2975. "haskell",
  2976. "haxe",
  2977. "http",
  2978. "icon",
  2979. "inform7",
  2980. "ini",
  2981. "j",
  2982. "jade",
  2983. "java",
  2984. "javascript",
  2985. "json",
  2986. "jsx",
  2987. "julia",
  2988. "keyman",
  2989. "kotlin",
  2990. "latex",
  2991. "less",
  2992. "lolcode",
  2993. "lua",
  2994. "makefile",
  2995. "markdown",
  2996. "markup",
  2997. "matlab",
  2998. "mel",
  2999. "mizar",
  3000. "monkey",
  3001. "nasm",
  3002. "nginx",
  3003. "nim",
  3004. "nix",
  3005. "nsis",
  3006. "objectivec",
  3007. "ocaml",
  3008. "oz",
  3009. "parigp",
  3010. "parser",
  3011. "pascal",
  3012. "perl",
  3013. "php",
  3014. "powershell",
  3015. "processing",
  3016. "prolog",
  3017. "puppet",
  3018. "pure",
  3019. "python",
  3020. "q",
  3021. "qore",
  3022. "r",
  3023. "rest",
  3024. "rip",
  3025. "roboconf",
  3026. "ruby",
  3027. "rust",
  3028. "sas",
  3029. "sass",
  3030. "scala",
  3031. "scheme",
  3032. "scss",
  3033. "smalltalk",
  3034. "smarty",
  3035. "sql",
  3036. "stylus",
  3037. "svg",
  3038. "swift",
  3039. "tcl",
  3040. "textile",
  3041. "twig",
  3042. "typescript",
  3043. "verilog",
  3044. "vhdl",
  3045. "vim",
  3046. "wiki",
  3047. "xml",
  3048. "yaml",
  3049. ];
  3050. $.md.registerGimmick(prismGimmick);
  3051. function prism_highlight() {
  3052. // marked adds lang-ruby, lang-csharp etc to the <code> block like in GFM
  3053. var $codeblocks = $("pre code[class^=lang-]");
  3054. $codeblocks.each(function () {
  3055. var $this = $(this);
  3056. var classes = $this.attr("class");
  3057. var lang = classes.substring(5);
  3058. if (supportedLangs.indexOf(lang) < 0) {
  3059. return;
  3060. }
  3061. $this.removeClass(classes);
  3062. $this.addClass("language-" + lang);
  3063. });
  3064. Prism.highlightAll();
  3065. }
  3066. })(jQuery);
  3067. (function ($) {
  3068. "use strict";
  3069. var themes = [
  3070. { name: "bootstrap", url: "netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" },
  3071. { name: "cyborg", url: "netdna.bootstrapcdn.com/bootswatch/3.0.0/cyborg/bootstrap.min.css" },
  3072. { name: "slate", url: "netdna.bootstrapcdn.com/bootswatch/3.0.0/slate/bootstrap.min.css" },
  3073. { name: "darkly", url: "cdn.jsdelivr.net/npm/bootswatch@3.2.0/darkly/bootstrap.min.css" },
  3074. ];
  3075. var useChooser = false;
  3076. var themeChooserGimmick = {
  3077. name: "Themes",
  3078. version: $.md.version,
  3079. once: function () {
  3080. $.md.linkGimmick(this, "themechooser", themechooser, "skel_ready");
  3081. $.md.linkGimmick(this, "theme", apply_theme);
  3082. },
  3083. };
  3084. $.md.registerGimmick(themeChooserGimmick);
  3085. var log = $.md.getLogger();
  3086. var set_theme = function (theme) {
  3087. theme.inverse = theme.inverse || false;
  3088. if (theme.url === undefined) {
  3089. if (!theme.name) {
  3090. log.error("Theme name must be given!");
  3091. return;
  3092. }
  3093. var saved_theme = themes.filter(function (t) {
  3094. return t.name === theme.name;
  3095. })[0];
  3096. if (!saved_theme) {
  3097. log.error("Theme " + name + " not found, removing link");
  3098. return;
  3099. }
  3100. theme = $.extend(theme, saved_theme);
  3101. }
  3102. $('link[rel=stylesheet][href*="netdna.bootstrapcdn.com"]').remove();
  3103. // slim instance has no bootstrap hardcoded in
  3104. var has_default_bootstrap_css = $("style[id*=bootstrap]").length > 0;
  3105. if (theme.name !== "bootstrap" || !has_default_bootstrap_css) {
  3106. // in devel & fat version the style is inlined, remove it
  3107. $("style[id*=bootstrap]").remove();
  3108. $('<link rel="stylesheet" type="text/css">').attr("href", $.md.prepareLink(theme.url)).appendTo("head");
  3109. }
  3110. if (theme.inverse === true) {
  3111. $("#md-main-navbar").removeClass("navbar-default");
  3112. $("#md-main-navbar").addClass("navbar-inverse");
  3113. } else {
  3114. $("#md-main-navbar").addClass("navbar-default");
  3115. $("#md-main-navbar").removeClass("navbar-inverse");
  3116. }
  3117. };
  3118. var apply_theme = function ($links, opt, text) {
  3119. opt.name = opt.name || text;
  3120. $links.each(function (i, link) {
  3121. $.md.stage("postgimmick").subscribe(function (done) {
  3122. var $link = $(link);
  3123. // only set a theme if no theme from the chooser is selected,
  3124. // or if the chooser isn't enabled
  3125. if (window.localStorage.theme === undefined || !useChooser) {
  3126. set_theme(opt);
  3127. }
  3128. done();
  3129. });
  3130. });
  3131. $links.remove();
  3132. };
  3133. var themechooser = function ($links, opt, text) {
  3134. useChooser = true;
  3135. $.md.stage("bootstrap").subscribe(function (done) {
  3136. restore_theme(opt);
  3137. done();
  3138. });
  3139. return $links.each(function (i, e) {
  3140. var $this = $(e);
  3141. var $chooser = $('<a href=""></a><ul></ul>');
  3142. $chooser.eq(0).text(text);
  3143. $.each(themes, function (i, theme) {
  3144. var $li = $("<li></li>");
  3145. $chooser.eq(1).append($li);
  3146. var $a = $("<a/>")
  3147. .text(theme.name)
  3148. .attr("href", "")
  3149. .click(function (ev) {
  3150. ev.preventDefault();
  3151. window.localStorage.theme = theme.name;
  3152. window.location.reload();
  3153. })
  3154. .appendTo($li);
  3155. });
  3156. $chooser.eq(1).append('<li class="divider" />');
  3157. var $li = $("<li/>");
  3158. var $a_use_default = $("<a>Use default</a>");
  3159. $a_use_default.click(function (ev) {
  3160. ev.preventDefault();
  3161. window.localStorage.removeItem("theme");
  3162. window.location.reload();
  3163. });
  3164. $li.append($a_use_default);
  3165. $chooser.eq(1).append($li);
  3166. $this.replaceWith($chooser);
  3167. });
  3168. };
  3169. var restore_theme = function (opt) {
  3170. if (window.localStorage.theme) {
  3171. opt = $.extend({ name: window.localStorage.theme }, opt);
  3172. set_theme(opt);
  3173. }
  3174. };
  3175. })(jQuery);
  3176. (function ($) {
  3177. //'use strict';
  3178. var youtubeGimmick = {
  3179. name: "youtube",
  3180. load: function () {
  3181. $.md.stage("gimmick").subscribe(function (done) {
  3182. youtubeLinkToIframe();
  3183. done();
  3184. });
  3185. },
  3186. };
  3187. $.md.registerGimmick(youtubeGimmick);
  3188. function youtubeLinkToIframe() {
  3189. var $youtube_links = $("a[href*=youtube\\.com]:empty, a[href*=youtu\\.be]:empty");
  3190. $youtube_links.each(function () {
  3191. var $this = $(this);
  3192. var href = $this.attr("href");
  3193. if (href !== undefined) {
  3194. // extract the v parameter from youtube
  3195. var exp = /.*(?:youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=)([^#\&\?]*).*/;
  3196. var m = href.match(exp);
  3197. if (m && m[1].length === 11) {
  3198. // insert the iframe
  3199. var short_handle = m[1];
  3200. var frame = $('<iframe class="md-external" frameborder="0" allowfullscreen></iframe>');
  3201. frame.attr("src", "http://youtube.com/embed/" + short_handle);
  3202. // remove the a tag
  3203. $this.replaceWith(frame);
  3204. }
  3205. }
  3206. });
  3207. }
  3208. })(jQuery);
  3209. (function ($) {
  3210. "use strict";
  3211. var scripturl = "//cdnjs.cloudflare.com/ajax/libs/Chart.js/1.0.2/Chart.min.js";
  3212. var chartGimmick = {
  3213. name: "chart",
  3214. version: $.md.version,
  3215. once: function () {
  3216. $.md.linkGimmick(this, "chart", chart);
  3217. // load the chart js
  3218. $.md.registerScript(this, scripturl, {
  3219. license: "MIT",
  3220. loadstage: "skel_ready",
  3221. finishstage: "gimmick",
  3222. });
  3223. },
  3224. };
  3225. $.md.registerGimmick(chartGimmick);
  3226. var log = $.md.getLogger();
  3227. function chart($links, opt, text) {
  3228. return $links.each(function (i, link) {
  3229. // Get the options for this gimmick
  3230. // labelColumn: This is a string the indicates the column that will be used to
  3231. // label the data points
  3232. // dataColumns: This is a array of strings that indicate each column to be plotted
  3233. // canvasId: This is a ID for the given chart. Defaults to a random number
  3234. // between 1-1000.
  3235. // chartOptions: This is an object that is passed to chartjs to configure its
  3236. // options.
  3237. // chartType: This string is the type of chart we want to render. Bar, Line,
  3238. // or Radar. Defaults to Line.
  3239. var default_options = {
  3240. chartType: "Line",
  3241. canvasId: "chartGimmick" + Math.floor(Math.random() * 1000 + 1),
  3242. chartOptions: {
  3243. responsive: false,
  3244. },
  3245. };
  3246. var options = $.extend({}, default_options, opt);
  3247. var $link = $(link);
  3248. var table = $link.parents().find("table").last();
  3249. if (table.length === 0) {
  3250. log.error("Chart Gimmick: No tables found on the page.");
  3251. $link.remove();
  3252. return;
  3253. }
  3254. // Replace the Gimmick with the canvas that chartJS needs
  3255. var myHtml = $('<canvas id="' + options.canvasId + '"></canvas>');
  3256. myHtml.width(options.width || "450px");
  3257. myHtml.height(options.height || "250px");
  3258. $link.replaceWith(myHtml);
  3259. // This is the object that is given to the chart frame work for rendering. It will be
  3260. // built up by processing the html table that is found on the table.
  3261. var chartConfig = {
  3262. datasets: [],
  3263. labels: [],
  3264. };
  3265. var chartAvailableToRender = true;
  3266. // These variables hold the indices of the columns in the table we care about. They will
  3267. // be populated as we process the table based on the options that are given in the
  3268. // gimmick
  3269. var labelColumnIndex = -1;
  3270. var dataColumnIndices = [];
  3271. // Get the index of the columns that we care about for charting
  3272. table.find("th").each(function (index) {
  3273. // This is the column that labels each data point
  3274. if (this.textContent === options.labelColumn) {
  3275. labelColumnIndex = index;
  3276. }
  3277. // Check if this is a data column
  3278. else {
  3279. for (var i = 0; i < options.dataColumns.length; i++) {
  3280. if (this.textContent === options.dataColumns[i]) {
  3281. dataColumnIndices.push(index);
  3282. }
  3283. }
  3284. }
  3285. });
  3286. // Get the data
  3287. table.find("tr").each(function (rowIndex) {
  3288. $(this)
  3289. .find("td")
  3290. .each(function (colIndex) {
  3291. if (colIndex === labelColumnIndex) {
  3292. chartConfig.labels.push(this.textContent);
  3293. } else {
  3294. for (var i = 0; i < dataColumnIndices.length; i++) {
  3295. if (colIndex === dataColumnIndices[i]) {
  3296. if (chartConfig.datasets[i] === undefined) {
  3297. chartConfig.datasets[i] = {};
  3298. chartConfig.datasets[i].data = [];
  3299. }
  3300. chartConfig.datasets[i].data.push(this.textContent);
  3301. }
  3302. }
  3303. }
  3304. });
  3305. });
  3306. // No Chart data found
  3307. if (chartConfig.datasets[i] === undefined) {
  3308. chartAvailableToRender = false;
  3309. log.error(
  3310. "Chart Gimmick: No data was found for the chart. Make sure that there " +
  3311. "is a tables on the page. Check that your " +
  3312. "column headers match the chart configuration."
  3313. );
  3314. }
  3315. if (chartAvailableToRender) {
  3316. var canvas = document.getElementById(options.canvasId);
  3317. var ctx = canvas.getContext("2d");
  3318. $.md.stage("postgimmick").subscribe(function (done) {
  3319. setTimeout(function () {
  3320. new Chart(ctx)[options.chartType](chartConfig, options.chartOptions);
  3321. });
  3322. done();
  3323. });
  3324. }
  3325. });
  3326. }
  3327. })(jQuery);
  3328. (function ($) {
  3329. "use strict";
  3330. function yuml($link, opt, text) {
  3331. var default_options = {
  3332. type: "class" /* { class, activity, usecase } */,
  3333. style: "plain" /* { plain, scruffy } */,
  3334. direction: "LR" /* LR, TB, RL */,
  3335. scale: "100",
  3336. };
  3337. var options = $.extend({}, default_options, opt);
  3338. return $link.each(function (i, e) {
  3339. var $this = $(e);
  3340. var url = "http://yuml.me/diagram/";
  3341. var data = $this.attr("href");
  3342. var title = $this.attr("title");
  3343. title = title ? title : "";
  3344. /* `FOOBAR´ => (FOOBAR) */
  3345. data = data.replace(new RegExp("`", "g"), "(").replace(new RegExp("´", "g"), ")");
  3346. url +=
  3347. options.style +
  3348. ";dir:" +
  3349. options.direction +
  3350. ";scale:" +
  3351. options.scale +
  3352. "/" +
  3353. options.type +
  3354. "/" +
  3355. data;
  3356. var $img = $('<img src="' + url + '" title="' + title + '" alt="' + title + '">');
  3357. $this.replaceWith($img);
  3358. });
  3359. }
  3360. var yumlGimmick = {
  3361. name: "yuml",
  3362. version: $.md.version,
  3363. once: function () {
  3364. $.md.linkGimmick(this, "yuml", yuml);
  3365. $.md.registerScript(this, "", {
  3366. license: "LGPL",
  3367. loadstage: "postgimmick",
  3368. finishstage: "all_ready",
  3369. });
  3370. },
  3371. };
  3372. $.md.registerGimmick(yumlGimmick);
  3373. })(jQuery);