├── wmd-buttons.png ├── wmd-buttons.psd ├── Makefile ├── wmd-test.html ├── License.txt ├── Readme.md ├── markdownhelp.html ├── wmd.css ├── jsmin.py ├── showdown.js ├── wmd.combined.min.js └── wmd.js /wmd-buttons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChiperSoft/wmd/HEAD/wmd-buttons.png -------------------------------------------------------------------------------- /wmd-buttons.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChiperSoft/wmd/HEAD/wmd-buttons.psd -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | JSFILES=wmd.js showdown.js 3 | 4 | all: wmd.combined.js wmd.combined.min.js 5 | 6 | wmd.combined.js: $(JSFILES) 7 | cat $(JSFILES) > $@ 8 | 9 | wmd.combined.min.js: $(JSFILES) 10 | cat $(JSFILES) | python jsmin.py > $@ 11 | -------------------------------------------------------------------------------- /wmd-test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 || Description | 22 |Example: | 23 |Creates: | 24 |
| Text surrounded by asterisks or underscores will be made italic | 29 |*italics* | 30 |italics | 31 |
| Text surrounded by double asterisks will be bold | 34 |**bold** | 35 |bold | 36 |
| To create a hyperlink, surround the text you want to be the link with brackets followed by the URL in parenthesis. | 39 |linked text | 41 ||
| A line of text starting with a pound symbol will become a heading. There are six levels of heading which you can reach by adding more pound signs. | 44 |#heading 1 | 45 |
|
46 |
| ##heading 2 | 49 |heading 2 |
50 | |
| You can also create a header by following it with two or more equal signs or hyphens. | 53 |heading 1 =========== |
54 |
|
55 |
| heading 2 ----------- |
58 | heading 2 |
59 | |
| A series of lines beginning with hyphens will create an unordered list. | 62 |
63 | - item 1 64 | - item 2 65 | - item 3 66 | |
67 |
|
72 |
| A series of lines beginning with numbers followed by a period will create an ordered list. | 75 |
76 | 1. item 1 77 | 2. item 2 78 | 3. item 3 79 | |
80 |
|
85 |
| A line started with a greater-then symbol will identify that text as being quoted from someone else. 88 | | > quoted text | 89 |quoted text |
90 |
| Lines starting with four spaces are treated as preformatted text and will display without wrapping. | 93 |
94 | if 1 * 2 < 3: 95 | print "hello, world!" 96 | |
97 | if 1 * 2 < 3: |
98 |
s around 177 | // "paragraphs" that are wrapped in non-block-level tags, such as anchors, 178 | // phrase emphasis, and spans. The list of tags we're looking for is 179 | // hard-coded: 180 | var block_tags_a = "p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del"; 181 | var block_tags_b = "p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math"; 182 | 183 | // First, look for nested blocks, e.g.: 184 | //
tags around block-level tags.
326 | text = _HashHTMLBlocks(text);
327 | text = _FormParagraphs(text);
328 |
329 | return text;
330 | };
331 |
332 |
333 | var _RunSpanGamut = function (text) {
334 | //
335 | // These are all the transformations that occur *within* block-level
336 | // tags like paragraphs, headers, and list items.
337 | //
338 | text = _DoCodeSpans(text);
339 | text = _EscapeSpecialCharsWithinTagAttributes(text);
340 | text = _EncodeBackslashEscapes(text);
341 |
342 | // Process anchor and image tags. Images must come first,
343 | // because ![foo][f] looks like an anchor.
344 | text = _DoImages(text);
345 | text = _DoAnchors(text);
346 |
347 | // Make links out of things like ` Just type tags
1044 | //
1045 | // Strip leading and trailing lines:
1046 | text = text.replace(/^\n+/g, "");
1047 | text = text.replace(/\n+$/g, "");
1048 |
1049 | var i;
1050 | var grafs = text.split(/\n{2,}/g);
1051 | var grafsOut = [];
1052 |
1053 | //
1054 | // Wrap tags.
1055 | //
1056 | var end = grafs.length;
1057 | for (i = 0; i < end; i++) {
1058 | var str = grafs[i];
1059 | var p_tag = ' ';
1060 |
1061 | // if this is an HTML marker, copy it
1062 | if (str.search(/~K(\d+)K/g) >= 0) {
1063 | grafsOut.push(str);
1064 | }
1065 | else if (str.search(/\S/) >= 0) {
1066 | str = _RunSpanGamut(str);
1067 |
1068 | if (str.substr(0,2)==='->') {
1069 | if (str.substr(-5)==='<-') {
1070 | p_tag = ' ';
1071 | str = str.slice(2,-5);
1072 | } else {
1073 | p_tag = ' ';
1074 | str = str.substring(2);
1075 | }
1076 | }
1077 |
1078 | str = str.replace(/\n/g, " Enter the image URL. You can also add a title, which will be displayed as a tool tip. Example: Enter the web address. You can also add a title, which will be displayed as a tool tip. Example: ';str=str.slice(2,-5);}else{p_tag=' ';str=str.substring(2);}}
184 | str=str.replace(/\n/g,"
\n");
357 |
358 | return text;
359 | };
360 |
361 | var _EscapeSpecialCharsWithinTagAttributes = function (text) {
362 | //
363 | // Within tags -- meaning between < and > -- encode [\ ` * _] so they
364 | // don't conflict with their use in Markdown for code, italics and strong.
365 | //
366 | // Build a regex to find HTML tags and comments. See Friedl's
367 | // "Mastering Regular Expressions", 2nd Ed., pp. 200-201.
368 | var regex = /(<[a-z\/!$]("[^"]*"|'[^']*'|[^'">])*>|)/gi;
369 |
370 | text = text.replace(regex, function (wholeMatch) {
371 | var tag = wholeMatch.replace(/(.)<\/?code>(?=.)/g, "$1`");
372 | tag = escapeCharacters(tag, "\\`*_");
373 | return tag;
374 | });
375 |
376 | return text;
377 | };
378 |
379 | var _DoAnchors = function (text) {
380 | //
381 | // Turn Markdown link shortcuts into XHTML tags.
382 | //
383 | //
384 | // First, handle reference-style links: [link text] [id]
385 | //
386 | /*
387 | text = text.replace(/
388 | ( // wrap whole match in $1
389 | \[
390 | (
391 | (?:
392 | \[[^\]]*\] // allow brackets nested one level
393 | |
394 | [^\[] // or anything else
395 | )*
396 | )
397 | \]
398 |
399 | [ ]? // one optional space
400 | (?:\n[ ]*)? // one optional newline followed by spaces
401 |
402 | \[
403 | (.*?) // id = $3
404 | \]
405 | )()()()() // pad remaining backreferences
406 | /g,_DoAnchors_callback);
407 | */
408 | text = text.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g, writeAnchorTag);
409 |
410 | //
411 | // Next, inline-style links: [link text](url "optional title")
412 | //
413 | /*
414 | text = text.replace(/
415 | ( // wrap whole match in $1
416 | \[
417 | (
418 | (?:
419 | \[[^\]]*\] // allow brackets nested one level
420 | |
421 | [^\[\]] // or anything else
422 | )
423 | )
424 | \]
425 | \( // literal paren
426 | [ \t]*
427 | () // no id, so leave $3 empty
428 | (.*?)>? // href = $4
429 | [ \t]*
430 | ( // $5
431 | (['"]) // quote char = $6
432 | (.*?) // Title = $7
433 | \6 // matching quote
434 | [ \t]* // ignore any spaces/tabs between closing quote and )
435 | )? // title is optional
436 | \)
437 | )
438 | /g,writeAnchorTag);
439 | */
440 | text = text.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\]\([ \t]*()(.*?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g, writeAnchorTag);
441 |
442 | //
443 | // Last, handle reference-style shortcuts: [link text]
444 | // These must come last in case you've also got [link test][1]
445 | // or [link test](/foo)
446 | //
447 | /*
448 | text = text.replace(/
449 | ( // wrap whole match in $1
450 | \[
451 | ([^\[\]]+) // link text = $2; can't contain '[' or ']'
452 | \]
453 | )()()()()() // pad rest of backreferences
454 | /g, writeAnchorTag);
455 | */
456 | text = text.replace(/(\[([^\[\]]+)\])()()()()()/g, writeAnchorTag);
457 |
458 | return text;
459 | };
460 |
461 | var writeAnchorTag = function (wholeMatch, m1, m2, m3, m4, m5, m6, m7) {
462 | if (m7 === undefined) m7 = "";
463 | var whole_match = m1;
464 | var link_text = m2;
465 | var link_id = m3.toLowerCase();
466 | var url = m4;
467 | var title = m7;
468 | var blank_target = false;
469 |
470 | if (url === "") {
471 | if (link_id === "") {
472 | // lower-case and turn embedded newlines into spaces
473 | link_id = link_text.toLowerCase().replace(/ ?\n/g, " ");
474 | } else {
475 | if (link_id[0]=="!") {
476 | blank_target = true;
477 | link_id = link_id.substr(1);
478 | }
479 | }
480 | url = "#" + link_id;
481 |
482 | if (g_urls[link_id] !== undefined) {
483 | url = g_urls[link_id];
484 | if (g_titles[link_id] !== undefined) {
485 | title = g_titles[link_id];
486 | }
487 | if (url[0]=="!") {
488 | blank_target = true;
489 | url = url.substr(1);
490 | }
491 | }
492 | else {
493 | if (whole_match.search(/\(\s*\)$/m) > -1) {
494 | // Special case for explicit empty url
495 | url = "";
496 | } else {
497 | return whole_match;
498 | }
499 | }
500 | } else {
501 | if (url[0]=="!") {
502 | blank_target = true;
503 | url = url.substr(1);
504 | }
505 | }
506 |
507 | url = escapeCharacters(url, "*_");
508 | var result = "" + link_text + "";
521 |
522 | return result;
523 | };
524 |
525 |
526 | var _DoImages = function (text) {
527 | //
528 | // Turn Markdown image shortcuts into tags.
529 | //
530 | //
531 | // First, handle reference-style labeled images: ![alt text][id]
532 | //
533 | /*
534 | text = text.replace(/
535 | ( // wrap whole match in $1
536 | !\[
537 | (.*?) // alt text = $2
538 | \]
539 |
540 | [ ]? // one optional space
541 | (?:\n[ ]*)? // one optional newline followed by spaces
542 |
543 | \[
544 | (.*?) // id = $3
545 | \]
546 | )()()()() // pad rest of backreferences
547 | /g,writeImageTag);
548 | */
549 | text = text.replace(/(!\[(.*?)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g, writeImageTag);
550 |
551 | //
552 | // Next, handle inline images: 
553 | // Don't forget: encode * and _
554 | /*
555 | text = text.replace(/
556 | ( // wrap whole match in $1
557 | !\[
558 | (.*?) // alt text = $2
559 | \]
560 | \s? // One optional whitespace character
561 | \( // literal paren
562 | [ \t]*
563 | () // no id, so leave $3 empty
564 | (\S+?)>? // src url = $4
565 | [ \t]*
566 | ( // $5
567 | (['"]) // quote char = $6
568 | (.*?) // title = $7
569 | \6 // matching quote
570 | [ \t]*
571 | )? // title is optional
572 | \)
573 | )
574 | /g,writeImageTag);
575 | */
576 | text = text.replace(/(!\[(.*?)\]\s?\([ \t]*()(\S+?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g, writeImageTag);
577 |
578 | return text;
579 | };
580 |
581 | var writeImageTag = function (wholeMatch, m1, m2, m3, m4, m5, m6, m7) {
582 | var whole_match = m1;
583 | var alt_text = m2;
584 | var link_id = m3.toLowerCase();
585 | var url = m4;
586 | var title = m7;
587 |
588 | if (!title) title = "";
589 |
590 | if (url === "") {
591 | if (link_id === "") {
592 | // lower-case and turn embedded newlines into spaces
593 | link_id = alt_text.toLowerCase().replace(/ ?\n/g, " ");
594 | }
595 | url = "#" + link_id;
596 |
597 | if (g_urls[link_id] !== undefined) {
598 | url = g_urls[link_id];
599 | if (g_titles[link_id] !== undefined) {
600 | title = g_titles[link_id];
601 | }
602 | }
603 | else {
604 | return whole_match;
605 | }
606 | }
607 |
608 | alt_text = alt_text.replace(/"/g, """);
609 | url = escapeCharacters(url, "*_");
610 | var result = "
";
620 |
621 | return result;
622 | };
623 |
624 |
625 | var _DoHeaders = function (text) {
626 |
627 | // Setext-style headers:
628 | // Header 1
629 | // ========
630 | //
631 | // Header 2
632 | // --------
633 | //
634 | text = text.replace(/^(.+)[ \t]*\n=+[ \t]*\n+/gm, function (wholeMatch, m1) {
635 | return hashBlock("
" + _RunSpanGamut(m1) + "
");
636 | });
637 |
638 | text = text.replace(/^(.+)[ \t]*\n-+[ \t]*\n+/gm, function (matchFound, m1) {
639 | return hashBlock("" + _RunSpanGamut(m1) + "
");
640 | });
641 |
642 | // atx-style headers:
643 | // # Header 1
644 | // ## Header 2
645 | // ## Header 2 with closing hashes ##
646 | // ...
647 | // ###### Header 6
648 | //
649 | /*
650 | text = text.replace(/
651 | ^(\#{1,6}) // $1 = string of #'s
652 | [ \t]*
653 | (.+?) // $2 = Header text
654 | [ \t]*
655 | \#* // optional closing #'s (not counted)
656 | \n+
657 | /gm, function() {...});
658 | */
659 |
660 | text = text.replace(/^(\#{1,6})[ \t]*(.+?)[ \t]*\#*\n+/gm, function (wholeMatch, m1, m2) {
661 | var h_level = m1.length;
662 | return hashBlock("` blocks.
815 | //
816 | /*
817 | text = text.replace(text,
818 | /(?:\n\n|^)
819 | ( // $1 = the code block -- one or more lines, starting with a space/tab
820 | (?:
821 | (?:[ ]{4}|\t) // Lines must start with a tab or a tab-width of spaces - attacklab: g_tab_width
822 | .*\n+
823 | )+
824 | )
825 | (\n*[ ]{0,3}[^ \t\n]|(?=~0)) // attacklab: g_tab_width
826 | /g,function(){...});
827 | */
828 |
829 | // attacklab: sentinel workarounds for lack of \A and \Z, safari\khtml bug
830 | text += "~0";
831 |
832 | text = text.replace(/(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=~0))/g, function (wholeMatch, m1, m2) {
833 | var codeblock = m1;
834 | var nextChar = m2;
835 |
836 | codeblock = _EncodeCode(_Outdent(codeblock));
837 | codeblock = _Detab(codeblock);
838 | codeblock = codeblock.replace(/^\n+/g, ""); // trim leading newlines
839 | codeblock = codeblock.replace(/\n+$/g, ""); // trim trailing whitespace
840 | codeblock = "
";
841 |
842 | return hashBlock(codeblock) + nextChar;
843 | });
844 |
845 | // attacklab: strip sentinel
846 | text = text.replace(/~0/, "");
847 |
848 | return text;
849 | };
850 |
851 | var hashBlock = function (text) {
852 | text = text.replace(/(^\n+|\n+$)/g, "");
853 | return "\n\n~K" + (g_html_blocks.push(text) - 1) + "K\n\n";
854 | };
855 |
856 |
857 | var _DoCodeSpans = function (text) {
858 | //
859 | // * Backtick quotes are used for " + codeblock + "\n spans.
860 | //
861 | // * You can use multiple backticks as the delimiters if you want to
862 | // include literal backticks in the code span. So, this input:
863 | //
864 | // Just type ``foo `bar` baz`` at the prompt.
865 | //
866 | // Will translate to:
867 | //
868 | // foo `bar` baz at the prompt.`bar` ...
881 | //
882 | /*
883 | text = text.replace(/
884 | (^|[^\\]) // Character before opening ` can't be a backslash
885 | (`+) // $2 = Opening run of `
886 | ( // $3 = The code block
887 | [^\r]*?
888 | [^`] // attacklab: work around lack of lookbehind
889 | )
890 | \2 // Matching closer
891 | (?!`)
892 | /gm, function(){...});
893 | */
894 |
895 | text = text.replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm, function (wholeMatch, m1, m2, m3, m4) {
896 | var c = m3;
897 | c = c.replace(/^([ \t]*)/g, ""); // leading whitespace
898 | c = c.replace(/[ \t]*$/g, ""); // trailing whitespace
899 | c = _EncodeCode(c);
900 | return m1 + "" + c + "";
901 | });
902 |
903 |
904 | // Process ^^superscript^^ notation
905 | text = text.replace(/(^|[^\\])(\^{2})([^\r]*?[^\^]{2})\2(?!\^)/gm, function (wholeMatch, m1, m2, m3, m4) {
906 | var c = m3;
907 | c = c.replace(/^([ \t]*)/g, ""); // leading whitespace
908 | c = c.replace(/[ \t]*$/g, ""); // trailing whitespace
909 | c = _EncodeCode(c);
910 | return m1 + "" + c + "";
911 | });
912 |
913 | // Process ,,subscript,, notation
914 | text = text.replace(/(^|[^\\])(,{2})([^\r]*?[^,]{2})\2(?!,)/gm, function (wholeMatch, m1, m2, m3, m4) {
915 | var c = m3;
916 | c = c.replace(/^([ \t]*)/g, ""); // leading whitespace
917 | c = c.replace(/[ \t]*$/g, ""); // trailing whitespace
918 | c = _EncodeCode(c);
919 | return m1 + "" + c + "";
920 | });
921 |
922 | // Process ~~strike~~ notation
923 | text = text.replace(/(^|[^\\])(~T~T)([^\r]*?[^~]{2})\2(?!~)/gm, function (wholeMatch, m1, m2, m3, m4) {
924 | var c = m3;
925 | c = c.replace(/^([ \t]*)/g, ""); // leading whitespace
926 | c = c.replace(/[ \t]*$/g, ""); // trailing whitespace
927 | c = _EncodeCode(c);
928 | return m1 + "" + c + "";
929 | });
930 |
931 | return text;
932 | };
933 |
934 |
935 | var _EncodeCode = function (text) {
936 | //
937 | // Encode/escape certain characters inside Markdown code runs.
938 | // The point is that in code, these characters are literals,
939 | // and lose their special Markdown meanings.
940 | //
941 | // Encode all ampersands; HTML entities are not
942 | // entities within a Markdown code span.
943 | text = text.replace(/&/g, "&");
944 |
945 | // Do the angle bracket song and dance:
946 | text = text.replace(//g, ">");
948 |
949 | // Encode "smart" quotes
950 | text = text.
951 | replace( /\u2026/g , '…').
952 | replace( /\u00AB/g , '«' ).
953 | replace( /\u00BB/g , '»' ).
954 | replace( /\u201C/g , '“' ).
955 | replace( /\u201D/g , '”' ).
956 | replace( /\u2018/g , '‘' ).
957 | replace( /\u2019/g , '’' ).
958 | replace( /\u2014/g , '—' ).
959 | replace( /\u2013/g , '–' ).
960 | replace( /\u2022/g , '•' ).
961 | replace( /\u2122/g , '™' ).
962 | replace( /\u00A9/g , '©' ).
963 | replace( /\u00AE/g , '®' );
964 |
965 |
966 | // Now, escape characters that are magic in Markdown:
967 | text = escapeCharacters(text, "*_{}[]\\", false);
968 |
969 | // jj the line above breaks this:
970 | //---
971 | //* Item
972 | // 1. Subitem
973 | // special char: *
974 | //---
975 | return text;
976 | };
977 |
978 |
979 | var _DoItalicsAndBold = function (text) {
980 |
981 | if (true) { //eventually this will be replaced with a runtime option. But for now we're forcing it.
982 | text = text.replace(/(\*\*)(?=\S)([^\r]*?\S[*]*)\1/g, "$2");
983 | text = text.replace(/(\w)_(\w)/g, "$1~E95E$2"); // ** GFM ** "~E95E" == escaped "_"
984 | text = text.replace(/(\*)(?=\S)([^\r]*?\S)\1/g, "$2");
985 | text = text.replace(/(_)(?=\S)([^\r]*?\S)\1/g, "$2");
986 | } else {
987 | // must go first:
988 | text = text.replace(/(\*\*|__)(?=\S)([^\r]*?\S[*_]*)\1/g, "$2");
989 |
990 | text = text.replace(/(\w)_(\w)/g, "$1~E95E$2"); // ** GFM ** "~E95E" == escaped "_"
991 | text = text.replace(/(\*|_)(?=\S)([^\r]*?\S)\1/g, "$2");
992 | }
993 |
994 | return text;
995 | };
996 |
997 |
998 | var _DoBlockQuotes = function (text) {
999 |
1000 | /*
1001 | text = text.replace(/
1002 | ( // Wrap whole match in $1
1003 | (
1004 | ^[ \t]*>[ \t]? // '>' at the start of a line
1005 | .+\n // rest of the first line
1006 | (.+\n)* // subsequent consecutive lines
1007 | \n* // blanks
1008 | )+
1009 | )
1010 | /gm, function(){...});
1011 | */
1012 |
1013 | text = text.replace(/((^[ \t]*>[ \t]?.+\n(.+\n)*\n*)+)/gm, function (wholeMatch, m1) {
1014 | var bq = m1;
1015 |
1016 | // attacklab: hack around Konqueror 3.5.4 bug:
1017 | // "----------bug".replace(/^-/g,"") == "bug"
1018 | bq = bq.replace(/^[ \t]*>[ \t]?/gm, "~0"); // trim one level of quoting
1019 | // attacklab: clean up hack
1020 | bq = bq.replace(/~0/g, "");
1021 |
1022 | bq = bq.replace(/^[ \t]+$/gm, ""); // trim whitespace-only lines
1023 | bq = _RunBlockGamut(bq); // recurse
1024 | bq = bq.replace(/(^|\n)/g, "$1 ");
1025 | // These leading spaces screw with content, so we need to fix that:
1026 | bq = bq.replace(/(\s*
[^\r]+?<\/pre>)/gm, function (wholeMatch, m1) {
1027 | var pre = m1;
1028 | // attacklab: hack around Konqueror 3.5.4 bug:
1029 | pre = pre.replace(/^ {2}/mg, "~0");
1030 | pre = pre.replace(/~0/g, "");
1031 | return pre;
1032 | });
1033 |
1034 | return hashBlock("";}}
70 | if(wmd.panels.preview){if(wmd.options.tagFilter.enabled){text=text.replace(/<[^<>]*>?/gi,function(tag){return(tag.match(wmd.options.tagFilter.allowedTags)||tag.match(wmd.options.tagFilter.patternLink)||tag.match(wmd.options.tagFilter.patternImage))?tag:"";});}
71 | wmd.panels.preview.innerHTML=text;}
72 | setPanelScrollTops();if(isFirstTimeFilled){isFirstTimeFilled=false;return;}
73 | var fullTop=position.getTop(wmd.panels.input)-getDocScrollTop();if(browser.isIE){window.setTimeout(function(){window.scrollBy(0,fullTop-emptyTop);},0);}
74 | else{window.scrollBy(0,fullTop-emptyTop);}};var init=function(){setupEvents(wmd.panels.input,applyTimeout);makePreviewHtml();if(wmd.panels.preview){wmd.panels.preview.scrollTop=0;}
75 | if(wmd.panels.output){wmd.panels.output.scrollTop=0;}};this.destroy=function(){if(poller){poller.destroy();}};init();};var UndoManager=function(wmd,textarea,pastePollInterval,callback){var undoObj=this;var undoStack=[];var stackPtr=0;var mode="none";var lastState;var poller;var timer;var inputStateObj;var setMode=function(newMode,noSave){if(mode!=newMode){mode=newMode;if(!noSave){saveState();}}
76 | if(!browser.isIE||mode!="moving"){timer=window.setTimeout(refreshState,1);}
77 | else{inputStateObj=null;}};var refreshState=function(){inputStateObj=new TextareaState(textarea,wmd);poller.tick();timer=undefined;};this.setCommandMode=function(){mode="command";saveState();timer=window.setTimeout(refreshState,0);};this.canUndo=function(){return stackPtr>1;};this.canRedo=function(){if(undoStack[stackPtr+1]){return true;}
78 | return false;};this.undo=function(){if(undoObj.canUndo()){if(lastState){lastState.restore();lastState=null;}
79 | else{undoStack[stackPtr]=new TextareaState(textarea,wmd);undoStack[--stackPtr].restore();if(callback){callback();}}}
80 | mode="none";textarea.focus();refreshState();};this.redo=function(){if(undoObj.canRedo()){undoStack[++stackPtr].restore();if(callback){callback();}}
81 | mode="none";textarea.focus();refreshState();};var saveState=function(){var currState=inputStateObj||new TextareaState(textarea,wmd);if(!currState){return false;}
82 | if(mode=="moving"){if(!lastState){lastState=currState;}
83 | return;}
84 | if(lastState){if(undoStack[stackPtr-1].text!=lastState.text){undoStack[stackPtr++]=lastState;}
85 | lastState=null;}
86 | undoStack[stackPtr++]=currState;undoStack[stackPtr+1]=null;if(callback){callback();}};var handleCtrlYZ=function(event){var handled=false;if(event.ctrlKey||event.metaKey){var keyCode=event.charCode||event.keyCode;var keyCodeChar=String.fromCharCode(keyCode);switch(keyCodeChar){case"y":undoObj.redo();handled=true;break;case"z":if(!event.shiftKey){undoObj.undo();}
87 | else{undoObj.redo();}
88 | handled=true;break;}}
89 | if(handled){if(event.preventDefault){event.preventDefault();}
90 | if(window.event){window.event.returnValue=false;}
91 | return;}};var handleModeChange=function(event){if(!event.ctrlKey&&!event.metaKey){var keyCode=event.keyCode;if((keyCode>=33&&keyCode<=40)||(keyCode>=63232&&keyCode<=63235)){setMode("moving");}
92 | else if(keyCode==8||keyCode==46||keyCode==127){setMode("deleting");}
93 | else if(keyCode==13){setMode("newlines");}
94 | else if(keyCode==27){setMode("escape");}
95 | else if((keyCode<16||keyCode>20)&&keyCode!=91){setMode("typing");}}};var setEventHandlers=function(){util.addEvent(textarea,"keypress",function(event){if((event.ctrlKey||event.metaKey)&&(event.keyCode==89||event.keyCode==90)){event.preventDefault();}});var handlePaste=function(){if(browser.isIE||(inputStateObj&&inputStateObj.text!=textarea.value)){if(timer==undefined){mode="paste";saveState();refreshState();}}};poller=new InputPoller(textarea,handlePaste,pastePollInterval);util.addEvent(textarea,"keydown",handleCtrlYZ);util.addEvent(textarea,"keydown",handleModeChange);util.addEvent(textarea,"mousedown",function(){setMode("moving");});textarea.onpaste=handlePaste;textarea.ondrop=handlePaste;};var init=function(){setEventHandlers();refreshState();saveState();};this.destroy=function(){if(poller){poller.destroy();}};init();};WMDEditor.util=util;WMDEditor.position=position;WMDEditor.TextareaState=TextareaState;WMDEditor.InputPoller=InputPoller;WMDEditor.PreviewManager=PreviewManager;WMDEditor.UndoManager=UndoManager;var doc=window.document;var re=window.RegExp;var nav=window.navigator;function get_browser(){var b={};b.isIE=/msie/.test(nav.userAgent.toLowerCase());b.isIE_5or6=/msie 6/.test(nav.userAgent.toLowerCase())||/msie 5/.test(nav.userAgent.toLowerCase());b.isIE_7plus=b.isIE&&!b.isIE_5or6;b.isOpera=/opera/.test(nav.userAgent.toLowerCase());b.isKonqueror=/konqueror/.test(nav.userAgent.toLowerCase());return b;}
96 | var browser=get_browser();var wmdBase=function(wmd,wmd_options){wmd.Command={};wmd.Global={};wmd.buttons={};wmd.showdown=window.Showdown;var util=WMDEditor.util;var position=WMDEditor.position;var command=wmd.Command;wmd.ieCachedRange=null;wmd.ieRetardedClick=false;wmd.editor=function(previewRefreshCallback){if(!previewRefreshCallback){previewRefreshCallback=function(){};}
97 | var inputBox=wmd.panels.input;var offsetHeight=0;var editObj=this;var mainDiv;var mainSpan;var div;var creationHandle;var undoMgr;var doClick=function(button){inputBox.focus();if(button.textOp){if(undoMgr){undoMgr.setCommandMode();}
98 | var state=new TextareaState(wmd.panels.input,wmd);if(!state){return;}
99 | var chunks=state.getChunks();var fixupInputArea=function(){inputBox.focus();if(chunks){state.setChunks(chunks);}
100 | state.restore();previewRefreshCallback();};var useDefaultText=true;var noCleanup=button.textOp(chunks,fixupInputArea,useDefaultText);if(!noCleanup){fixupInputArea();}}
101 | if(button.execute){button.execute(editObj);}};var setUndoRedoButtonStates=function(){if(undoMgr){if(wmd.buttons["wmd-undo-button"])setupButton(wmd.buttons["wmd-undo-button"],undoMgr.canUndo());if(wmd.buttons["wmd-redo-button"])setupButton(wmd.buttons["wmd-redo-button"],undoMgr.canRedo());}};var setupButton=function(button,isEnabled){if(isEnabled){button.className=button.className.replace(new RegExp("(^|\\s+)disabled(\\s+|$)"),' ');if(browser.isIE){button.onmousedown=function(){wmd.ieRetardedClick=true;wmd.ieCachedRange=document.selection.createRange();};}
102 | if(!button.isHelp){button.onclick=function(){if(this.onmouseout){this.onmouseout();}
103 | doClick(this);return false;};}}
104 | else{button.className+=(button.className?' ':'')+'disabled';button.onmouseover=button.onmouseout=button.onclick=function(){};}};var makeSpritedButtonRow=function(){var buttonBar=(typeof wmd_options.button_bar=='string')?document.getElementById(wmd_options.button_bar||"wmd-button-bar"):wmd_options.button_bar;var normalYShift="0px";var disabledYShift="-20px";var highlightYShift="-40px";var buttonRow=document.createElement("ul");buttonRow.className="wmd-button-row";buttonRow=buttonBar.appendChild(buttonRow);var xoffset=0;function createButton(name,title,textOp){var button=document.createElement("li");wmd.buttons[name]=button;button.className="wmd-button "+name;button.XShift=xoffset+"px";xoffset-=20;if(title)button.title=title;if(textOp)button.textOp=textOp;return button;}
105 | function addButton(name,title,textOp){var button=createButton(name,title,textOp);setupButton(button,true);buttonRow.appendChild(button);return button;}
106 | function addSpacer(){var spacer=document.createElement("li");spacer.className="wmd-spacer";buttonRow.appendChild(spacer);return spacer;}
107 | var modifierKey=(navigator.appVersion.indexOf("Mac")!=-1)?"Cmd":"Ctrl";var buttonlist=wmd_options.buttons.split(' ');for(var i=0;i\n" + bq + "\n
");
1035 | });
1036 | return text;
1037 | };
1038 |
1039 |
1040 | var _FormParagraphs = function (text) {
1041 | //
1042 | // Params:
1043 | // $text - string to process with html
"); // ** GFM **
1079 | str = str.replace(/^([ \t]*)/g, p_tag);
1080 | str += "
http://i.imgur.com/1cZl4.jpg
http://www.google.com/]*")?(\stitle="[^"<>]*")?\s?\/?>)$/i}};WMDEditor.prototype={getPanels:function(){return{buttonBar:(typeof this.options.button_bar=='string')?document.getElementById(this.options.button_bar):this.options.button_bar,preview:(typeof this.options.preview=='string')?document.getElementById(this.options.preview):this.options.preview,output:(typeof this.options.output=='string')?document.getElementById(this.options.output):this.options.output,input:(typeof this.options.input=='string')?document.getElementById(this.options.input):this.options.input};},startEditor:function(){this.panels=this.getPanels();this.previewMgr=new PreviewManager(this);edit=new this.editor(this.previewMgr.refresh);this.previewMgr.refresh(true);}};var util={isVisible:function(elem){return elem.offsetWidth>0||elem.offsetHeight>0;},addEvent:function(elem,event,listener){if(elem.attachEvent){elem.attachEvent("on"+event,listener);}
2 | else{elem.addEventListener(event,listener,false);}},removeEvent:function(elem,event,listener){if(elem.detachEvent){elem.detachEvent("on"+event,listener);}
3 | else{elem.removeEventListener(event,listener,false);}},fixEolChars:function(text){text=text.replace(/\r\n/g,"\n");text=text.replace(/\r/g,"\n");return text;},extendRegExp:function(regex,pre,post){if(pre===null||pre===undefined){pre="";}
4 | if(post===null||post===undefined){post="";}
5 | var pattern=regex.toString();var flags="";var result=pattern.match(/\/([gim]*)$/);if(result===null){flags=result[0];}
6 | else{flags="";}
7 | pattern=pattern.replace(/(^\/|\/[gim]*$)/g,"");pattern=pre+pattern+post;return new RegExp(pattern,flags);},createImage:function(img){var imgPath=imageDirectory+img;var elem=document.createElement("img");elem.className="wmd-button";elem.src=imgPath;return elem;},prompt:function(text,defaultInputText,makeLinkMarkdown,promptType){var dialog;var background;var input;var titleInput;var newWinCheckbox;if(defaultInputText===undefined){defaultInputText="";}
8 | var checkEscape=function(key){var code=(key.charCode||key.keyCode);if(code===27){close(true);}};var close=function(isCancel){util.removeEvent(document.body,"keydown",checkEscape);var text=input.value+(titleInput.value?' "'+titleInput.value+'"':'');if(isCancel){text=null;}
9 | else{text=text.replace('http://http://','http://');text=text.replace('http://https://','https://');text=text.replace('http://ftp://','ftp://');if(promptType=='link'&&newWinCheckbox.checked)text='!'+text;}
10 | dialog.parentNode.removeChild(dialog);background.parentNode.removeChild(background);makeLinkMarkdown(text);return false;};var createBackground=function(){background=document.createElement("div");background.className="wmd-prompt-background";style=background.style;style.position="absolute";style.top="0";style.zIndex="10000";if(browser.isKonqueror){style.backgroundColor="transparent";}
11 | else if(browser.isIE){style.filter="alpha(opacity=50)";}
12 | else{style.opacity="0.5";}
13 | var pageSize=position.getPageSize();style.height=pageSize[1]+"px";if(browser.isIE){style.left=document.documentElement.scrollLeft;style.width=document.documentElement.clientWidth;}
14 | else{style.left="0";style.width="100%";}
15 | document.body.appendChild(background);};var createDialog=function(){dialog=document.createElement("div");dialog.className="wmd-prompt-dialog";dialog.style.padding="10px;";dialog.style.position="fixed";dialog.style.width="400px";dialog.style.zIndex="10001";var question=document.createElement("div");question.innerHTML=text;question.style.padding="5px";dialog.appendChild(question);var form=document.createElement("form");form.onsubmit=function(){return close(false);};var style=form.style;style.padding="0";style.margin="0";style.cssFloat="left";style.width="100%";style.textAlign="center";style.position="relative";dialog.appendChild(form);var label=document.createElement("label");style=label.style;style.display="block";style.width="80%";style.marginLeft=style.marginRight="auto";style.textAlign="left";form.appendChild(label);label.appendChild(document.createTextNode(promptType+" URL:"));input=document.createElement("input");input.type="text";input.value=defaultInputText;style=input.style;style.display="block";style.width="100%";style.marginLeft=style.marginRight="auto";label.appendChild(input);label=document.createElement("label");style=label.style;style.display="block";style.width="80%";style.marginLeft=style.marginRight="auto";style.textAlign="left";form.appendChild(label);label.appendChild(document.createTextNode(promptType+" Title (Hover Text):"));titleInput=document.createElement("input");titleInput.type="text";style=titleInput.style;style.display="block";style.width="100%";style.marginLeft=style.marginRight="auto";label.appendChild(titleInput);if(promptType=='link'){label=document.createElement("label");style=label.style;style.display="block";style.textAlign="center";form.appendChild(label);newWinCheckbox=document.createElement("input");newWinCheckbox.type='checkbox';newWinCheckbox.value='!';label.appendChild(newWinCheckbox);label.appendChild(document.createTextNode(" Have this link open in a new window"));}
16 | var okButton=document.createElement("input");okButton.type="button";okButton.onclick=function(){return close(false);};okButton.value="OK";style=okButton.style;style.margin="10px";style.display="inline";style.width="7em";var cancelButton=document.createElement("input");cancelButton.type="button";cancelButton.onclick=function(){return close(true);};cancelButton.value="Cancel";style=cancelButton.style;style.margin="10px";style.display="inline";style.width="7em";if(/mac/.test(nav.platform.toLowerCase())){form.appendChild(cancelButton);form.appendChild(okButton);}
17 | else{form.appendChild(okButton);form.appendChild(cancelButton);}
18 | util.addEvent(document.body,"keydown",checkEscape);dialog.style.top="50%";dialog.style.left="50%";dialog.style.display="block";if(browser.isIE_5or6){dialog.style.position="absolute";dialog.style.top=document.documentElement.scrollTop+200+"px";dialog.style.left="50%";}
19 | document.body.appendChild(dialog);dialog.style.marginTop=-(position.getHeight(dialog)/2)+"px";dialog.style.marginLeft=-(position.getWidth(dialog)/2)+"px";};createBackground();window.setTimeout(function(){createDialog();var defTextLen=defaultInputText.length;if(input.selectionStart!==undefined){input.selectionStart=0;input.selectionEnd=defTextLen;}
20 | else if(input.createTextRange){var range=input.createTextRange();range.collapse(false);range.moveStart("character",-defTextLen);range.moveEnd("character",defTextLen);range.select();}
21 | input.focus();},0);},extend:function(){function _update(a,b){for(var k in b)if(b.hasOwnProperty(k)){if(typeof a[k]==='object'&&typeof b[k]==='object')_update(a[k],b[k]);else a[k]=b[k];}
22 | return a;}
23 | var d={};for(var i=0;i
"+newText+" "+modifierKey+"+Q",command.doBlockquote);break;case'code':addButton("wmd-code-button","Code Sample
"+modifierKey+"+K",command.doCode);break;case'image':addButton("wmd-image-button","Image "+modifierKey+"+G",function(chunk,postProcessing,useDefaultText){return command.doLinkOrImage(chunk,postProcessing,true);});break;case'ol':addButton("wmd-olist-button","Numbered List
"+modifierKey+"+O",function(chunk,postProcessing,useDefaultText){command.doList(chunk,postProcessing,true,useDefaultText);});break;case'ul':addButton("wmd-ulist-button","Bulleted List
"+modifierKey+"+U",function(chunk,postProcessing,useDefaultText){command.doList(chunk,postProcessing,false,useDefaultText);});break;case'heading':addButton("wmd-heading-button","Heading
/
"+modifierKey+"+H",command.doHeading);break;case'hr':addButton("wmd-hr-button","Horizontal Rule
"+modifierKey+"+R",command.doHorizontalRule);break;case'undo':var undoButton=addButton("wmd-undo-button","Undo - "+modifierKey+"+Z");undoButton.execute=function(manager){manager.undo();};break;case'redo':var redoButton=addButton("wmd-redo-button","Redo - "+modifierKey+"+Y");if(/win/.test(nav.platform.toLowerCase())){redoButton.title="Redo - "+modifierKey+"+Y";}
108 | else{redoButton.title="Redo - "+modifierKey+"+Shift+Z";}
109 | redoButton.execute=function(manager){manager.redo();};break;case'help':var helpButton=createButton("wmd-help-button");helpButton.isHelp=true;setupButton(helpButton,true);buttonRow.appendChild(helpButton);var helpAnchor=document.createElement("a");helpAnchor.href=wmd_options.helpLink;helpAnchor.target=wmd_options.helpTarget;helpAnchor.title=wmd_options.helpHoverTitle;helpButton.appendChild(helpAnchor);break;case'':addSpacer();break;}}
110 | setUndoRedoButtonStates();};var setupEditor=function(){if(/\?noundo/.test(document.location.href)){wmd.nativeUndo=true;}
111 | if(!wmd.nativeUndo){undoMgr=new UndoManager(wmd,wmd.panels.input,wmd.options.pastePollInterval,function(){previewRefreshCallback();setUndoRedoButtonStates();});}
112 | makeSpritedButtonRow();var keyEvent="keydown";if(browser.isOpera){keyEvent="keypress";}
113 | util.addEvent(inputBox,keyEvent,function(key){if(wmd.options.modifierKeys&&(key.ctrlKey||key.metaKey)){var keyCode=key.charCode||key.keyCode;var keyCodeStr=String.fromCharCode(keyCode).toLowerCase();switch(keyCodeStr){case wmd.options.modifierKeys.bold:if(wmd.buttons["wmd-bold-button"])doClick(wmd.buttons["wmd-bold-button"]);else return;break;case wmd.options.modifierKeys.italic:if(wmd.buttons["wmd-italic-button"])doClick(wmd.buttons["wmd-italic-button"]);else return;break;case wmd.options.modifierKeys.link:if(wmd.buttons["wmd-link-button"])doClick(wmd.buttons["wmd-link-button"]);else return;break;case wmd.options.modifierKeys.quote:if(wmd.buttons["wmd-quote-button"])doClick(wmd.buttons["wmd-quote-button"]);else return;break;case wmd.options.modifierKeys.code:if(wmd.buttons["wmd-code-button"])doClick(wmd.buttons["wmd-code-button"]);else return;break;case wmd.options.modifierKeys.image:if(wmd.buttons["wmd-image-button"])doClick(wmd.buttons["wmd-image-button"]);else return;break;case wmd.options.modifierKeys.orderedList:if(wmd.buttons["wmd-olist-button"])doClick(wmd.buttons["wmd-olist-button"]);else return;break;case wmd.options.modifierKeys.unorderedList:if(wmd.buttons["wmd-ulist-button"])doClick(wmd.buttons["wmd-ulist-button"]);else return;break;case wmd.options.modifierKeys.heading:if(wmd.buttons["wmd-heading-button"])doClick(wmd.buttons["wmd-heading-button"]);else return;break;case wmd.options.modifierKeys.horizontalRule:if(wmd.buttons["wmd-hr-button"])doClick(wmd.buttons["wmd-hr-button"]);else return;break;case wmd.options.modifierKeys.redo:if(wmd.buttons["wmd-redo-button"])doClick(wmd.buttons["wmd-redo-button"]);else return;break;case wmd.options.modifierKeys.undo:if(key.shiftKey){if(wmd.buttons["wmd-redo-button"])doClick(wmd.buttons["wmd-redo-button"]);else return;}else{if(wmd.buttons["wmd-undo-button"])doClick(wmd.buttons["wmd-undo-button"]);else return;}
114 | break;default:return;}
115 | if(key.preventDefault){key.preventDefault();}
116 | if(window.event){window.event.returnValue=false;}}});util.addEvent(inputBox,"keyup",function(key){if(!key.shiftKey&&!key.ctrlKey&&!key.metaKey){var keyCode=key.charCode||key.keyCode;if(keyCode===13){fakeButton={};fakeButton.textOp=command.doAutoindent;doClick(fakeButton);}}});if(browser.isIE){util.addEvent(inputBox,"keydown",function(key){var code=key.keyCode;if(code===27){return false;}});}};this.undo=function(){if(undoMgr){undoMgr.undo();}};this.redo=function(){if(undoMgr){undoMgr.redo();}};var init=function(){setupEditor();};this.destroy=function(){if(undoMgr){undoMgr.destroy();}
117 | if(div.parentNode){div.parentNode.removeChild(div);}
118 | if(inputBox){inputBox.style.marginTop="";}
119 | window.clearInterval(creationHandle);};init();};command.prefixes="(?:\\s{4,}|\\s*>|\\s*-\\s+|\\s*\\d+\\.|=|\\+|-|_|\\*|#|\\s*\\[[^\n]]+\\]:)";command.unwrap=function(chunk){var txt=new re("([^\\n])\\n(?!(\\n|"+command.prefixes+"))","g");chunk.selection=chunk.selection.replace(txt,"$1 $2");};command.wrap=function(chunk,len){command.unwrap(chunk);var regex=new re("(.{1,"+len+"})( +|$\\n?)","gm");chunk.selection=chunk.selection.replace(regex,function(line,marked){if(new re("^"+command.prefixes,"").test(line)){return line;}
120 | return marked+"\n";});chunk.selection=chunk.selection.replace(/\s+$/,"");};command.doBold=function(chunk,postProcessing,useDefaultText){return command.doBorI(chunk,2,"strong text");};command.doItalic=function(chunk,postProcessing,useDefaultText){return command.doBorI(chunk,1,"emphasized text");};command.doBorI=function(chunk,nStars,insertText){chunk.trimWhitespace();chunk.selection=chunk.selection.replace(/\n{2,}/g,"\n");chunk.before.search(/(\**$)/);var starsBefore=re.$1;chunk.after.search(/(^\**)/);var starsAfter=re.$1;var prevStars=Math.min(starsBefore.length,starsAfter.length);if((prevStars>=nStars)&&(prevStars!=2||nStars!=1)){chunk.before=chunk.before.replace(re("[*]{"+nStars+"}$",""),"");chunk.after=chunk.after.replace(re("^[*]{"+nStars+"}",""),"");}
121 | else if(!chunk.selection&&starsAfter){chunk.after=chunk.after.replace(/^([*_]*)/,"");chunk.before=chunk.before.replace(/(\s?)$/,"");var whitespace=re.$1;chunk.before=chunk.before+starsAfter+whitespace;}
122 | else{if(!chunk.selection&&!starsAfter){chunk.selection=insertText;}
123 | var markup=nStars<=1?"*":"**";chunk.before=chunk.before+markup;chunk.after=markup+chunk.after;}
124 | return;};command.stripLinkDefs=function(text,defsToAdd){text=text.replace(/^[ ]{0,3}\[(\d+)\]:[ \t]*\n?[ \t]*(\S+?)>?[ \t]*\n?[ \t]*(?:(\n*)["(](.+?)[")][ \t]*)?(?:\n+|$)/gm,function(totalMatch,id,link,newlines,title){defsToAdd[id]=totalMatch.replace(/\s*$/,"");if(newlines){defsToAdd[id]=totalMatch.replace(/["(](.+?)[")]$/,"");return newlines+title;}
125 | return"";});return text;};command.addLinkDef=function(chunk,linkDef){var refNumber=0;var defsToAdd={};chunk.before=command.stripLinkDefs(chunk.before,defsToAdd);chunk.selection=command.stripLinkDefs(chunk.selection,defsToAdd);chunk.after=command.stripLinkDefs(chunk.after,defsToAdd);var defs="";var regex=/(\[(?:\[[^\]]*\]|[^\[\]])*\][ ]?(?:\n[ ]*)?\[)(\d+)(\])/g;var addDefNumber=function(def){refNumber++;def=def.replace(/^[ ]{0,3}\[(\d+)\]:/," ["+refNumber+"]:");defs+="\n"+def;};var getLink=function(wholeMatch,link,id,end){if(defsToAdd[id]){addDefNumber(defsToAdd[id]);return link+refNumber+end;}
126 | return wholeMatch;};chunk.before=chunk.before.replace(regex,getLink);if(linkDef){addDefNumber(linkDef);}
127 | else{chunk.selection=chunk.selection.replace(regex,getLink);}
128 | var refOut=refNumber;chunk.after=chunk.after.replace(regex,getLink);if(chunk.after){chunk.after=chunk.after.replace(/\n*$/,"");}
129 | if(!chunk.after){chunk.selection=chunk.selection.replace(/\n*$/,"");}
130 | chunk.after+="\n\n"+defs;return refOut;};command.doLinkOrImage=function(chunk,postProcessing,isImage){chunk.trimWhitespace();chunk.findTags(/\s*!?\[/,/\][ ]?(?:\n[ ]*)?(\[.*?\])?/);if(chunk.endTag.length>1){chunk.startTag=chunk.startTag.replace(/!?\[/,"");chunk.endTag="";command.addLinkDef(chunk,null);}
131 | else{if(/\n\n/.test(chunk.selection)){command.addLinkDef(chunk,null);return;}
132 | var makeLinkMarkdown=function(link){console.log(link);if(link!==null){chunk.startTag=chunk.endTag="";var linkDef=" [999]: "+link;var num=command.addLinkDef(chunk,linkDef);chunk.startTag=isImage?"![":"[";chunk.endTag="]["+num+"]";if(!chunk.selection){if(isImage){chunk.selection="alt text";}
133 | else{chunk.selection="link text";}}}
134 | postProcessing();};if(isImage){util.prompt(wmd_options.imageDialogText,wmd_options.imageDefaultText,makeLinkMarkdown,'Image');}
135 | else{util.prompt(wmd_options.linkDialogText,wmd_options.linkDefaultText,makeLinkMarkdown,'Link');}
136 | return true;}};command.doAutoindent=function(chunk,postProcessing,useDefaultText){if(!wmd.options.autoFormatting)return;if(wmd.options.autoFormatting.list)chunk.before=chunk.before.replace(/(\n|^)[ ]{0,3}([*+-]|\d+[.])[ \t]*\n$/,"\n\n");if(wmd.options.autoFormatting.quote)chunk.before=chunk.before.replace(/(\n|^)[ ]{0,3}>[ \t]*\n$/,"\n\n");if(wmd.options.autoFormatting.code)chunk.before=chunk.before.replace(/(\n|^)[ \t]+\n$/,"\n\n");useDefaultText=false;if(/(\n|^)[ ]{0,3}([*+-])[ \t]+.*\n$/.test(chunk.before)){if(command.doList&&wmd.options.autoFormatting.list){command.doList(chunk,postProcessing,false,true);}}
137 | if(/(\n|^)[ ]{0,3}(\d+[.])[ \t]+.*\n$/.test(chunk.before)){if(command.doList&&wmd.options.autoFormatting.list){command.doList(chunk,postProcessing,true,true);}}
138 | if(/(\n|^)[ ]{0,3}>[ \t]+.*\n$/.test(chunk.before)){if(command.doBlockquote&&wmd.options.autoFormatting.quote){command.doBlockquote(chunk,postProcessing,useDefaultText);}}
139 | if(/(\n|^)(\t|[ ]{4,}).*\n$/.test(chunk.before)){if(command.doCode&&wmd.options.autoFormatting.code){command.doCode(chunk,postProcessing,useDefaultText);}}};command.doBlockquote=function(chunk,postProcessing,useDefaultText){chunk.selection=chunk.selection.replace(/^(\n*)([^\r]+?)(\n*)$/,function(totalMatch,newlinesBefore,text,newlinesAfter){chunk.before+=newlinesBefore;chunk.after=newlinesAfter+chunk.after;return text;});chunk.before=chunk.before.replace(/(>[ \t]*)$/,function(totalMatch,blankLine){chunk.selection=blankLine+chunk.selection;return"";});var defaultText=useDefaultText?"Blockquote":"";chunk.selection=chunk.selection.replace(/^(\s|>)+$/,"");chunk.selection=chunk.selection||defaultText;if(chunk.before){chunk.before=chunk.before.replace(/\n?$/,"\n");}
140 | if(chunk.after){chunk.after=chunk.after.replace(/^\n?/,"\n");}
141 | chunk.before=chunk.before.replace(/(((\n|^)(\n[ \t]*)*>(.+\n)*.*)+(\n[ \t]*)*$)/,function(totalMatch){chunk.startTag=totalMatch;return"";});chunk.after=chunk.after.replace(/^(((\n|^)(\n[ \t]*)*>(.+\n)*.*)+(\n[ \t]*)*)/,function(totalMatch){chunk.endTag=totalMatch;return"";});var replaceBlanksInTags=function(useBracket){var replacement=useBracket?"> ":"";if(chunk.startTag){chunk.startTag=chunk.startTag.replace(/\n((>|\s)*)\n$/,function(totalMatch,markdown){return"\n"+markdown.replace(/^[ ]{0,3}>?[ \t]*$/gm,replacement)+"\n";});}
142 | if(chunk.endTag){chunk.endTag=chunk.endTag.replace(/^\n((>|\s)*)\n/,function(totalMatch,markdown){return"\n"+markdown.replace(/^[ ]{0,3}>?[ \t]*$/gm,replacement)+"\n";});}};if(/^(?![ ]{0,3}>)/m.test(chunk.selection)){command.wrap(chunk,wmd_options.lineLength-2);chunk.selection=chunk.selection.replace(/^/gm,"> ");replaceBlanksInTags(true);chunk.addBlankLines();}
143 | else{chunk.selection=chunk.selection.replace(/^[ ]{0,3}> ?/gm,"");command.unwrap(chunk);replaceBlanksInTags(false);if(!/^(\n|^)[ ]{0,3}>/.test(chunk.selection)&&chunk.startTag){chunk.startTag=chunk.startTag.replace(/\n{0,2}$/,"\n\n");}
144 | if(!/(\n|^)[ ]{0,3}>.*$/.test(chunk.selection)&&chunk.endTag){chunk.endTag=chunk.endTag.replace(/^\n{0,2}/,"\n\n");}}
145 | if(!/\n/.test(chunk.selection)){chunk.selection=chunk.selection.replace(/^(> *)/,function(wholeMatch,blanks){chunk.startTag+=blanks;return"";});}};command.doCode=function(chunk,postProcessing,useDefaultText){var hasTextBefore=/\S[ ]*$/.test(chunk.before);var hasTextAfter=/^[ ]*\S/.test(chunk.after);if((!hasTextAfter&&!hasTextBefore)||/\n/.test(chunk.selection)){chunk.before=chunk.before.replace(/[ ]{4}$/,function(totalMatch){chunk.selection=totalMatch+chunk.selection;return"";});var nLinesBefore=1;var nLinesAfter=1;if(/\n(\t|[ ]{4,}).*\n$/.test(chunk.before)||chunk.after===""){nLinesBefore=0;}
146 | if(/^\n(\t|[ ]{4,})/.test(chunk.after)){nLinesAfter=0;}
147 | chunk.addBlankLines(nLinesBefore,nLinesAfter);if(!chunk.selection){chunk.startTag=" ";chunk.selection=useDefaultText?"enter code here":"";}
148 | else{if(/^[ ]{0,3}\S/m.test(chunk.selection)){chunk.selection=chunk.selection.replace(/^/gm," ");}
149 | else{chunk.selection=chunk.selection.replace(/^[ ]{4}/gm,"");}}}
150 | else{chunk.trimWhitespace();chunk.findTags(/`/,/`/);if(!chunk.startTag&&!chunk.endTag){chunk.startTag=chunk.endTag="`";if(!chunk.selection){chunk.selection=useDefaultText?"enter code here":"";}}
151 | else if(chunk.endTag&&!chunk.startTag){chunk.before+=chunk.endTag;chunk.endTag="";}
152 | else{chunk.startTag=chunk.endTag="";}}};command.doList=function(chunk,postProcessing,isNumberedList,useDefaultText){var previousItemsRegex=/(\n|^)(([ ]{0,3}([*+-]|\d+[.])[ \t]+.*)(\n.+|\n{2,}([*+-].*|\d+[.])[ \t]+.*|\n{2,}[ \t]+\S.*)*)\n*$/;var nextItemsRegex=/^\n*(([ ]{0,3}([*+-]|\d+[.])[ \t]+.*)(\n.+|\n{2,}([*+-].*|\d+[.])[ \t]+.*|\n{2,}[ \t]+\S.*)*)\n*/;var bullet="-";var num=1;var getItemPrefix=function(){var prefix;if(isNumberedList){prefix=" "+num+". ";num++;}
153 | else{prefix=" "+bullet+" ";}
154 | return prefix;};var getPrefixedItem=function(itemText){if(isNumberedList===undefined){isNumberedList=/^\s*\d/.test(itemText);}
155 | itemText=itemText.replace(/^[ ]{0,3}([*+-]|\d+[.])\s/gm,function(_){return getItemPrefix();});return itemText;};chunk.findTags(/(\n|^)*[ ]{0,3}([*+-]|\d+[.])\s+/,null);if(chunk.before&&!/\n$/.test(chunk.before)&&!/^\n/.test(chunk.startTag)){chunk.before+=chunk.startTag;chunk.startTag="";}
156 | if(chunk.startTag){var hasDigits=/\d+[.]/.test(chunk.startTag);chunk.startTag="";chunk.selection=chunk.selection.replace(/\n[ ]{4}/g,"\n");command.unwrap(chunk);chunk.addBlankLines();if(hasDigits){chunk.after=chunk.after.replace(nextItemsRegex,getPrefixedItem);}
157 | if(isNumberedList==hasDigits){return;}}
158 | var nLinesBefore=1;chunk.before=chunk.before.replace(previousItemsRegex,function(itemText){if(/^\s*([*+-])/.test(itemText)){bullet=re.$1;}
159 | nLinesBefore=/[^\n]\n\n[^\n]/.test(itemText)?1:0;return getPrefixedItem(itemText);});if(!chunk.selection){chunk.selection=useDefaultText?"List item":" ";}
160 | var prefix=getItemPrefix();var nLinesAfter=1;chunk.after=chunk.after.replace(nextItemsRegex,function(itemText){nLinesAfter=/[^\n]\n\n[^\n]/.test(itemText)?1:0;return getPrefixedItem(itemText);});chunk.trimWhitespace(true);chunk.addBlankLines(nLinesBefore,nLinesAfter,true);chunk.startTag=prefix;var spaces=prefix.replace(/./g," ");command.wrap(chunk,wmd_options.lineLength-spaces.length);chunk.selection=chunk.selection.replace(/\n/g,"\n"+spaces);};command.doHeading=function(chunk,postProcessing,useDefaultText){chunk.selection=chunk.selection.replace(/\s+/g," ");chunk.selection=chunk.selection.replace(/(^\s+|\s+$)/g,"");if(!chunk.selection){chunk.startTag="## ";chunk.selection="Heading";chunk.endTag=" ##";return;}
161 | var headerLevel=0;chunk.findTags(/#+[ ]*/,/[ ]*#+/);if(/#+/.test(chunk.startTag)){headerLevel=re.lastMatch.length;}
162 | chunk.startTag=chunk.endTag="";chunk.findTags(null,/\s?(-+|=+)/);if(/=+/.test(chunk.endTag)){headerLevel=1;}
163 | if(/-+/.test(chunk.endTag)){headerLevel=2;}
164 | chunk.startTag=chunk.endTag="";chunk.addBlankLines(1,1);var headerLevelToCreate=headerLevel==0?2:headerLevel-1;if(headerLevelToCreate>0){var headerChar=headerLevelToCreate>=2?"-":"=";var len=chunk.selection.length;if(len>wmd_options.lineLength){len=wmd_options.lineLength;}
165 | chunk.endTag="\n";while(len--){chunk.endTag+=headerChar;}}};command.doHorizontalRule=function(chunk,postProcessing,useDefaultText){chunk.startTag="----------\n";chunk.selection="";chunk.addBlankLines(2,1,true);};};})();function setup_wmd(options){return new WMDEditor(options);}
166 | Showdown={};Showdown.converter=function(){var g_urls;var g_titles;var g_html_blocks;var g_list_level=0;this.makeHtml=function(text){g_urls=[];g_titles=[];g_html_blocks=[];text=text.replace(/~/g,"~T");text=text.replace(/\$/g,"~D");text=text.replace(/\r\n/g,"\n");text=text.replace(/\r/g,"\n");text="\n\n"+text+"\n\n";text=_Detab(text);text=text.replace(/^[ \t]+$/mg,"");text=_HashHTMLBlocks(text);text=_StripLinkDefinitions(text);text=_RunBlockGamut(text);text=_UnescapeSpecialChars(text);text=text.replace(/~D/g,"$$");text=text.replace(/~T/g,"~");text=text.replace(/https?\:\/\/[^"\s<>]*[^.,;'">\:\s<>\)\]\!]/g,function(wholeMatch,matchIndex){var left=text.slice(Math.max(0,text.lastIndexOf('\n',matchIndex)),matchIndex);var right=text.slice(matchIndex);if(left.match(/<([a-z]+)\s[^>]+>?$/)&&right.match(/^[^>]*>/)){return wholeMatch;}
167 | return""+wholeMatch+"";});text=text.replace(/[a-z0-9_\-+=.]+@[a-z0-9\-]+(\.[a-z0-9\-]+)+/ig,function(wholeMatch,m1,matchIndex){var left=text.slice(Math.max(0,text.lastIndexOf('\n',matchIndex)),matchIndex);if(left.match(/<([a-z]+)\s[^>]+>?$/)||left.match(/mailto\:$/)){return wholeMatch;}
168 | return""+wholeMatch+"";});return text;};var _StripLinkDefinitions=function(text){text=text.replace(/^[ ]{0,3}\[(.+)\]:[ \t]*\n?[ \t]*(\S+?)>?[ \t]*\n?[ \t]*(?:(\n*)["(](.+?)[")][ \t]*)?(?:\n+)/gm,function(wholeMatch,m1,m2,m3,m4){m1=m1.toLowerCase();g_urls[m1]=_EncodeAmpsAndAngles(m2);if(m3){return m3+m4;}else if(m4){g_titles[m1]=m4.replace(/"/g,""");}
169 | return"";});return text;};var _HashHTMLBlocks=function(text){text=text.replace(/\n/g,"\n\n");var block_tags_a="p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del";var block_tags_b="p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math";text=text.replace(/^(<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del)\b[^\r]*?\n<\/\2>[ \t]*(?=\n+))/gm,hashElement);text=text.replace(/^(<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math)\b[^\r]*?.*<\/\2>[ \t]*(?=\n+)\n)/gm,hashElement);text=text.replace(/(\n[ ]{0,3}(<(hr)\b([^<>])*?\/?>)[ \t]*(?=\n{2,}))/g,hashElement);text=text.replace(/(\n\n[ ]{0,3}[ \t]*(?=\n{2,}))/g,hashElement);text=text.replace(/(?:\n\n)([ ]{0,3}(?:<([?%])[^\r]*?\2>)[ \t]*(?=\n{2,}))/g,hashElement);text=text.replace(/\n\n/g,"\n");return text;};var hashElement=function(wholeMatch,m1){var blockText=m1;blockText=blockText.replace(/\n\n/g,"\n");blockText=blockText.replace(/^\n/,"");blockText=blockText.replace(/\n+$/g,"");blockText="\n\n~K"+(g_html_blocks.push(blockText)-1)+"K\n\n";return blockText;};var _RunBlockGamut=function(text){text=_DoHeaders(text);var key=hashBlock("
");text=text.replace(/^[ ]{0,2}([ ]?\*[ ]?){3,}[ \t]*$/gm,key);text=text.replace(/^[ ]{0,2}([ ]?\-[ ]?){3,}[ \t]*$/gm,key);text=text.replace(/^[ ]{0,2}([ ]?\_[ ]?){3,}[ \t]*$/gm,key);text=_DoLists(text);text=_DoCodeBlocks(text);text=_DoBlockQuotes(text);text=_HashHTMLBlocks(text);text=_FormParagraphs(text);return text;};var _RunSpanGamut=function(text){text=_DoCodeSpans(text);text=_EscapeSpecialCharsWithinTagAttributes(text);text=_EncodeBackslashEscapes(text);text=_DoImages(text);text=_DoAnchors(text);text=_DoAutoLinks(text);text=_EncodeAmpsAndAngles(text);text=_ConvertExtraSpecialCharacters(text);text=_DoItalicsAndBold(text);text=text.replace(/ {2,}\n/g,"
\n");return text;};var _EscapeSpecialCharsWithinTagAttributes=function(text){var regex=/(<[a-z\/!$]("[^"]*"|'[^']*'|[^'">])*>|)/gi;text=text.replace(regex,function(wholeMatch){var tag=wholeMatch.replace(/(.)<\/?code>(?=.)/g,"$1`");tag=escapeCharacters(tag,"\\`*_");return tag;});return text;};var _DoAnchors=function(text){text=text.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g,writeAnchorTag);text=text.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\]\([ \t]*()(.*?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,writeAnchorTag);text=text.replace(/(\[([^\[\]]+)\])()()()()()/g,writeAnchorTag);return text;};var writeAnchorTag=function(wholeMatch,m1,m2,m3,m4,m5,m6,m7){if(m7===undefined)m7="";var whole_match=m1;var link_text=m2;var link_id=m3.toLowerCase();var url=m4;var title=m7;var blank_target=false;if(url===""){if(link_id===""){link_id=link_text.toLowerCase().replace(/ ?\n/g," ");}else{if(link_id[0]=="!"){blank_target=true;link_id=link_id.substr(1);}}
170 | url="#"+link_id;if(g_urls[link_id]!==undefined){url=g_urls[link_id];if(g_titles[link_id]!==undefined){title=g_titles[link_id];}
171 | if(url[0]=="!"){blank_target=true;url=url.substr(1);}}
172 | else{if(whole_match.search(/\(\s*\)$/m)>-1){url="";}else{return whole_match;}}}else{if(url[0]=="!"){blank_target=true;url=url.substr(1);}}
173 | url=escapeCharacters(url,"*_");var result=""+link_text+"";return result;};var _DoImages=function(text){text=text.replace(/(!\[(.*?)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g,writeImageTag);text=text.replace(/(!\[(.*?)\]\s?\([ \t]*()(\S+?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,writeImageTag);return text;};var writeImageTag=function(wholeMatch,m1,m2,m3,m4,m5,m6,m7){var whole_match=m1;var alt_text=m2;var link_id=m3.toLowerCase();var url=m4;var title=m7;if(!title)title="";if(url===""){if(link_id===""){link_id=alt_text.toLowerCase().replace(/ ?\n/g," ");}
176 | url="#"+link_id;if(g_urls[link_id]!==undefined){url=g_urls[link_id];if(g_titles[link_id]!==undefined){title=g_titles[link_id];}}
177 | else{return whole_match;}}
178 | alt_text=alt_text.replace(/"/g,""");url=escapeCharacters(url,"*_");var result="";return result;};var _DoHeaders=function(text){text=text.replace(/^(.+)[ \t]*\n=+[ \t]*\n+/gm,function(wholeMatch,m1){return hashBlock("
"+_RunSpanGamut(m1)+"
");});text=text.replace(/^(.+)[ \t]*\n-+[ \t]*\n+/gm,function(matchFound,m1){return hashBlock(""+_RunSpanGamut(m1)+"
");});text=text.replace(/^(\#{1,6})[ \t]*(.+?)[ \t]*\#*\n+/gm,function(wholeMatch,m1,m2){var h_level=m1.length;return hashBlock("
";return hashBlock(codeblock)+nextChar;});text=text.replace(/~0/,"");return text;};var hashBlock=function(text){text=text.replace(/(^\n+|\n+$)/g,"");return"\n\n~K"+(g_html_blocks.push(text)-1)+"K\n\n";};var _DoCodeSpans=function(text){text=text.replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm,function(wholeMatch,m1,m2,m3,m4){var c=m3;c=c.replace(/^([ \t]*)/g,"");c=c.replace(/[ \t]*$/g,"");c=_EncodeCode(c);return m1+""+codeblock+"\n"+c+"";});text=text.replace(/(^|[^\\])(\^{2})([^\r]*?[^\^]{2})\2(?!\^)/gm,function(wholeMatch,m1,m2,m3,m4){var c=m3;c=c.replace(/^([ \t]*)/g,"");c=c.replace(/[ \t]*$/g,"");c=_EncodeCode(c);return m1+""+c+"";});text=text.replace(/(^|[^\\])(,{2})([^\r]*?[^,]{2})\2(?!,)/gm,function(wholeMatch,m1,m2,m3,m4){var c=m3;c=c.replace(/^([ \t]*)/g,"");c=c.replace(/[ \t]*$/g,"");c=_EncodeCode(c);return m1+""+c+"";});text=text.replace(/(^|[^\\])(~T~T)([^\r]*?[^~]{2})\2(?!~)/gm,function(wholeMatch,m1,m2,m3,m4){var c=m3;c=c.replace(/^([ \t]*)/g,"");c=c.replace(/[ \t]*$/g,"");c=_EncodeCode(c);return m1+""+c+"";});return text;};var _EncodeCode=function(text){text=text.replace(/&/g,"&");text=text.replace(//g,">");text=text.replace(/\u2026/g,'…').replace(/\u00AB/g,'«').replace(/\u00BB/g,'»').replace(/\u201C/g,'“').replace(/\u201D/g,'”').replace(/\u2018/g,'‘').replace(/\u2019/g,'’').replace(/\u2014/g,'—').replace(/\u2013/g,'–').replace(/\u2022/g,'•').replace(/\u2122/g,'™').replace(/\u00A9/g,'©').replace(/\u00AE/g,'®');text=escapeCharacters(text,"*_{}[]\\",false);return text;};var _DoItalicsAndBold=function(text){if(true){text=text.replace(/(\*\*)(?=\S)([^\r]*?\S[*]*)\1/g,"$2");text=text.replace(/(\w)_(\w)/g,"$1~E95E$2");text=text.replace(/(\*)(?=\S)([^\r]*?\S)\1/g,"$2");text=text.replace(/(_)(?=\S)([^\r]*?\S)\1/g,"$2");}else{text=text.replace(/(\*\*|__)(?=\S)([^\r]*?\S[*_]*)\1/g,"$2");text=text.replace(/(\w)_(\w)/g,"$1~E95E$2");text=text.replace(/(\*|_)(?=\S)([^\r]*?\S)\1/g,"$2");}
182 | return text;};var _DoBlockQuotes=function(text){text=text.replace(/((^[ \t]*>[ \t]?.+\n(.+\n)*\n*)+)/gm,function(wholeMatch,m1){var bq=m1;bq=bq.replace(/^[ \t]*>[ \t]?/gm,"~0");bq=bq.replace(/~0/g,"");bq=bq.replace(/^[ \t]+$/gm,"");bq=_RunBlockGamut(bq);bq=bq.replace(/(^|\n)/g,"$1 ");bq=bq.replace(/(\s*[^\r]+?<\/pre>)/gm,function(wholeMatch,m1){var pre=m1;pre=pre.replace(/^ {2}/mg,"~0");pre=pre.replace(/~0/g,"");return pre;});return hashBlock("\n"+bq+"\n
");});return text;};var _FormParagraphs=function(text){text=text.replace(/^\n+/g,"");text=text.replace(/\n+$/g,"");var i;var grafs=text.split(/\n{2,}/g);var grafsOut=[];var end=grafs.length;for(i=0;i
");str=str.replace(/^([ \t]*)/g,p_tag);str+="
You can also add a title, which will be displayed as a tool tip.
Example:
http://i.imgur.com/1cZl4.jpg
Enter the web address.
You can also add a title, which will be displayed as a tool tip.
Example:
http://www.google.com/
1011 | else {
1012 | var newText = text.replace(/&/g, "&");
1013 | newText = newText.replace(/" + newText + "";
1015 | }
1016 | }
1017 |
1018 | if (wmd.panels.preview) {
1019 | // original WMD code allowed javascript injection, like this:
1020 | //
1021 | // now, we first ensure elements (and attributes of IMG and A elements) are in a whitelist
1022 | // and if not in whitelist, replace with blanks in preview to prevent XSS attacks
1023 | // when editing malicious markdown
1024 | // code courtesy of https://github.com/polestarsoft/wmd/commit/e7a09c9170ea23e7e806425f46d7423af2a74641
1025 | if (wmd.options.tagFilter.enabled) {
1026 | text = text.replace(/<[^<>]*>?/gi, function (tag) {
1027 | return (tag.match(wmd.options.tagFilter.allowedTags) || tag.match(wmd.options.tagFilter.patternLink) || tag.match(wmd.options.tagFilter.patternImage)) ? tag : "";
1028 | });
1029 | }
1030 | wmd.panels.preview.innerHTML = text;
1031 | }
1032 |
1033 | setPanelScrollTops();
1034 |
1035 | if (isFirstTimeFilled) {
1036 | isFirstTimeFilled = false;
1037 | return;
1038 | }
1039 |
1040 | var fullTop = position.getTop(wmd.panels.input) - getDocScrollTop();
1041 |
1042 | if (browser.isIE) {
1043 | window.setTimeout(function () {
1044 | window.scrollBy(0, fullTop - emptyTop);
1045 | }, 0);
1046 | }
1047 | else {
1048 | window.scrollBy(0, fullTop - emptyTop);
1049 | }
1050 | };
1051 |
1052 | var init = function () {
1053 |
1054 | setupEvents(wmd.panels.input, applyTimeout);
1055 | makePreviewHtml();
1056 |
1057 | if (wmd.panels.preview) {
1058 | wmd.panels.preview.scrollTop = 0;
1059 | }
1060 | if (wmd.panels.output) {
1061 | wmd.panels.output.scrollTop = 0;
1062 | }
1063 | };
1064 |
1065 | this.destroy = function () {
1066 | if (poller) {
1067 | poller.destroy();
1068 | }
1069 | };
1070 |
1071 | init();
1072 | }; // }}}
1073 | // Handles pushing and popping TextareaStates for undo/redo commands.
1074 | // I should rename the stack variables to list.
1075 | var UndoManager = function (wmd, textarea, pastePollInterval, callback) { // {{{
1076 | var undoObj = this;
1077 | var undoStack = []; // A stack of undo states
1078 | var stackPtr = 0; // The index of the current state
1079 | var mode = "none";
1080 | var lastState; // The last state
1081 | var poller;
1082 | var timer; // The setTimeout handle for cancelling the timer
1083 | var inputStateObj;
1084 |
1085 | // Set the mode for later logic steps.
1086 | var setMode = function (newMode, noSave) {
1087 |
1088 | if (mode != newMode) {
1089 | mode = newMode;
1090 | if (!noSave) {
1091 | saveState();
1092 | }
1093 | }
1094 |
1095 | if (!browser.isIE || mode != "moving") {
1096 | timer = window.setTimeout(refreshState, 1);
1097 | }
1098 | else {
1099 | inputStateObj = null;
1100 | }
1101 | };
1102 |
1103 | var refreshState = function () {
1104 | inputStateObj = new TextareaState(textarea, wmd);
1105 | poller.tick();
1106 | timer = undefined;
1107 | };
1108 |
1109 | this.setCommandMode = function () {
1110 | mode = "command";
1111 | saveState();
1112 | timer = window.setTimeout(refreshState, 0);
1113 | };
1114 |
1115 | this.canUndo = function () {
1116 | return stackPtr > 1;
1117 | };
1118 |
1119 | this.canRedo = function () {
1120 | if (undoStack[stackPtr + 1]) {
1121 | return true;
1122 | }
1123 | return false;
1124 | };
1125 |
1126 | // Removes the last state and restores it.
1127 | this.undo = function () {
1128 |
1129 | if (undoObj.canUndo()) {
1130 | if (lastState) {
1131 | // What about setting state -1 to null or checking for undefined?
1132 | lastState.restore();
1133 | lastState = null;
1134 | }
1135 | else {
1136 | undoStack[stackPtr] = new TextareaState(textarea, wmd);
1137 | undoStack[--stackPtr].restore();
1138 |
1139 | if (callback) {
1140 | callback();
1141 | }
1142 | }
1143 | }
1144 |
1145 | mode = "none";
1146 | textarea.focus();
1147 | refreshState();
1148 | };
1149 |
1150 | // Redo an action.
1151 | this.redo = function () {
1152 |
1153 | if (undoObj.canRedo()) {
1154 |
1155 | undoStack[++stackPtr].restore();
1156 |
1157 | if (callback) {
1158 | callback();
1159 | }
1160 | }
1161 |
1162 | mode = "none";
1163 | textarea.focus();
1164 | refreshState();
1165 | };
1166 |
1167 | // Push the input area state to the stack.
1168 | var saveState = function () {
1169 |
1170 | var currState = inputStateObj || new TextareaState(textarea, wmd);
1171 |
1172 | if (!currState) {
1173 | return false;
1174 | }
1175 | if (mode == "moving") {
1176 | if (!lastState) {
1177 | lastState = currState;
1178 | }
1179 | return;
1180 | }
1181 | if (lastState) {
1182 | if (undoStack[stackPtr - 1].text != lastState.text) {
1183 | undoStack[stackPtr++] = lastState;
1184 | }
1185 | lastState = null;
1186 | }
1187 | undoStack[stackPtr++] = currState;
1188 | undoStack[stackPtr + 1] = null;
1189 | if (callback) {
1190 | callback();
1191 | }
1192 | };
1193 |
1194 | var handleCtrlYZ = function (event) {
1195 |
1196 | var handled = false;
1197 |
1198 | if (event.ctrlKey || event.metaKey) {
1199 |
1200 | // IE and Opera do not support charCode.
1201 | var keyCode = event.charCode || event.keyCode;
1202 | var keyCodeChar = String.fromCharCode(keyCode);
1203 |
1204 | switch (keyCodeChar) {
1205 |
1206 | case "y":
1207 | undoObj.redo();
1208 | handled = true;
1209 | break;
1210 |
1211 | case "z":
1212 | if (!event.shiftKey) {
1213 | undoObj.undo();
1214 | }
1215 | else {
1216 | undoObj.redo();
1217 | }
1218 | handled = true;
1219 | break;
1220 | }
1221 | }
1222 |
1223 | if (handled) {
1224 | if (event.preventDefault) {
1225 | event.preventDefault();
1226 | }
1227 | if (window.event) {
1228 | window.event.returnValue = false;
1229 | }
1230 | return;
1231 | }
1232 | };
1233 |
1234 | // Set the mode depending on what is going on in the input area.
1235 | var handleModeChange = function (event) {
1236 |
1237 | if (!event.ctrlKey && !event.metaKey) {
1238 |
1239 | var keyCode = event.keyCode;
1240 |
1241 | if ((keyCode >= 33 && keyCode <= 40) || (keyCode >= 63232 && keyCode <= 63235)) {
1242 | // 33 - 40: page up/dn and arrow keys
1243 | // 63232 - 63235: page up/dn and arrow keys on safari
1244 | setMode("moving");
1245 | }
1246 | else if (keyCode == 8 || keyCode == 46 || keyCode == 127) {
1247 | // 8: backspace
1248 | // 46: delete
1249 | // 127: delete
1250 | setMode("deleting");
1251 | }
1252 | else if (keyCode == 13) {
1253 | // 13: Enter
1254 | setMode("newlines");
1255 | }
1256 | else if (keyCode == 27) {
1257 | // 27: escape
1258 | setMode("escape");
1259 | }
1260 | else if ((keyCode < 16 || keyCode > 20) && keyCode != 91) {
1261 | // 16-20 are shift, etc.
1262 | // 91: left window key
1263 | // I think this might be a little messed up since there are
1264 | // a lot of nonprinting keys above 20.
1265 | setMode("typing");
1266 | }
1267 | }
1268 | };
1269 |
1270 | var setEventHandlers = function () {
1271 |
1272 | util.addEvent(textarea, "keypress", function (event) {
1273 | // keyCode 89: y
1274 | // keyCode 90: z
1275 | if ((event.ctrlKey || event.metaKey) && (event.keyCode == 89 || event.keyCode == 90)) {
1276 | event.preventDefault();
1277 | }
1278 | });
1279 |
1280 | var handlePaste = function () {
1281 | if (browser.isIE || (inputStateObj && inputStateObj.text != textarea.value)) {
1282 | if (timer == undefined) {
1283 | mode = "paste";
1284 | saveState();
1285 | refreshState();
1286 | }
1287 | }
1288 | };
1289 |
1290 | poller = new InputPoller(textarea, handlePaste, pastePollInterval);
1291 |
1292 | util.addEvent(textarea, "keydown", handleCtrlYZ);
1293 | util.addEvent(textarea, "keydown", handleModeChange);
1294 |
1295 | util.addEvent(textarea, "mousedown", function () {
1296 | setMode("moving");
1297 | });
1298 | textarea.onpaste = handlePaste;
1299 | textarea.ondrop = handlePaste;
1300 | };
1301 |
1302 | var init = function () {
1303 | setEventHandlers();
1304 | refreshState();
1305 | saveState();
1306 | };
1307 |
1308 | this.destroy = function () {
1309 | if (poller) {
1310 | poller.destroy();
1311 | }
1312 | };
1313 |
1314 | init();
1315 | }; //}}}
1316 | WMDEditor.util = util;
1317 | WMDEditor.position = position;
1318 | WMDEditor.TextareaState = TextareaState;
1319 | WMDEditor.InputPoller = InputPoller;
1320 | WMDEditor.PreviewManager = PreviewManager;
1321 | WMDEditor.UndoManager = UndoManager;
1322 |
1323 | // A few handy aliases for readability.
1324 | var doc = window.document;
1325 | var re = window.RegExp;
1326 | var nav = window.navigator;
1327 |
1328 | function get_browser() {
1329 | var b = {};
1330 | b.isIE = /msie/.test(nav.userAgent.toLowerCase());
1331 | b.isIE_5or6 = /msie 6/.test(nav.userAgent.toLowerCase()) || /msie 5/.test(nav.userAgent.toLowerCase());
1332 | b.isIE_7plus = b.isIE && !b.isIE_5or6;
1333 | b.isOpera = /opera/.test(nav.userAgent.toLowerCase());
1334 | b.isKonqueror = /konqueror/.test(nav.userAgent.toLowerCase());
1335 | return b;
1336 | }
1337 |
1338 | // Used to work around some browser bugs where we can't use feature testing.
1339 | var browser = get_browser();
1340 |
1341 | var wmdBase = function (wmd, wmd_options) { // {{{
1342 | // Some namespaces.
1343 | //wmd.Util = {};
1344 | //wmd.Position = {};
1345 | wmd.Command = {};
1346 | wmd.Global = {};
1347 | wmd.buttons = {};
1348 |
1349 | wmd.showdown = window.Showdown;
1350 |
1351 | var util = WMDEditor.util;
1352 | var position = WMDEditor.position;
1353 | var command = wmd.Command;
1354 |
1355 | // Internet explorer has problems with CSS sprite buttons that use HTML
1356 | // lists. When you click on the background image "button", IE will
1357 | // select the non-existent link text and discard the selection in the
1358 | // textarea. The solution to this is to cache the textarea selection
1359 | // on the button's mousedown event and set a flag. In the part of the
1360 | // code where we need to grab the selection, we check for the flag
1361 | // and, if it's set, use the cached area instead of querying the
1362 | // textarea.
1363 | //
1364 | // This ONLY affects Internet Explorer (tested on versions 6, 7
1365 | // and 8) and ONLY on button clicks. Keyboard shortcuts work
1366 | // normally since the focus never leaves the textarea.
1367 | wmd.ieCachedRange = null; // cached textarea selection
1368 | wmd.ieRetardedClick = false; // flag
1369 | // I think my understanding of how the buttons and callbacks are stored in the array is incomplete.
1370 | wmd.editor = function (previewRefreshCallback) { // {{{
1371 | if (!previewRefreshCallback) {
1372 | previewRefreshCallback = function () {};
1373 | }
1374 |
1375 | var inputBox = wmd.panels.input;
1376 |
1377 | var offsetHeight = 0;
1378 |
1379 | var editObj = this;
1380 |
1381 | var mainDiv;
1382 | var mainSpan;
1383 |
1384 | var div; // This name is pretty ambiguous. I should rename this.
1385 | // Used to cancel recurring events from setInterval.
1386 | var creationHandle;
1387 |
1388 | var undoMgr; // The undo manager
1389 | // Perform the button's action.
1390 | var doClick = function (button) {
1391 |
1392 | inputBox.focus();
1393 |
1394 | if (button.textOp) {
1395 |
1396 | if (undoMgr) {
1397 | undoMgr.setCommandMode();
1398 | }
1399 |
1400 | var state = new TextareaState(wmd.panels.input, wmd);
1401 |
1402 | if (!state) {
1403 | return;
1404 | }
1405 |
1406 | var chunks = state.getChunks();
1407 |
1408 | // Some commands launch a "modal" prompt dialog. Javascript
1409 | // can't really make a modal dialog box and the WMD code
1410 | // will continue to execute while the dialog is displayed.
1411 | // This prevents the dialog pattern I'm used to and means
1412 | // I can't do something like this:
1413 | //
1414 | // var link = CreateLinkDialog();
1415 | // makeMarkdownLink(link);
1416 | //
1417 | // Instead of this straightforward method of handling a
1418 | // dialog I have to pass any code which would execute
1419 | // after the dialog is dismissed (e.g. link creation)
1420 | // in a function parameter.
1421 | //
1422 | // Yes this is awkward and I think it sucks, but there's
1423 | // no real workaround. Only the image and link code
1424 | // create dialogs and require the function pointers.
1425 | var fixupInputArea = function () {
1426 |
1427 | inputBox.focus();
1428 |
1429 | if (chunks) {
1430 | state.setChunks(chunks);
1431 | }
1432 |
1433 | state.restore();
1434 | previewRefreshCallback();
1435 | };
1436 |
1437 | var useDefaultText = true;
1438 | var noCleanup = button.textOp(chunks, fixupInputArea, useDefaultText);
1439 |
1440 | if (!noCleanup) {
1441 | fixupInputArea();
1442 | }
1443 |
1444 | }
1445 |
1446 | if (button.execute) {
1447 | button.execute(editObj);
1448 | }
1449 | };
1450 |
1451 | var setUndoRedoButtonStates = function () {
1452 | if (undoMgr) {
1453 | if (wmd.buttons["wmd-undo-button"]) setupButton(wmd.buttons["wmd-undo-button"], undoMgr.canUndo());
1454 | if (wmd.buttons["wmd-redo-button"]) setupButton(wmd.buttons["wmd-redo-button"], undoMgr.canRedo());
1455 | }
1456 | };
1457 |
1458 | var setupButton = function (button, isEnabled) {
1459 |
1460 | if (isEnabled) {
1461 | button.className = button.className.replace(new RegExp("(^|\\s+)disabled(\\s+|$)"), ' ');
1462 |
1463 | // IE tries to select the background image "button" text (it's
1464 | // implemented in a list item) so we have to cache the selection
1465 | // on mousedown.
1466 | if (browser.isIE) {
1467 | button.onmousedown = function () {
1468 | wmd.ieRetardedClick = true;
1469 | wmd.ieCachedRange = document.selection.createRange();
1470 | };
1471 | }
1472 |
1473 | if (!button.isHelp) {
1474 | button.onclick = function () {
1475 | if (this.onmouseout) {
1476 | this.onmouseout();
1477 | }
1478 | doClick(this);
1479 | return false;
1480 | };
1481 | }
1482 | }
1483 | else {
1484 | button.className += (button.className ? ' ' : '') + 'disabled';
1485 | button.onmouseover = button.onmouseout = button.onclick = function () {};
1486 | }
1487 | };
1488 |
1489 | var makeSpritedButtonRow = function () {
1490 |
1491 | var buttonBar = (typeof wmd_options.button_bar == 'string') ? document.getElementById(wmd_options.button_bar || "wmd-button-bar") : wmd_options.button_bar;
1492 |
1493 | var normalYShift = "0px";
1494 | var disabledYShift = "-20px";
1495 | var highlightYShift = "-40px";
1496 |
1497 | var buttonRow = document.createElement("ul");
1498 | buttonRow.className = "wmd-button-row";
1499 | buttonRow = buttonBar.appendChild(buttonRow);
1500 |
1501 | var xoffset = 0;
1502 |
1503 | function createButton(name, title, textOp) {
1504 | var button = document.createElement("li");
1505 | wmd.buttons[name] = button;
1506 | button.className = "wmd-button " + name;
1507 | button.XShift = xoffset + "px";
1508 | xoffset -= 20;
1509 |
1510 | if (title) button.title = title;
1511 |
1512 | if (textOp) button.textOp = textOp;
1513 |
1514 | return button;
1515 | }
1516 |
1517 | function addButton(name, title, textOp) {
1518 | var button = createButton(name, title, textOp);
1519 |
1520 | setupButton(button, true);
1521 | buttonRow.appendChild(button);
1522 | return button;
1523 | }
1524 |
1525 | function addSpacer() {
1526 | var spacer = document.createElement("li");
1527 | spacer.className = "wmd-spacer";
1528 | buttonRow.appendChild(spacer);
1529 | return spacer;
1530 | }
1531 |
1532 | // Detection of mac for displaying proper modifier key.
1533 | var modifierKey = (navigator.appVersion.indexOf("Mac")!=-1) ? "Cmd" : "Ctrl";
1534 |
1535 | var buttonlist = wmd_options.buttons.split(' ');
1536 | for (var i=0;i"+modifierKey+"+Q", command.doBlockquote); 1551 | break; 1552 | case 'code': 1553 | addButton("wmd-code-button", "Code Sample"+modifierKey+"+K", command.doCode); 1554 | break; 1555 | case 'image': 1556 | addButton("wmd-image-button", "Image"+modifierKey+"+G", function (chunk, postProcessing, useDefaultText) { 1557 | return command.doLinkOrImage(chunk, postProcessing, true); 1558 | }); 1559 | break; 1560 | case 'ol': 1561 | addButton("wmd-olist-button", "Numbered List
"+modifierKey+"+O", function (chunk, postProcessing, useDefaultText) { 1562 | command.doList(chunk, postProcessing, true, useDefaultText); 1563 | }); 1564 | break; 1565 | case 'ul': 1566 | addButton("wmd-ulist-button", "Bulleted List
"+modifierKey+"+U", function (chunk, postProcessing, useDefaultText) { 1567 | command.doList(chunk, postProcessing, false, useDefaultText); 1568 | }); 1569 | break; 1570 | case 'heading': 1571 | addButton("wmd-heading-button", "Heading
/
"+modifierKey+"+H", command.doHeading); 1572 | break; 1573 | case 'hr': 1574 | addButton("wmd-hr-button", "Horizontal Rule
"+modifierKey+"+R", command.doHorizontalRule); 1575 | break; 1576 | case 'undo': 1577 | var undoButton = addButton("wmd-undo-button", "Undo - "+modifierKey+"+Z"); 1578 | undoButton.execute = function (manager) { 1579 | manager.undo(); 1580 | }; 1581 | break; 1582 | case 'redo': 1583 | var redoButton = addButton("wmd-redo-button", "Redo - "+modifierKey+"+Y"); 1584 | if (/win/.test(nav.platform.toLowerCase())) { 1585 | redoButton.title = "Redo - "+modifierKey+"+Y"; 1586 | } 1587 | else { 1588 | // mac and other non-Windows platforms 1589 | redoButton.title = "Redo - "+modifierKey+"+Shift+Z"; 1590 | } 1591 | redoButton.execute = function (manager) { 1592 | manager.redo(); 1593 | }; 1594 | break; 1595 | case 'help': 1596 | var helpButton = createButton("wmd-help-button"); 1597 | helpButton.isHelp = true; 1598 | setupButton(helpButton, true); 1599 | buttonRow.appendChild(helpButton); 1600 | 1601 | var helpAnchor = document.createElement("a"); 1602 | helpAnchor.href = wmd_options.helpLink; 1603 | helpAnchor.target = wmd_options.helpTarget; 1604 | helpAnchor.title = wmd_options.helpHoverTitle; 1605 | helpButton.appendChild(helpAnchor); 1606 | break; 1607 | case '': 1608 | addSpacer(); 1609 | break; 1610 | } 1611 | } 1612 | 1613 | setUndoRedoButtonStates(); 1614 | }; 1615 | 1616 | var setupEditor = function () { 1617 | 1618 | if (/\?noundo/.test(document.location.href)) { 1619 | wmd.nativeUndo = true; 1620 | } 1621 | 1622 | if (!wmd.nativeUndo) { 1623 | undoMgr = new UndoManager(wmd, wmd.panels.input, wmd.options.pastePollInterval, function () { 1624 | previewRefreshCallback(); 1625 | setUndoRedoButtonStates(); 1626 | }); 1627 | } 1628 | 1629 | makeSpritedButtonRow(); 1630 | 1631 | 1632 | var keyEvent = "keydown"; 1633 | if (browser.isOpera) { 1634 | keyEvent = "keypress"; 1635 | } 1636 | 1637 | util.addEvent(inputBox, keyEvent, function (key) { 1638 | 1639 | // Check to see if we have a button key and, if so execute the callback. 1640 | if (wmd.options.modifierKeys && (key.ctrlKey || key.metaKey)) { 1641 | 1642 | var keyCode = key.charCode || key.keyCode; 1643 | var keyCodeStr = String.fromCharCode(keyCode).toLowerCase(); 1644 | 1645 | switch (keyCodeStr) { 1646 | case wmd.options.modifierKeys.bold: 1647 | if (wmd.buttons["wmd-bold-button"]) doClick(wmd.buttons["wmd-bold-button"]); 1648 | else return; 1649 | break; 1650 | case wmd.options.modifierKeys.italic: 1651 | if (wmd.buttons["wmd-italic-button"]) doClick(wmd.buttons["wmd-italic-button"]); 1652 | else return; 1653 | break; 1654 | case wmd.options.modifierKeys.link: 1655 | if (wmd.buttons["wmd-link-button"]) doClick(wmd.buttons["wmd-link-button"]); 1656 | else return; 1657 | break; 1658 | case wmd.options.modifierKeys.quote: 1659 | if (wmd.buttons["wmd-quote-button"]) doClick(wmd.buttons["wmd-quote-button"]); 1660 | else return; 1661 | break; 1662 | case wmd.options.modifierKeys.code: 1663 | if (wmd.buttons["wmd-code-button"]) doClick(wmd.buttons["wmd-code-button"]); 1664 | else return; 1665 | break; 1666 | case wmd.options.modifierKeys.image: 1667 | if (wmd.buttons["wmd-image-button"]) doClick(wmd.buttons["wmd-image-button"]); 1668 | else return; 1669 | break; 1670 | case wmd.options.modifierKeys.orderedList: 1671 | if (wmd.buttons["wmd-olist-button"]) doClick(wmd.buttons["wmd-olist-button"]); 1672 | else return; 1673 | break; 1674 | case wmd.options.modifierKeys.unorderedList: 1675 | if (wmd.buttons["wmd-ulist-button"]) doClick(wmd.buttons["wmd-ulist-button"]); 1676 | else return; 1677 | break; 1678 | case wmd.options.modifierKeys.heading: 1679 | if (wmd.buttons["wmd-heading-button"]) doClick(wmd.buttons["wmd-heading-button"]); 1680 | else return; 1681 | break; 1682 | case wmd.options.modifierKeys.horizontalRule: 1683 | if (wmd.buttons["wmd-hr-button"]) doClick(wmd.buttons["wmd-hr-button"]); 1684 | else return; 1685 | break; 1686 | case wmd.options.modifierKeys.redo: 1687 | if (wmd.buttons["wmd-redo-button"]) doClick(wmd.buttons["wmd-redo-button"]); 1688 | else return; 1689 | break; 1690 | case wmd.options.modifierKeys.undo: 1691 | if (key.shiftKey) { 1692 | if (wmd.buttons["wmd-redo-button"]) doClick(wmd.buttons["wmd-redo-button"]); 1693 | else return; 1694 | } else { 1695 | if (wmd.buttons["wmd-undo-button"]) doClick(wmd.buttons["wmd-undo-button"]); 1696 | else return; 1697 | } 1698 | break; 1699 | default: 1700 | return; 1701 | } 1702 | 1703 | 1704 | if (key.preventDefault) { 1705 | key.preventDefault(); 1706 | } 1707 | 1708 | if (window.event) { 1709 | window.event.returnValue = false; 1710 | } 1711 | } 1712 | }); 1713 | 1714 | // Auto-continue lists, code blocks and block quotes when 1715 | // the enter key is pressed. 1716 | util.addEvent(inputBox, "keyup", function (key) { 1717 | if (!key.shiftKey && !key.ctrlKey && !key.metaKey) { 1718 | var keyCode = key.charCode || key.keyCode; 1719 | // Key code 13 is Enter 1720 | if (keyCode === 13) { 1721 | fakeButton = {}; 1722 | fakeButton.textOp = command.doAutoindent; 1723 | doClick(fakeButton); 1724 | } 1725 | } 1726 | }); 1727 | 1728 | // Disable ESC clearing the input textarea on IE 1729 | if (browser.isIE) { 1730 | util.addEvent(inputBox, "keydown", function (key) { 1731 | var code = key.keyCode; 1732 | // Key code 27 is ESC 1733 | if (code === 27) { 1734 | return false; 1735 | } 1736 | }); 1737 | } 1738 | }; 1739 | 1740 | 1741 | this.undo = function () { 1742 | if (undoMgr) { 1743 | undoMgr.undo(); 1744 | } 1745 | }; 1746 | 1747 | this.redo = function () { 1748 | if (undoMgr) { 1749 | undoMgr.redo(); 1750 | } 1751 | }; 1752 | 1753 | // This is pretty useless. The setupEditor function contents 1754 | // should just be copied here. 1755 | var init = function () { 1756 | setupEditor(); 1757 | }; 1758 | 1759 | this.destroy = function () { 1760 | if (undoMgr) { 1761 | undoMgr.destroy(); 1762 | } 1763 | if (div.parentNode) { 1764 | div.parentNode.removeChild(div); 1765 | } 1766 | if (inputBox) { 1767 | inputBox.style.marginTop = ""; 1768 | } 1769 | window.clearInterval(creationHandle); 1770 | }; 1771 | 1772 | init(); 1773 | }; // }}} 1774 | // command {{{ 1775 | // The markdown symbols - 4 spaces = code, > = blockquote, etc. 1776 | command.prefixes = "(?:\\s{4,}|\\s*>|\\s*-\\s+|\\s*\\d+\\.|=|\\+|-|_|\\*|#|\\s*\\[[^\n]]+\\]:)"; 1777 | 1778 | // Remove markdown symbols from the chunk selection. 1779 | command.unwrap = function (chunk) { 1780 | var txt = new re("([^\\n])\\n(?!(\\n|" + command.prefixes + "))", "g"); 1781 | chunk.selection = chunk.selection.replace(txt, "$1 $2"); 1782 | }; 1783 | 1784 | command.wrap = function (chunk, len) { 1785 | command.unwrap(chunk); 1786 | var regex = new re("(.{1," + len + "})( +|$\\n?)", "gm"); 1787 | 1788 | chunk.selection = chunk.selection.replace(regex, function (line, marked) { 1789 | if (new re("^" + command.prefixes, "").test(line)) { 1790 | return line; 1791 | } 1792 | return marked + "\n"; 1793 | }); 1794 | 1795 | chunk.selection = chunk.selection.replace(/\s+$/, ""); 1796 | }; 1797 | 1798 | command.doBold = function (chunk, postProcessing, useDefaultText) { 1799 | return command.doBorI(chunk, 2, "strong text"); 1800 | }; 1801 | 1802 | command.doItalic = function (chunk, postProcessing, useDefaultText) { 1803 | return command.doBorI(chunk, 1, "emphasized text"); 1804 | }; 1805 | 1806 | // chunk: The selected region that will be enclosed with */** 1807 | // nStars: 1 for italics, 2 for bold 1808 | // insertText: If you just click the button without highlighting text, this gets inserted 1809 | command.doBorI = function (chunk, nStars, insertText) { 1810 | 1811 | // Get rid of whitespace and fixup newlines. 1812 | chunk.trimWhitespace(); 1813 | chunk.selection = chunk.selection.replace(/\n{2,}/g, "\n"); 1814 | 1815 | // Look for stars before and after. Is the chunk already marked up? 1816 | chunk.before.search(/(\**$)/); 1817 | var starsBefore = re.$1; 1818 | 1819 | chunk.after.search(/(^\**)/); 1820 | var starsAfter = re.$1; 1821 | 1822 | var prevStars = Math.min(starsBefore.length, starsAfter.length); 1823 | 1824 | // Remove stars if we have to since the button acts as a toggle. 1825 | if ((prevStars >= nStars) && (prevStars != 2 || nStars != 1)) { 1826 | chunk.before = chunk.before.replace(re("[*]{" + nStars + "}$", ""), ""); 1827 | chunk.after = chunk.after.replace(re("^[*]{" + nStars + "}", ""), ""); 1828 | } 1829 | else if (!chunk.selection && starsAfter) { 1830 | // It's not really clear why this code is necessary. It just moves 1831 | // some arbitrary stuff around. 1832 | chunk.after = chunk.after.replace(/^([*_]*)/, ""); 1833 | chunk.before = chunk.before.replace(/(\s?)$/, ""); 1834 | var whitespace = re.$1; 1835 | chunk.before = chunk.before + starsAfter + whitespace; 1836 | } 1837 | else { 1838 | 1839 | // In most cases, if you don't have any selected text and click the button 1840 | // you'll get a selected, marked up region with the default text inserted. 1841 | if (!chunk.selection && !starsAfter) { 1842 | chunk.selection = insertText; 1843 | } 1844 | 1845 | // Add the true markup. 1846 | var markup = nStars <= 1 ? "*" : "**"; // shouldn't the test be = ? 1847 | chunk.before = chunk.before + markup; 1848 | chunk.after = markup + chunk.after; 1849 | } 1850 | 1851 | return; 1852 | }; 1853 | 1854 | command.stripLinkDefs = function (text, defsToAdd) { 1855 | 1856 | text = text.replace(/^[ ]{0,3}\[(\d+)\]:[ \t]*\n?[ \t]*(\S+?)>?[ \t]*\n?[ \t]*(?:(\n*)["(](.+?)[")][ \t]*)?(?:\n+|$)/gm, function (totalMatch, id, link, newlines, title) { 1857 | defsToAdd[id] = totalMatch.replace(/\s*$/, ""); 1858 | if (newlines) { 1859 | // Strip the title and return that separately. 1860 | defsToAdd[id] = totalMatch.replace(/["(](.+?)[")]$/, ""); 1861 | return newlines + title; 1862 | } 1863 | return ""; 1864 | }); 1865 | 1866 | return text; 1867 | }; 1868 | 1869 | command.addLinkDef = function (chunk, linkDef) { 1870 | 1871 | var refNumber = 0; // The current reference number 1872 | var defsToAdd = {}; // 1873 | // Start with a clean slate by removing all previous link definitions. 1874 | chunk.before = command.stripLinkDefs(chunk.before, defsToAdd); 1875 | chunk.selection = command.stripLinkDefs(chunk.selection, defsToAdd); 1876 | chunk.after = command.stripLinkDefs(chunk.after, defsToAdd); 1877 | 1878 | var defs = ""; 1879 | var regex = /(\[(?:\[[^\]]*\]|[^\[\]])*\][ ]?(?:\n[ ]*)?\[)(\d+)(\])/g; 1880 | 1881 | var addDefNumber = function (def) { 1882 | refNumber++; 1883 | def = def.replace(/^[ ]{0,3}\[(\d+)\]:/, " [" + refNumber + "]:"); 1884 | defs += "\n" + def; 1885 | }; 1886 | 1887 | var getLink = function (wholeMatch, link, id, end) { 1888 | 1889 | if (defsToAdd[id]) { 1890 | addDefNumber(defsToAdd[id]); 1891 | return link + refNumber + end; 1892 | 1893 | } 1894 | return wholeMatch; 1895 | }; 1896 | 1897 | chunk.before = chunk.before.replace(regex, getLink); 1898 | 1899 | if (linkDef) { 1900 | addDefNumber(linkDef); 1901 | } 1902 | else { 1903 | chunk.selection = chunk.selection.replace(regex, getLink); 1904 | } 1905 | 1906 | var refOut = refNumber; 1907 | 1908 | chunk.after = chunk.after.replace(regex, getLink); 1909 | 1910 | if (chunk.after) { 1911 | chunk.after = chunk.after.replace(/\n*$/, ""); 1912 | } 1913 | if (!chunk.after) { 1914 | chunk.selection = chunk.selection.replace(/\n*$/, ""); 1915 | } 1916 | 1917 | chunk.after += "\n\n" + defs; 1918 | 1919 | return refOut; 1920 | }; 1921 | 1922 | command.doLinkOrImage = function (chunk, postProcessing, isImage) { 1923 | 1924 | chunk.trimWhitespace(); 1925 | chunk.findTags(/\s*!?\[/, /\][ ]?(?:\n[ ]*)?(\[.*?\])?/); 1926 | 1927 | if (chunk.endTag.length > 1) { 1928 | 1929 | chunk.startTag = chunk.startTag.replace(/!?\[/, ""); 1930 | chunk.endTag = ""; 1931 | command.addLinkDef(chunk, null); 1932 | 1933 | } 1934 | else { 1935 | 1936 | if (/\n\n/.test(chunk.selection)) { 1937 | command.addLinkDef(chunk, null); 1938 | return; 1939 | } 1940 | 1941 | // The function to be executed when you enter a link and press OK or Cancel. 1942 | // Marks up the link and adds the ref. 1943 | var makeLinkMarkdown = function (link) { 1944 | console.log(link); 1945 | if (link !== null) { 1946 | 1947 | chunk.startTag = chunk.endTag = ""; 1948 | var linkDef = " [999]: " + link; 1949 | 1950 | var num = command.addLinkDef(chunk, linkDef); 1951 | chunk.startTag = isImage ? "![" : "["; 1952 | chunk.endTag = "][" + num + "]"; 1953 | 1954 | if (!chunk.selection) { 1955 | if (isImage) { 1956 | chunk.selection = "alt text"; 1957 | } 1958 | else { 1959 | chunk.selection = "link text"; 1960 | } 1961 | } 1962 | } 1963 | postProcessing(); 1964 | }; 1965 | 1966 | if (isImage) { 1967 | util.prompt(wmd_options.imageDialogText, wmd_options.imageDefaultText, makeLinkMarkdown, 'Image'); 1968 | } 1969 | else { 1970 | util.prompt(wmd_options.linkDialogText, wmd_options.linkDefaultText, makeLinkMarkdown, 'Link'); 1971 | } 1972 | return true; 1973 | } 1974 | }; 1975 | 1976 | // Moves the cursor to the next line and continues lists, quotes and code. 1977 | command.doAutoindent = function (chunk, postProcessing, useDefaultText) { 1978 | if (!wmd.options.autoFormatting) return; 1979 | 1980 | if (wmd.options.autoFormatting.list) chunk.before = chunk.before.replace(/(\n|^)[ ]{0,3}([*+-]|\d+[.])[ \t]*\n$/, "\n\n"); 1981 | if (wmd.options.autoFormatting.quote) chunk.before = chunk.before.replace(/(\n|^)[ ]{0,3}>[ \t]*\n$/, "\n\n"); 1982 | if (wmd.options.autoFormatting.code) chunk.before = chunk.before.replace(/(\n|^)[ \t]+\n$/, "\n\n"); 1983 | 1984 | useDefaultText = false; 1985 | 1986 | if (/(\n|^)[ ]{0,3}([*+-])[ \t]+.*\n$/.test(chunk.before)) { 1987 | if (command.doList && wmd.options.autoFormatting.list) { 1988 | command.doList(chunk, postProcessing, false, true); 1989 | } 1990 | } 1991 | if (/(\n|^)[ ]{0,3}(\d+[.])[ \t]+.*\n$/.test(chunk.before)) { 1992 | if (command.doList && wmd.options.autoFormatting.list) { 1993 | command.doList(chunk, postProcessing, true, true); 1994 | } 1995 | } 1996 | if (/(\n|^)[ ]{0,3}>[ \t]+.*\n$/.test(chunk.before)) { 1997 | if (command.doBlockquote && wmd.options.autoFormatting.quote) { 1998 | command.doBlockquote(chunk, postProcessing, useDefaultText); 1999 | } 2000 | } 2001 | if (/(\n|^)(\t|[ ]{4,}).*\n$/.test(chunk.before)) { 2002 | if (command.doCode && wmd.options.autoFormatting.code) { 2003 | command.doCode(chunk, postProcessing, useDefaultText); 2004 | } 2005 | } 2006 | }; 2007 | 2008 | command.doBlockquote = function (chunk, postProcessing, useDefaultText) { 2009 | 2010 | chunk.selection = chunk.selection.replace(/^(\n*)([^\r]+?)(\n*)$/, function (totalMatch, newlinesBefore, text, newlinesAfter) { 2011 | chunk.before += newlinesBefore; 2012 | chunk.after = newlinesAfter + chunk.after; 2013 | return text; 2014 | }); 2015 | 2016 | chunk.before = chunk.before.replace(/(>[ \t]*)$/, function (totalMatch, blankLine) { 2017 | chunk.selection = blankLine + chunk.selection; 2018 | return ""; 2019 | }); 2020 | 2021 | var defaultText = useDefaultText ? "Blockquote" : ""; 2022 | chunk.selection = chunk.selection.replace(/^(\s|>)+$/, ""); 2023 | chunk.selection = chunk.selection || defaultText; 2024 | 2025 | if (chunk.before) { 2026 | chunk.before = chunk.before.replace(/\n?$/, "\n"); 2027 | } 2028 | if (chunk.after) { 2029 | chunk.after = chunk.after.replace(/^\n?/, "\n"); 2030 | } 2031 | 2032 | chunk.before = chunk.before.replace(/(((\n|^)(\n[ \t]*)*>(.+\n)*.*)+(\n[ \t]*)*$)/, function (totalMatch) { 2033 | chunk.startTag = totalMatch; 2034 | return ""; 2035 | }); 2036 | 2037 | chunk.after = chunk.after.replace(/^(((\n|^)(\n[ \t]*)*>(.+\n)*.*)+(\n[ \t]*)*)/, function (totalMatch) { 2038 | chunk.endTag = totalMatch; 2039 | return ""; 2040 | }); 2041 | 2042 | var replaceBlanksInTags = function (useBracket) { 2043 | 2044 | var replacement = useBracket ? "> " : ""; 2045 | 2046 | if (chunk.startTag) { 2047 | chunk.startTag = chunk.startTag.replace(/\n((>|\s)*)\n$/, function (totalMatch, markdown) { 2048 | return "\n" + markdown.replace(/^[ ]{0,3}>?[ \t]*$/gm, replacement) + "\n"; 2049 | }); 2050 | } 2051 | if (chunk.endTag) { 2052 | chunk.endTag = chunk.endTag.replace(/^\n((>|\s)*)\n/, function (totalMatch, markdown) { 2053 | return "\n" + markdown.replace(/^[ ]{0,3}>?[ \t]*$/gm, replacement) + "\n"; 2054 | }); 2055 | } 2056 | }; 2057 | 2058 | if (/^(?![ ]{0,3}>)/m.test(chunk.selection)) { 2059 | command.wrap(chunk, wmd_options.lineLength - 2); 2060 | chunk.selection = chunk.selection.replace(/^/gm, "> "); 2061 | replaceBlanksInTags(true); 2062 | chunk.addBlankLines(); 2063 | } 2064 | else { 2065 | chunk.selection = chunk.selection.replace(/^[ ]{0,3}> ?/gm, ""); 2066 | command.unwrap(chunk); 2067 | replaceBlanksInTags(false); 2068 | 2069 | if (!/^(\n|^)[ ]{0,3}>/.test(chunk.selection) && chunk.startTag) { 2070 | chunk.startTag = chunk.startTag.replace(/\n{0,2}$/, "\n\n"); 2071 | } 2072 | 2073 | if (!/(\n|^)[ ]{0,3}>.*$/.test(chunk.selection) && chunk.endTag) { 2074 | chunk.endTag = chunk.endTag.replace(/^\n{0,2}/, "\n\n"); 2075 | } 2076 | } 2077 | 2078 | if (!/\n/.test(chunk.selection)) { 2079 | chunk.selection = chunk.selection.replace(/^(> *)/, function (wholeMatch, blanks) { 2080 | chunk.startTag += blanks; 2081 | return ""; 2082 | }); 2083 | } 2084 | }; 2085 | 2086 | command.doCode = function (chunk, postProcessing, useDefaultText) { 2087 | 2088 | var hasTextBefore = /\S[ ]*$/.test(chunk.before); 2089 | var hasTextAfter = /^[ ]*\S/.test(chunk.after); 2090 | 2091 | // Use 'four space' markdown if the selection is on its own 2092 | // line or is multiline. 2093 | if ((!hasTextAfter && !hasTextBefore) || /\n/.test(chunk.selection)) { 2094 | 2095 | chunk.before = chunk.before.replace(/[ ]{4}$/, function (totalMatch) { 2096 | chunk.selection = totalMatch + chunk.selection; 2097 | return ""; 2098 | }); 2099 | 2100 | var nLinesBefore = 1; 2101 | var nLinesAfter = 1; 2102 | 2103 | 2104 | if (/\n(\t|[ ]{4,}).*\n$/.test(chunk.before) || chunk.after === "") { 2105 | nLinesBefore = 0; 2106 | } 2107 | if (/^\n(\t|[ ]{4,})/.test(chunk.after)) { 2108 | nLinesAfter = 0; // This needs to happen on line 1 2109 | } 2110 | 2111 | chunk.addBlankLines(nLinesBefore, nLinesAfter); 2112 | 2113 | if (!chunk.selection) { 2114 | chunk.startTag = " "; 2115 | chunk.selection = useDefaultText ? "enter code here" : ""; 2116 | } 2117 | else { 2118 | if (/^[ ]{0,3}\S/m.test(chunk.selection)) { 2119 | chunk.selection = chunk.selection.replace(/^/gm, " "); 2120 | } 2121 | else { 2122 | chunk.selection = chunk.selection.replace(/^[ ]{4}/gm, ""); 2123 | } 2124 | } 2125 | } 2126 | else { 2127 | // Use backticks (`) to delimit the code block. 2128 | chunk.trimWhitespace(); 2129 | chunk.findTags(/`/, /`/); 2130 | 2131 | if (!chunk.startTag && !chunk.endTag) { 2132 | chunk.startTag = chunk.endTag = "`"; 2133 | if (!chunk.selection) { 2134 | chunk.selection = useDefaultText ? "enter code here" : ""; 2135 | } 2136 | } 2137 | else if (chunk.endTag && !chunk.startTag) { 2138 | chunk.before += chunk.endTag; 2139 | chunk.endTag = ""; 2140 | } 2141 | else { 2142 | chunk.startTag = chunk.endTag = ""; 2143 | } 2144 | } 2145 | }; 2146 | 2147 | command.doList = function (chunk, postProcessing, isNumberedList, useDefaultText) { 2148 | 2149 | // These are identical except at the very beginning and end. 2150 | // Should probably use the regex extension function to make this clearer. 2151 | var previousItemsRegex = /(\n|^)(([ ]{0,3}([*+-]|\d+[.])[ \t]+.*)(\n.+|\n{2,}([*+-].*|\d+[.])[ \t]+.*|\n{2,}[ \t]+\S.*)*)\n*$/; 2152 | var nextItemsRegex = /^\n*(([ ]{0,3}([*+-]|\d+[.])[ \t]+.*)(\n.+|\n{2,}([*+-].*|\d+[.])[ \t]+.*|\n{2,}[ \t]+\S.*)*)\n*/; 2153 | 2154 | // The default bullet is a dash but others are possible. 2155 | // This has nothing to do with the particular HTML bullet, 2156 | // it's just a markdown bullet. 2157 | var bullet = "-"; 2158 | 2159 | // The number in a numbered list. 2160 | var num = 1; 2161 | 2162 | // Get the item prefix - e.g. " 1. " for a numbered list, " - " for a bulleted list. 2163 | var getItemPrefix = function () { 2164 | var prefix; 2165 | if (isNumberedList) { 2166 | prefix = " " + num + ". "; 2167 | num++; 2168 | } 2169 | else { 2170 | prefix = " " + bullet + " "; 2171 | } 2172 | return prefix; 2173 | }; 2174 | 2175 | // Fixes the prefixes of the other list items. 2176 | var getPrefixedItem = function (itemText) { 2177 | 2178 | // The numbering flag is unset when called by autoindent. 2179 | if (isNumberedList === undefined) { 2180 | isNumberedList = /^\s*\d/.test(itemText); 2181 | } 2182 | 2183 | // Renumber/bullet the list element. 2184 | itemText = itemText.replace(/^[ ]{0,3}([*+-]|\d+[.])\s/gm, function (_) { 2185 | return getItemPrefix(); 2186 | }); 2187 | 2188 | return itemText; 2189 | }; 2190 | 2191 | chunk.findTags(/(\n|^)*[ ]{0,3}([*+-]|\d+[.])\s+/, null); 2192 | 2193 | if (chunk.before && !/\n$/.test(chunk.before) && !/^\n/.test(chunk.startTag)) { 2194 | chunk.before += chunk.startTag; 2195 | chunk.startTag = ""; 2196 | } 2197 | 2198 | if (chunk.startTag) { 2199 | 2200 | var hasDigits = /\d+[.]/.test(chunk.startTag); 2201 | chunk.startTag = ""; 2202 | chunk.selection = chunk.selection.replace(/\n[ ]{4}/g, "\n"); 2203 | command.unwrap(chunk); 2204 | chunk.addBlankLines(); 2205 | 2206 | if (hasDigits) { 2207 | // Have to renumber the bullet points if this is a numbered list. 2208 | chunk.after = chunk.after.replace(nextItemsRegex, getPrefixedItem); 2209 | } 2210 | if (isNumberedList == hasDigits) { 2211 | return; 2212 | } 2213 | } 2214 | 2215 | var nLinesBefore = 1; 2216 | 2217 | chunk.before = chunk.before.replace(previousItemsRegex, function (itemText) { 2218 | if (/^\s*([*+-])/.test(itemText)) { 2219 | bullet = re.$1; 2220 | } 2221 | nLinesBefore = /[^\n]\n\n[^\n]/.test(itemText) ? 1 : 0; 2222 | return getPrefixedItem(itemText); 2223 | }); 2224 | 2225 | if (!chunk.selection) { 2226 | chunk.selection = useDefaultText ? "List item" : " "; 2227 | } 2228 | 2229 | var prefix = getItemPrefix(); 2230 | 2231 | var nLinesAfter = 1; 2232 | 2233 | chunk.after = chunk.after.replace(nextItemsRegex, function (itemText) { 2234 | nLinesAfter = /[^\n]\n\n[^\n]/.test(itemText) ? 1 : 0; 2235 | return getPrefixedItem(itemText); 2236 | }); 2237 | 2238 | chunk.trimWhitespace(true); 2239 | chunk.addBlankLines(nLinesBefore, nLinesAfter, true); 2240 | chunk.startTag = prefix; 2241 | var spaces = prefix.replace(/./g, " "); 2242 | command.wrap(chunk, wmd_options.lineLength - spaces.length); 2243 | chunk.selection = chunk.selection.replace(/\n/g, "\n" + spaces); 2244 | 2245 | }; 2246 | 2247 | command.doHeading = function (chunk, postProcessing, useDefaultText) { 2248 | 2249 | // Remove leading/trailing whitespace and reduce internal spaces to single spaces. 2250 | chunk.selection = chunk.selection.replace(/\s+/g, " "); 2251 | chunk.selection = chunk.selection.replace(/(^\s+|\s+$)/g, ""); 2252 | 2253 | // If we clicked the button with no selected text, we just 2254 | // make a level 2 hash header around some default text. 2255 | if (!chunk.selection) { 2256 | chunk.startTag = "## "; 2257 | chunk.selection = "Heading"; 2258 | chunk.endTag = " ##"; 2259 | return; 2260 | } 2261 | 2262 | var headerLevel = 0; // The existing header level of the selected text. 2263 | // Remove any existing hash heading markdown and save the header level. 2264 | chunk.findTags(/#+[ ]*/, /[ ]*#+/); 2265 | if (/#+/.test(chunk.startTag)) { 2266 | headerLevel = re.lastMatch.length; 2267 | } 2268 | chunk.startTag = chunk.endTag = ""; 2269 | 2270 | // Try to get the current header level by looking for - and = in the line 2271 | // below the selection. 2272 | chunk.findTags(null, /\s?(-+|=+)/); 2273 | if (/=+/.test(chunk.endTag)) { 2274 | headerLevel = 1; 2275 | } 2276 | if (/-+/.test(chunk.endTag)) { 2277 | headerLevel = 2; 2278 | } 2279 | 2280 | // Skip to the next line so we can create the header markdown. 2281 | chunk.startTag = chunk.endTag = ""; 2282 | chunk.addBlankLines(1, 1); 2283 | 2284 | // We make a level 2 header if there is no current header. 2285 | // If there is a header level, we substract one from the header level. 2286 | // If it's already a level 1 header, it's removed. 2287 | var headerLevelToCreate = headerLevel == 0 ? 2 : headerLevel - 1; 2288 | 2289 | if (headerLevelToCreate > 0) { 2290 | 2291 | // The button only creates level 1 and 2 underline headers. 2292 | // Why not have it iterate over hash header levels? Wouldn't that be easier and cleaner? 2293 | var headerChar = headerLevelToCreate >= 2 ? "-" : "="; 2294 | var len = chunk.selection.length; 2295 | if (len > wmd_options.lineLength) { 2296 | len = wmd_options.lineLength; 2297 | } 2298 | chunk.endTag = "\n"; 2299 | while (len--) { 2300 | chunk.endTag += headerChar; 2301 | } 2302 | } 2303 | }; 2304 | 2305 | command.doHorizontalRule = function (chunk, postProcessing, useDefaultText) { 2306 | chunk.startTag = "----------\n"; 2307 | chunk.selection = ""; 2308 | chunk.addBlankLines(2, 1, true); 2309 | }; 2310 | // }}} 2311 | }; // }}} 2312 | })(); 2313 | 2314 | // For backward compatibility 2315 | 2316 | function setup_wmd(options) { 2317 | return new WMDEditor(options); 2318 | } --------------------------------------------------------------------------------