├── .gitignore
├── LICENSE
├── README.md
├── project.clj
├── resources
├── core.css
├── index.dev.html
├── index.html
└── marked.js
└── src
└── wordsmith
├── core.cljs
└── persistence.cljs
/.gitignore:
--------------------------------------------------------------------------------
1 | pom.xml
2 | *jar
3 | /lib/
4 | /classes/
5 | /out/
6 | /target/
7 | .lein-deps-sum
8 | .lein-repl-history
9 | .lein-plugins/
10 | wordsmith.js
11 | .nrepl-port
12 | /node_modules/
13 | /resources/main.js
14 | /resources/main.dev.js
15 | /resources/dev/
16 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Johanna Larsson
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # wordsmith
2 |
3 | A sample ClojureScript + om application for markdown editing with live preview and localStorage persistence.
4 |
5 | Running it:
6 |
7 | ~~~
8 | lein cljsbuild once release
9 | ~~~
10 |
11 | Once compilation has finished, open the index.html file in your browser.
12 |
13 | [live]: http://wordsmith.variadic.me/
14 |
--------------------------------------------------------------------------------
/project.clj:
--------------------------------------------------------------------------------
1 | (defproject wordsmith "0.1.0"
2 | :description "A markdown editor with live preview and localStorage
3 | saving. Built using ClojureScript and Om."
4 | :url "https://github.com/yuhama/wordsmith"
5 |
6 | :dependencies [[org.clojure/clojure "1.5.1"]
7 | [org.clojure/clojurescript "0.0-2173"]
8 | [org.clojure/core.async "0.1.267.0-0d7780-alpha"]
9 | [om "0.6.2"]]
10 |
11 | :plugins [[lein-cljsbuild "1.0.2"]]
12 |
13 | :source-paths ["src"]
14 |
15 | :cljsbuild {
16 | :builds [{:id "release"
17 | :source-paths ["src"]
18 | :compiler {
19 | :output-to "resources/main.js"
20 | :optimizations :advanced
21 | :pretty-print false
22 | :preamble ["react/react.min.js"]
23 | :externs ["react/externs/react.js"
24 | "marked.js"]
25 | :closure-warnings {:externs-validation :off}}}
26 | {:id "dev"
27 | :source-paths ["src"]
28 | :compiler {
29 | :output-to "resources/main.dev.js"
30 | :output-dir "resources/dev"
31 | :optimizations :none}}]})
32 |
--------------------------------------------------------------------------------
/resources/core.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: #767;
3 | }
4 |
5 | .container {
6 | height:95%;
7 | overflow: hidden;
8 | padding:0 10px;
9 | }
10 |
11 | #left-menu {
12 | width: 20%;
13 | background-color: #a9a;
14 | float:left;
15 | padding:20px 10px;
16 | clear:both;
17 | min-height:90%;
18 | color:#eee;
19 | box-sizing:border-box;
20 | -webkit-box-sizing: border-box;
21 | -moz-box-sizing:border-box;
22 | }
23 |
24 | #left-menu ul {
25 | list-style: none;
26 | padding: 0;
27 | margin: 0;
28 | font-size: 16px;
29 | font-family: monospace;
30 | }
31 |
32 | #left-menu li {
33 | padding:5px;
34 | overflow: hidden;
35 | }
36 |
37 | #left-menu li span {
38 | display:block;
39 | float:left;
40 | }
41 |
42 | .left-menu-title {
43 | cursor: pointer;
44 | word-wrap:break-word;
45 | width:80%;
46 | vertical-align: top;
47 | }
48 |
49 | .delete-button {
50 | padding:0 5px;
51 | cursor: pointer;
52 | margin-right:5px;
53 | vertical-align: top;
54 | }
55 |
56 | #input-area {
57 | font-family:Consolas,monospace;
58 | width:40%;
59 | height:90%;
60 | background-color: #bab;
61 | float:left;
62 | color:white;
63 | border:0;
64 | line-height: 18px;
65 | font-size:14px;
66 | padding:20px;
67 | margin:0;
68 | outline:none;
69 | resize:none;
70 | box-sizing:border-box;
71 | -webkit-box-sizing: border-box;
72 | -moz-box-sizing:border-box;
73 | }
74 |
75 | #output-area {
76 | width:40%;
77 | height:90%;
78 | background-color: #a9a;
79 | float:left;
80 | color:white;
81 | border:0;
82 | font-size:16px;
83 | padding:20px;
84 | border:0;
85 | font-family:Georgia,serif;
86 | box-sizing:border-box;
87 | -webkit-box-sizing: border-box;
88 | -moz-box-sizing:border-box;
89 | overflow-y: scroll;
90 | word-wrap:break-word;
91 | }
92 |
93 | code,pre {
94 | width:100%;
95 | overflow: scroll;
96 | font-size:14px;
97 | }
98 |
99 | #title-field input {
100 | border:none;
101 | border-bottom:1px solid #ccc;
102 | line-height:20px;
103 | margin:10px 0;
104 | padding:5px;
105 | font-size:20px;
106 | float:left;
107 | color:#ddd;
108 | background-color:#767;
109 | width:40%;
110 | outline:none;
111 | }
112 |
113 | #title-field input:focus {
114 | background-color:#eee;
115 | color:#666;
116 | }
117 |
118 | button {
119 | color:#767;
120 | display:block;
121 | font-family: monospace;
122 | font-size: 20px;
123 | width:100px;
124 | height:30px;
125 | margin-top:10px;
126 | background-color: #eee;
127 | border:1px solid #ccc;
128 | box-sizing:border-box;
129 | -webkit-box-sizing: border-box;
130 | -moz-box-sizing:border-box;
131 | }
132 |
133 | #new-document {
134 | float:right;
135 | }
136 |
137 | #save-button {
138 | float:right;
139 | margin-right:10px;
140 | }
141 |
142 | #save-button.disabled {
143 | background-color: #767;
144 | color: #ccc;
145 | border:1px solid #ccc;
146 | }
147 |
148 | #last-saved {
149 | float:right;
150 | display:block;
151 | font-size:12px;
152 | padding:10px;
153 | margin-top:12px;
154 | color:black;
155 | }
156 |
157 | #footer {
158 | font-size:14px;
159 | text-align:center;
160 | color:#ccc;
161 | font-family:monospace;
162 | padding:10px;
163 | }
164 |
165 | #footer a {
166 | color:#aaa;
167 | }
168 |
169 | h1 {
170 | margin:20px 0 10px 0;
171 | }
172 |
173 | h2 {
174 | margin:15px 0 5px 0;
175 | }
176 |
177 | h3 {
178 | margin:15px 0 5px 0;
179 | }
180 |
181 | h1, h2, h3, h4, h5, h6 {
182 | font-weight:normal;
183 | }
184 |
185 | h1:first-of-type {
186 | margin-top:0;
187 | }
188 |
189 | a {
190 | color:#eee;
191 | }
192 |
193 | p {
194 | margin 15px 0;
195 | }
196 |
197 | h1 + p, h2 + p, h3 + p, h4 + p, h5 + p, h6 + p,
198 | h1 + ul, h2 + ul, h3 + ul, h4 + ul, h5 + ul, h6 + ul,
199 | h1 + ol, h2 + ol, h3 + ol, h4 + ol, h5 + ol, h6 + ol {
200 | margin-top: 0;
201 | }
202 |
203 | code, pre {
204 | white-space: pre-wrap;
205 | }
206 |
207 | hr {
208 | border: 0px solid #eee;
209 | border-bottom: 2px solid #eee;
210 | width: 75%;
211 | margin: 30px auto;
212 | }
213 |
214 | table {
215 | color:#fff;
216 | margin-left:10px;
217 | border-collapse:collapse;
218 | }
219 |
220 | td, th {
221 | border:1px solid #eee;
222 | padding:5px;
223 | }
224 |
--------------------------------------------------------------------------------
/resources/index.dev.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
11 |
12 | # Markdown Basics
13 |
14 | This is a cheatsheet of Github Flavored Markdown.
15 |
16 | *To get started, feel free to overwrite this with your own document, or click __new__ in the top right corner.*
17 |
18 | ## Formatting
19 |
20 | ### Paragraphs
21 |
22 | A paragraph is any "regular" text block with blank lines before and after.
23 |
24 | Paragraphs can have `inline code`, _italics_, __bold__ and ~~strike through~~. It also supports , named [hyperlinks](http://example.com) and simple hyperlinks http://example.com.
25 |
26 | ### Quotes
27 |
28 | > Markdown also has quoted text blocks
29 | > that make pretty blockquotes.
30 |
31 | ### Unordered lists
32 |
33 | * Milk
34 | * Eggs
35 |
36 | ### Ordered lists
37 |
38 | 1. Peanut butter
39 | 2. Jelly
40 |
41 | ### Code blocks
42 |
43 | ~~~
44 | fib 0 = 0
45 | fib 1 = 1
46 | fib n = fib (n-1) + fib (n-2)
47 | ~~~
48 |
49 | ### Horizontal rules
50 |
51 | --------
52 |
53 | ### Tables
54 |
55 | First Header | Second Header
56 | ------------- | -------------
57 | Content Cell | Content Cell
58 | Content Cell | Content Cell
59 |
60 | ## Credits
61 |
62 | Markdown was thought up and originally specified by [John Gruber][gruber]. This editor uses a dialect of Markdown, known as [Github Flavored Markdown][gfm].
63 |
64 | [gruber]: http://daringfireball.net/projects/markdown/
65 | [gfm]: http://github.github.com/github-flavored-markdown/
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/resources/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
11 |
12 | # Markdown Basics
13 |
14 | This is a cheatsheet of Github Flavored Markdown.
15 |
16 | *To get started, feel free to overwrite this with your own document, or click __new__ in the top right corner.*
17 |
18 | ## Formatting
19 |
20 | ### Paragraphs
21 |
22 | A paragraph is any "regular" text block with blank lines before and after.
23 |
24 | Paragraphs can have `inline code`, _italics_, __bold__ and ~~strike through~~. It also supports , named [hyperlinks](http://example.com) and simple hyperlinks http://example.com.
25 |
26 | ### Quotes
27 |
28 | > Markdown also has quoted text blocks
29 | > that make pretty blockquotes.
30 |
31 | ### Unordered lists
32 |
33 | * Milk
34 | * Eggs
35 |
36 | ### Ordered lists
37 |
38 | 1. Peanut butter
39 | 2. Jelly
40 |
41 | ### Code blocks
42 |
43 | ~~~
44 | fib 0 = 0
45 | fib 1 = 1
46 | fib n = fib (n-1) + fib (n-2)
47 | ~~~
48 |
49 | ### Horizontal rules
50 |
51 | --------
52 |
53 | ### Tables
54 |
55 | First Header | Second Header
56 | ------------- | -------------
57 | Content Cell | Content Cell
58 | Content Cell | Content Cell
59 |
60 | ## Credits
61 |
62 | Markdown was thought up and originally specified by [John Gruber][gruber]. This editor uses a dialect of Markdown, known as [Github Flavored Markdown][gfm].
63 |
64 | [gruber]: http://daringfireball.net/projects/markdown/
65 | [gfm]: http://github.github.com/github-flavored-markdown/
66 |
67 |
68 |
69 |
70 |
71 |
--------------------------------------------------------------------------------
/resources/marked.js:
--------------------------------------------------------------------------------
1 | /**
2 | * marked - a markdown parser
3 | * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
4 | * https://github.com/chjj/marked
5 | */
6 | (function(){var block={newline:/^\n+/,code:/^( {4}[^\n]+\n*)+/,fences:noop,hr:/^( *[-*_]){3,} *(?:\n+|$)/,heading:/^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,nptable:noop,lheading:/^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,blockquote:/^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,list:/^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:/^ *(?:comment|closed|closing) *(?:\n{2,}|\s*$)/,def:/^ *\[([^\]]+)\]: *([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,table:noop,paragraph:/^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,text:/^[^\n]+/};block.bullet=/(?:[*+-]|\d+\.)/;block.item=/^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;block.item=replace(block.item,"gm")(/bull/g,block.bullet)();block.list=replace(block.list)(/bull/g,block.bullet)("hr","\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))")("def","\\n+(?="+block.def.source+")")();block.blockquote=replace(block.blockquote)("def",block.def)();block._tag="(?!(?:"+"a|em|strong|small|s|cite|q|dfn|abbr|data|time|code"+"|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo"+"|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b";block.html=replace(block.html)("comment",//)("closed",/<(tag)[\s\S]+?<\/\1>/)("closing",/])*?>/)(/tag/g,block._tag)();block.paragraph=replace(block.paragraph)("hr",block.hr)("heading",block.heading)("lheading",block.lheading)("blockquote",block.blockquote)("tag","<"+block._tag)("def",block.def)();block.normal=merge({},block);block.gfm=merge({},block.normal,{fences:/^ *(`{3,}|~{3,}) *(\S+)? *\n([\s\S]+?)\s*\1 *(?:\n+|$)/,paragraph:/^/});block.gfm.paragraph=replace(block.paragraph)("(?!","(?!"+block.gfm.fences.source.replace("\\1","\\2")+"|"+block.list.source.replace("\\1","\\3")+"|")();block.tables=merge({},block.gfm,{nptable:/^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,table:/^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/});function Lexer(options){this.tokens=[];this.tokens.links={};this.options=options||marked.defaults;this.rules=block.normal;if(this.options.gfm){if(this.options.tables){this.rules=block.tables}else{this.rules=block.gfm}}}Lexer.rules=block;Lexer.lex=function(src,options){var lexer=new Lexer(options);return lexer.lex(src)};Lexer.prototype.lex=function(src){src=src.replace(/\r\n|\r/g,"\n").replace(/\t/g," ").replace(/\u00a0/g," ").replace(/\u2424/g,"\n");return this.token(src,true)};Lexer.prototype.token=function(src,top,bq){var src=src.replace(/^ +$/gm,""),next,loose,cap,bull,b,item,space,i,l;while(src){if(cap=this.rules.newline.exec(src)){src=src.substring(cap[0].length);if(cap[0].length>1){this.tokens.push({type:"space"})}}if(cap=this.rules.code.exec(src)){src=src.substring(cap[0].length);cap=cap[0].replace(/^ {4}/gm,"");this.tokens.push({type:"code",text:!this.options.pedantic?cap.replace(/\n+$/,""):cap});continue}if(cap=this.rules.fences.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"code",lang:cap[2],text:cap[3]});continue}if(cap=this.rules.heading.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"heading",depth:cap[1].length,text:cap[2]});continue}if(top&&(cap=this.rules.nptable.exec(src))){src=src.substring(cap[0].length);item={type:"table",header:cap[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:cap[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:cap[3].replace(/\n$/,"").split("\n")};for(i=0;i ?/gm,"");this.token(cap,top,true);this.tokens.push({type:"blockquote_end"});continue}if(cap=this.rules.list.exec(src)){src=src.substring(cap[0].length);bull=cap[2];this.tokens.push({type:"list_start",ordered:bull.length>1});cap=cap[0].match(this.rules.item);next=false;l=cap.length;i=0;for(;i1&&b.length>1)){src=cap.slice(i+1).join("\n")+src;i=l-1}}loose=next||/\n\n(?!\s*$)/.test(item);if(i!==l-1){next=item.charAt(item.length-1)==="\n";if(!loose)loose=next}this.tokens.push({type:loose?"loose_item_start":"list_item_start"});this.token(item,false,bq);this.tokens.push({type:"list_item_end"})}this.tokens.push({type:"list_end"});continue}if(cap=this.rules.html.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:this.options.sanitize?"paragraph":"html",pre:cap[1]==="pre"||cap[1]==="script"||cap[1]==="style",text:cap[0]});continue}if(!bq&&top&&(cap=this.rules.def.exec(src))){src=src.substring(cap[0].length);this.tokens.links[cap[1].toLowerCase()]={href:cap[2],title:cap[3]};continue}if(top&&(cap=this.rules.table.exec(src))){src=src.substring(cap[0].length);item={type:"table",header:cap[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:cap[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:cap[3].replace(/(?: *\| *)?\n$/,"").split("\n")};for(i=0;i])/,autolink:/^<([^ >]+(@|:\/)[^ >]+)>/,url:noop,tag:/^|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,link:/^!?\[(inside)\]\(href\)/,reflink:/^!?\[(inside)\]\s*\[([^\]]*)\]/,nolink:/^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,strong:/^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,em:/^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,code:/^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,br:/^ {2,}\n(?!\s*$)/,del:noop,text:/^[\s\S]+?(?=[\\?(?:\s+['"]([\s\S]*?)['"])?\s*/;inline.link=replace(inline.link)("inside",inline._inside)("href",inline._href)();inline.reflink=replace(inline.reflink)("inside",inline._inside)();inline.normal=merge({},inline);inline.pedantic=merge({},inline.normal,{strong:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,em:/^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/});inline.gfm=merge({},inline.normal,{escape:replace(inline.escape)("])","~|])")(),url:/^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,del:/^~~(?=\S)([\s\S]*?\S)~~/,text:replace(inline.text)("]|","~]|")("|","|https?://|")()});inline.breaks=merge({},inline.gfm,{br:replace(inline.br)("{2,}","*")(),text:replace(inline.gfm.text)("{2,}","*")()});function InlineLexer(links,options){this.options=options||marked.defaults;this.links=links;this.rules=inline.normal;this.renderer=this.options.renderer||new Renderer;this.renderer.options=this.options;if(!this.links){throw new Error("Tokens array requires a `links` property.")}if(this.options.gfm){if(this.options.breaks){this.rules=inline.breaks}else{this.rules=inline.gfm}}else if(this.options.pedantic){this.rules=inline.pedantic}}InlineLexer.rules=inline;InlineLexer.output=function(src,links,options){var inline=new InlineLexer(links,options);return inline.output(src)};InlineLexer.prototype.output=function(src){var out="",link,text,href,cap;while(src){if(cap=this.rules.escape.exec(src)){src=src.substring(cap[0].length);out+=cap[1];continue}if(cap=this.rules.autolink.exec(src)){src=src.substring(cap[0].length);if(cap[2]==="@"){text=cap[1].charAt(6)===":"?this.mangle(cap[1].substring(7)):this.mangle(cap[1]);href=this.mangle("mailto:")+text}else{text=escape(cap[1]);href=text}out+=this.renderer.link(href,null,text);continue}if(!this.inLink&&(cap=this.rules.url.exec(src))){src=src.substring(cap[0].length);text=escape(cap[1]);href=text;out+=this.renderer.link(href,null,text);continue}if(cap=this.rules.tag.exec(src)){if(!this.inLink&&/^/i.test(cap[0])){this.inLink=false}src=src.substring(cap[0].length);out+=this.options.sanitize?escape(cap[0]):cap[0];continue}if(cap=this.rules.link.exec(src)){src=src.substring(cap[0].length);this.inLink=true;out+=this.outputLink(cap,{href:cap[2],title:cap[3]});this.inLink=false;continue}if((cap=this.rules.reflink.exec(src))||(cap=this.rules.nolink.exec(src))){src=src.substring(cap[0].length);link=(cap[2]||cap[1]).replace(/\s+/g," ");link=this.links[link.toLowerCase()];if(!link||!link.href){out+=cap[0].charAt(0);src=cap[0].substring(1)+src;continue}this.inLink=true;out+=this.outputLink(cap,link);this.inLink=false;continue}if(cap=this.rules.strong.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.strong(this.output(cap[2]||cap[1]));continue}if(cap=this.rules.em.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.em(this.output(cap[2]||cap[1]));continue}if(cap=this.rules.code.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.codespan(escape(cap[2],true));continue}if(cap=this.rules.br.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.br();continue}if(cap=this.rules.del.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.del(this.output(cap[1]));continue}if(cap=this.rules.text.exec(src)){src=src.substring(cap[0].length);out+=escape(this.smartypants(cap[0]));continue}if(src){throw new Error("Infinite loop on byte: "+src.charCodeAt(0))}}return out};InlineLexer.prototype.outputLink=function(cap,link){var href=escape(link.href),title=link.title?escape(link.title):null;return cap[0].charAt(0)!=="!"?this.renderer.link(href,title,this.output(cap[1])):this.renderer.image(href,title,escape(cap[1]))};InlineLexer.prototype.smartypants=function(text){if(!this.options.smartypants)return text;return text.replace(/--/g,"—").replace(/(^|[-\u2014/(\[{"\s])'/g,"$1‘").replace(/'/g,"’").replace(/(^|[-\u2014/(\[{\u2018\s])"/g,"$1“").replace(/"/g,"â€").replace(/\.{3}/g,"…")};InlineLexer.prototype.mangle=function(text){var out="",l=text.length,i=0,ch;for(;i.5){ch="x"+ch.toString(16)}out+=""+ch+";"}return out};function Renderer(options){this.options=options||{}}Renderer.prototype.code=function(code,lang,escaped){if(this.options.highlight){var out=this.options.highlight(code,lang);if(out!=null&&out!==code){escaped=true;code=out}}if(!lang){return""+(escaped?code:escape(code,true))+"\n
"}return''+(escaped?code:escape(code,true))+"\n
\n"};Renderer.prototype.blockquote=function(quote){return"\n"+quote+"
\n"};Renderer.prototype.html=function(html){return html};Renderer.prototype.heading=function(text,level,raw){return"\n"};Renderer.prototype.hr=function(){return this.options.xhtml?"
\n":"
\n"};Renderer.prototype.list=function(body,ordered){var type=ordered?"ol":"ul";return"<"+type+">\n"+body+""+type+">\n"};Renderer.prototype.listitem=function(text){return""+text+"\n"};Renderer.prototype.paragraph=function(text){return""+text+"
\n"};Renderer.prototype.table=function(header,body){return"\n"+"\n"+header+"\n"+"\n"+body+"\n"+"
\n"};Renderer.prototype.tablerow=function(content){return"\n"+content+"
\n"};Renderer.prototype.tablecell=function(content,flags){var type=flags.header?"th":"td";var tag=flags.align?"<"+type+' style="text-align:'+flags.align+'">':"<"+type+">";return tag+content+""+type+">\n"};Renderer.prototype.strong=function(text){return""+text+""};Renderer.prototype.em=function(text){return""+text+""};Renderer.prototype.codespan=function(text){return""+text+"
"};Renderer.prototype.br=function(){return this.options.xhtml?"
":"
"};Renderer.prototype.del=function(text){return""+text+""};Renderer.prototype.link=function(href,title,text){if(this.options.sanitize){try{var prot=decodeURIComponent(unescape(href)).replace(/[^\w:]/g,"").toLowerCase()}catch(e){return""}if(prot.indexOf("javascript:")===0){return""}}var out='"+text+"";return out};Renderer.prototype.image=function(href,title,text){var out='
":">";return out};function Parser(options){this.tokens=[];this.token=null;this.options=options||marked.defaults;this.options.renderer=this.options.renderer||new Renderer;this.renderer=this.options.renderer;this.renderer.options=this.options}Parser.parse=function(src,options,renderer){var parser=new Parser(options,renderer);return parser.parse(src)};Parser.prototype.parse=function(src){this.inline=new InlineLexer(src.links,this.options,this.renderer);this.tokens=src.reverse();var out="";while(this.next()){out+=this.tok()}return out};Parser.prototype.next=function(){return this.token=this.tokens.pop()};Parser.prototype.peek=function(){return this.tokens[this.tokens.length-1]||0};Parser.prototype.parseText=function(){var body=this.token.text;while(this.peek().type==="text"){body+="\n"+this.next().text}return this.inline.output(body)};Parser.prototype.tok=function(){switch(this.token.type){case"space":{return""}case"hr":{return this.renderer.hr()}case"heading":{return this.renderer.heading(this.inline.output(this.token.text),this.token.depth,this.token.text)}case"code":{return this.renderer.code(this.token.text,this.token.lang,this.token.escaped)}case"table":{var header="",body="",i,row,cell,flags,j;cell="";for(i=0;i/g,">").replace(/"/g,""").replace(/'/g,"'")}function unescape(html){return html.replace(/&([#\w]+);/g,function(_,n){n=n.toLowerCase();if(n==="colon")return":";if(n.charAt(0)==="#"){return n.charAt(1)==="x"?String.fromCharCode(parseInt(n.substring(2),16)):String.fromCharCode(+n.substring(1))}return""})}function replace(regex,opt){regex=regex.source;opt=opt||"";return function self(name,val){if(!name)return new RegExp(regex,opt);val=val.source||val;val=val.replace(/(^|[^\[])\^/g,"$1");regex=regex.replace(name,val);return self}}function noop(){}noop.exec=noop;function merge(obj){var i=1,target,key;for(;iAn error occured:"+escape(e.message+"",true)+"
"}throw e}}marked.options=marked.setOptions=function(opt){merge(marked.defaults,opt);return marked};marked.defaults={gfm:true,tables:true,breaks:false,pedantic:false,sanitize:false,smartLists:false,silent:false,highlight:null,langPrefix:"lang-",smartypants:false,headerPrefix:"",renderer:new Renderer,xhtml:false};marked.Parser=Parser;marked.parser=Parser.parse;marked.Renderer=Renderer;marked.Lexer=Lexer;marked.lexer=Lexer.lex;marked.InlineLexer=InlineLexer;marked.inlineLexer=InlineLexer.output;marked.parse=marked;if(typeof exports==="object"){module.exports=marked}else if(typeof define==="function"&&define.amd){define(function(){return marked})}else{this.marked=marked}}).call(function(){return this||(typeof window!=="undefined"?window:global)}());
--------------------------------------------------------------------------------
/src/wordsmith/core.cljs:
--------------------------------------------------------------------------------
1 | (ns wordsmith.core
2 | (:require-macros [cljs.core.async.macros :refer [go-loop]])
3 | (:require [om.core :as om :include-macros true]
4 | [om.dom :as dom :include-macros true]
5 | [wordsmith.persistence :as p]
6 | [cljs.core.async :refer [put! chan