├── .gitattributes
├── .gitignore
├── .nojekyll
├── CNAME
├── LICENSE
├── README.md
├── _coverpage.md
├── assets
└── fonts
│ ├── labmono-license.txt
│ ├── labmono-regular-web.woff
│ └── labmono-regular-web.woff2
├── favicon.ico
├── ignored_characters.txt
├── index.html
├── parser
├── assets
│ └── fonts
│ │ ├── labmono-license.txt
│ │ ├── labmono-regular-web.woff
│ │ └── labmono-regular-web.woff2
├── css
│ └── styles.css
├── index.html
└── js
│ ├── MarginConverter.js
│ ├── MarginParser.js
│ ├── MarginParserExample.js
│ ├── TreeModel.js
│ └── jquery-3.4.1.min.js
└── styles.css
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
3 | assets/img/noun_Margin right_548853.png
4 | assets/img/noun_Margin right_548853.psd
5 | assets/img/logo.png
6 | README.margin
7 | .DS_Store
8 |
--------------------------------------------------------------------------------
/.nojekyll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gamburg/margin/baf615767bd73d86a206d8fd94e057881818fbfa/.nojekyll
--------------------------------------------------------------------------------
/CNAME:
--------------------------------------------------------------------------------
1 | margin.love
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Alex Gamburg
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 | # Philosophy
2 |
3 | Margin is a lightweight markup language for hierarchically structured thought, like notes and to-do lists.
4 |
5 | Its platform-independent structure is both human- and machine-readable.
6 |
7 | This means that Margin can thrive within any plain text editor, and on any hardware -- even paper.
8 |
9 | However unpredictably a thinker prefers to indent, ornament, number, or label their text, Margin will interpret their [**items**](#items) predictably:
10 |
11 | ```margin
12 | Favorite Movies
13 | Eyes Wide Shut
14 | Black Narcissus
15 | Adaptation
16 |
17 | [Is equivalent to...]
18 |
19 | Favorite Movies:
20 | - Eyes Wide Shut
21 | - Black Narcissus
22 | - Adaptation
23 |
24 | [Is equivalent to...]
25 |
26 | ** Favorite Movies **
27 | > Eyes Wide Shut
28 | > Black Narcissus
29 | > Adaptation
30 | ```
31 |
32 | This allows the thinker to adopt whatever visual grammar they prefer.
33 |
34 | Items can also be assigned arbitrary [**annotations**](#annotations), which can store meta data:
35 |
36 | ```margin
37 | Favorite Movies
38 | Eyes Wide Shut [year: 1999]
39 | Black Narcissus [year: 1947]
40 | Adaptation [year: 2002]
41 | ```
42 |
43 | Annotations can also signal how items should be interpreted, e.g. as tasks:
44 |
45 | ```margin
46 | Movies to watch:
47 | [x] Shoplifters
48 | [ ] Lawrence of Arabia
49 | [ ] Inland Empire
50 | ```
51 |
52 | Margin is especially useful for applications that wish to be less prescriptive in their mental models, leaving it to the user to determine how they'd like to interpret the hierarchical structure.
53 |
54 | Margin aims to shepherd apps away from the tendency to overcomplicate and over-define.
55 |
56 | ### Points of frustration that led to Margin {docsify-ignore}
57 |
58 | There are plenty of well-known, powerful applications that force their own organizational philosophy on the user. And there's nothing inherently wrong with that.
59 |
60 | Nevertheless, when an application's user-facing models of thought...
61 | 1. cannot be easily mapped to the user's own mental models, or
62 | 2. are not justified for the user,
63 |
64 | it can lead to frustration. For example:
65 | - A mobile to-do list app employs a `Flagged` button that takes up valuable home screen space before any tasks have been flagged -- and without knowing whether the user intends to use the flag feature at all. (iOS 13 Reminders)
66 |
67 | - A task management app employs a model of Board -> List -> Card. Lists cannot contain other lists, cards cannot contain other cards, cards cannot contain lists, and so on. (Trello)
68 |
69 | - A to-do list app dictates a set of reserved attributes, like `Labels` and `Filters`, which cannot be removed from the interface. (Todoist)
70 |
71 | I use and love all of the above applications. Their specialization is their strength. Margin's philosophy simply asserts that there is space for a more adaptable standard for stuctured thought.
72 |
73 | In this respect, Margin promotes a common sense approach to modeling thought: simply place the thinker's preferences first.
74 |
75 | This approach begins with a flexible plain text standard. After that, it is the application's job to improve the thinker's experience through specialized tools and prescriptive user-facing models -- as long as the underlying source material remains portable and human-readable.
76 |
77 | Margin is free and open-source.
78 |
79 | -------------------------------
80 |
81 | # Syntax
82 |
83 | Margin employs an ordered tree data structure whose nodes are called items. Indentation forms the basis of the syntax.
84 |
85 | ## Items
86 |
87 | Each line represents an item:
88 |
89 | ```margin
90 | Shirt
91 | Pants
92 | Shoes
93 | ```
94 | Each item can have a single parent and multiple children. Indentation alone determines this hierarchy:
95 | ```margin
96 | Shirt
97 | Collar
98 | Sleeves
99 | Buttons
100 | Pants
101 | Belt loop
102 | Pockets
103 | Shoes
104 | Tongue
105 | Laces
106 | ```
107 | Leading & trailing dashes, colons, asterisks, chevrons, underscores and whitespaces, as well as blank lines, are ignored:
108 | ```margin
109 | ** Key Takeaways **
110 | -------------------
111 | Feel free to use plain text decorations freely in order to:
112 | - Help structure your thinking
113 | - Make your plain text documents more easily scannable
114 | ```
115 | [See the list of all ignored characters.](https://margin.love/ignored_characters.txt)
116 |
117 | ## Annotations
118 |
119 | An annotation is any childless item wrapped in square brackets:
120 | ```margin
121 | I'm a plain old item
122 | [and I'm an annotation]
123 | ```
124 | Annotations can be used to store meta data:
125 | ```margin
126 | The Crying of Lot 49
127 | [author: Thomas Pynchon]
128 | [publication year: 1966]
129 | [publisher: J. B. Lippincott & Co.]
130 | ```
131 | An annotation is the child of any inline, non-annotation item:
132 | ```margin
133 | Items:
134 | - Item A
135 | - [I belong to Item B] Item B [I also belong to Item B]
136 | - Item C
137 | [I belong to Item C]
138 | ```
139 | Because annotations cannot have children, an indented item following an annotation is considered that annotation's parent:
140 | ```margin
141 | Items:
142 | - Item Y
143 | [I belong to Item Y]
144 | - [I belong to Item Z]
145 | Item Z
146 | ```
147 | Escape an annotation with a backslash:
148 | ```margin
149 | This is an item \[but this is not an annotation]
150 | ```
151 | Any text up until the (optional) first colon in an annotation may safely be interpreted as the annotation type.
152 |
153 | Annotations with type `population`:
154 | ```margin
155 | Continents
156 | Asia [population: 4,601,371,198]
157 | Africa [population: 1,308,064,195]
158 | Europe [population: 747,182,751]
159 | South America [population: 427,199,446]
160 | North America [population: 366,600,964]
161 | Oceania [population: 42,128,035]
162 | ```
163 | Annotations with types `waiter` and `host`:
164 | ```margin
165 | Restaurant Staff
166 | Christine [waiter]
167 | Steven [waiter]
168 | Jessica [host]
169 | ```
170 | An annotation whose type is not understood by the interpreting application may safely be ignored (but should not be discarded):
171 | ```margin
172 | [For example: this annotation won't be utilized unless the app has an interpreter for type "For example".]
173 | ```
174 | An annotation cannot be nested:
175 | ```margin
176 | [This entire sentence [including this text] represents a single annotation]
177 | ```
178 |
179 | ## Interpreting Items
180 |
181 | While there are no hard-and-fast rules about how items should be interpreted, the following are good guidelines for most applications.
182 |
183 | ### Tasks
184 | A task is any item that parents an annotation of type `x` or `empty string`:
185 | ```margin
186 | Daily Rituals
187 | [x] Meditate
188 | [ ] Work Out
189 | [ ] Read for 10 minutes
190 | ```
191 |
192 | ### Links
193 | An annotation of type `http` or `https` represents a link:
194 | ```margin
195 | Some people choose to set their homepage to [http://www.google.com].
196 | ```
197 | Text to the left of the annotation not separated by an `empty string` is the link's label:
198 | ```margin
199 | I rarely use Yahoo[http://www.yahoo.com] for search anymore.
200 | ```
201 | For multi-word labels, wrap the entire label in parentheses:
202 | ```margin
203 | Sometimes I do read (Yahoo News)[https://news.yahoo.com], though.
204 | ```
205 |
206 | ### Indexes
207 | An index is any item that parents an annotation of type `filter`:
208 | ```margin
209 | Now Playing [filter: release date is before tomorrow]
210 | Coming Soon [filter: release date is after today]
211 | ```
212 | An application may use the specified query to filter for certain nodes under certain conditions of interaction. For most applications, the default filter for a given task (when no filter is specified) would be that task's children. But this is outside the scope of the markup language itself.
213 |
214 | ### Document Parent
215 | Every Margin document has an implied document parent, an item that parents every top-level item in the document. This item can also have annotations, which can be useful as document-level meta data. These annotations are defined as the first apparently parentless annotation in the document:
216 | ```margin
217 | [Kid Reader Pro]
218 | [Reader Name: Kit Mapache]
219 |
220 | Read:
221 | - The Phantom Tollbooth
222 | - A Wrinkle in Time
223 | - Charlotte's Web
224 |
225 | Unread:
226 | - Where the Wild Things Are
227 | ```
228 |
229 | # Try it out
230 |
231 | The Margin JavaScript parser is currently in alpha. [You can try it out for yourself here](https://margin.love/parser), but note that some functionality defined in this spec will not yet function properly.
232 |
233 | # Implementations
234 |
235 | - This repo contains the original Javascript implementation.
236 | - [MarginRB](https://github.com/burlesona/margin-rb) - Ruby implementation by @burlesona
237 |
238 | # Questions
239 |
240 | **Why not TaskPaper?**
241 |
242 | [TaskPaper](https://www.taskpaper.com) is a great, minimal app for creating to-do lists. Some readers might feel that Margin's capabilities are redundant, but I believe Margin stands apart in several key ways:
243 |
244 | - Margin is not an app, but a markup language.
245 | - Margin is hierarchically less prescriptive than TaskPaper. Where TaskPaper splits items into `projects`, `tasks`, and `notes`, Margin sees only items. A top-level item in Margin *could* be considered a project, but it could also just as easily be considered a list, a note, a task, a chapter, an employee, an index, etc.
246 | - Margin is syntactically less prescriptive than [TaskPaper's formatting](https://guide.taskpaper.com/getting-started/). TaskPaper categorizes items by their ornamentation (`projects` end with a colon, `tasks` begin with a dash, and `notes` must not fall into either of those two categories). Margin intentionally avoids such definitions, allowing the user to ornament (or not) plain text in nearly any format they prefer.
247 |
248 | **Indentation? Human-readable? Won't a complicated Margin document just end up as a jumbled mess of deeply indented text blocks and annotations?**
249 |
250 | Margin isn't meant for storing complex databases. It's meant to make text-based structured thought portable and platform-independent. In the same way that Markdown is built to translate into HTML, but you wouldn't build a web app in Markdown, so Margin too has its limitations. The idea is to de-formalize any unnecessary syntactic requirements, leaving only indentations and a select number of special operators to dictate the parsing of the language. Keeping it simple has its benefits, but it also has its costs.
251 |
252 | **What is the preferred extension for Margin files?**
253 |
254 | Margin files use the extension `.margin`.
255 |
256 | **Does Margin support multi-line items?**
257 |
258 | No. But if you're writing in Margin and you really want items to span multiple lines, feel free to use whatever syntax appeals to you to acheive that. Margin certainly doesn't care what you do in the privacy of your own plain text editor. Just don't expect those multi-line items to be interpreted properly by a given application.
259 |
260 | **Where can I send feedback?**
261 |
262 | Please submit any feedback as an issue on [Margin's public GitHub repository](https://github.com/gamburg/margin/issues).
263 |
--------------------------------------------------------------------------------
/_coverpage.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | > ⊙
4 | # Margin
5 |
6 | > Lightweight markup designed for an open mind
7 |
8 | - The plain text language for list-making, note-taking, and to-dos.
9 | - Thinkers determine their own organizational models.
10 | - Infinitely extensible, inherently readable.
11 |
12 |
13 | [Learn Margin →](#philosophy)
14 | [Try it out ✎](https://margin.love/parser)
15 | [GitHub ♡](https://github.com/gamburg/margin)
16 |
17 |
18 |
19 | 
20 |
--------------------------------------------------------------------------------
/assets/fonts/labmono-license.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2015, Martin Wecke (http://martinwecke.de),
2 | with Reserved Font Name Lab Mono.
3 |
4 | This Font Software is licensed under the SIL Open Font License, Version 1.1.
5 | This license is copied below, and is also available with a FAQ at:
6 | http://scripts.sil.org/OFL
7 |
8 |
9 | -----------------------------------------------------------
10 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
11 | -----------------------------------------------------------
12 |
13 | PREAMBLE
14 | The goals of the Open Font License (OFL) are to stimulate worldwide
15 | development of collaborative font projects, to support the font creation
16 | efforts of academic and linguistic communities, and to provide a free and
17 | open framework in which fonts may be shared and improved in partnership
18 | with others.
19 |
20 | The OFL allows the licensed fonts to be used, studied, modified and
21 | redistributed freely as long as they are not sold by themselves. The
22 | fonts, including any derivative works, can be bundled, embedded,
23 | redistributed and/or sold with any software provided that any reserved
24 | names are not used by derivative works. The fonts and derivatives,
25 | however, cannot be released under any other type of license. The
26 | requirement for fonts to remain under this license does not apply
27 | to any document created using the fonts or their derivatives.
28 |
29 | DEFINITIONS
30 | "Font Software" refers to the set of files released by the Copyright
31 | Holder(s) under this license and clearly marked as such. This may
32 | include source files, build scripts and documentation.
33 |
34 | "Reserved Font Name" refers to any names specified as such after the
35 | copyright statement(s).
36 |
37 | "Original Version" refers to the collection of Font Software components as
38 | distributed by the Copyright Holder(s).
39 |
40 | "Modified Version" refers to any derivative made by adding to, deleting,
41 | or substituting -- in part or in whole -- any of the components of the
42 | Original Version, by changing formats or by porting the Font Software to a
43 | new environment.
44 |
45 | "Author" refers to any designer, engineer, programmer, technical
46 | writer or other person who contributed to the Font Software.
47 |
48 | PERMISSION & CONDITIONS
49 | Permission is hereby granted, free of charge, to any person obtaining
50 | a copy of the Font Software, to use, study, copy, merge, embed, modify,
51 | redistribute, and sell modified and unmodified copies of the Font
52 | Software, subject to the following conditions:
53 |
54 | 1) Neither the Font Software nor any of its individual components,
55 | in Original or Modified Versions, may be sold by itself.
56 |
57 | 2) Original or Modified Versions of the Font Software may be bundled,
58 | redistributed and/or sold with any software, provided that each copy
59 | contains the above copyright notice and this license. These can be
60 | included either as stand-alone text files, human-readable headers or
61 | in the appropriate machine-readable metadata fields within text or
62 | binary files as long as those fields can be easily viewed by the user.
63 |
64 | 3) No Modified Version of the Font Software may use the Reserved Font
65 | Name(s) unless explicit written permission is granted by the corresponding
66 | Copyright Holder. This restriction only applies to the primary font name as
67 | presented to the users.
68 |
69 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
70 | Software shall not be used to promote, endorse or advertise any
71 | Modified Version, except to acknowledge the contribution(s) of the
72 | Copyright Holder(s) and the Author(s) or with their explicit written
73 | permission.
74 |
75 | 5) The Font Software, modified or unmodified, in part or in whole,
76 | must be distributed entirely under this license, and must not be
77 | distributed under any other license. The requirement for fonts to
78 | remain under this license does not apply to any document created
79 | using the Font Software.
80 |
81 | TERMINATION
82 | This license becomes null and void if any of the above conditions are
83 | not met.
84 |
85 | DISCLAIMER
86 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
87 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
88 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
89 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
90 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
91 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
92 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
93 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
94 | OTHER DEALINGS IN THE FONT SOFTWARE.
95 |
--------------------------------------------------------------------------------
/assets/fonts/labmono-regular-web.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gamburg/margin/baf615767bd73d86a206d8fd94e057881818fbfa/assets/fonts/labmono-regular-web.woff
--------------------------------------------------------------------------------
/assets/fonts/labmono-regular-web.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gamburg/margin/baf615767bd73d86a206d8fd94e057881818fbfa/assets/fonts/labmono-regular-web.woff2
--------------------------------------------------------------------------------
/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gamburg/margin/baf615767bd73d86a206d8fd94e057881818fbfa/favicon.ico
--------------------------------------------------------------------------------
/ignored_characters.txt:
--------------------------------------------------------------------------------
1 | U+0020 (whitespace)
2 | U+0009 (tab)
3 | U+002A (*)
4 | U+FE61 (﹡)
5 | U+FF0A (*)
6 | U+002D (-)
7 | U+2013 (–)
8 | U+2014 (—)
9 | U+005F (_)
10 | U+003A (:)
11 | U+003E (>)
12 | U+002B (+)
13 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
17 |
18 |
19 |
20 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/parser/assets/fonts/labmono-license.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2015, Martin Wecke (http://martinwecke.de),
2 | with Reserved Font Name Lab Mono.
3 |
4 | This Font Software is licensed under the SIL Open Font License, Version 1.1.
5 | This license is copied below, and is also available with a FAQ at:
6 | http://scripts.sil.org/OFL
7 |
8 |
9 | -----------------------------------------------------------
10 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
11 | -----------------------------------------------------------
12 |
13 | PREAMBLE
14 | The goals of the Open Font License (OFL) are to stimulate worldwide
15 | development of collaborative font projects, to support the font creation
16 | efforts of academic and linguistic communities, and to provide a free and
17 | open framework in which fonts may be shared and improved in partnership
18 | with others.
19 |
20 | The OFL allows the licensed fonts to be used, studied, modified and
21 | redistributed freely as long as they are not sold by themselves. The
22 | fonts, including any derivative works, can be bundled, embedded,
23 | redistributed and/or sold with any software provided that any reserved
24 | names are not used by derivative works. The fonts and derivatives,
25 | however, cannot be released under any other type of license. The
26 | requirement for fonts to remain under this license does not apply
27 | to any document created using the fonts or their derivatives.
28 |
29 | DEFINITIONS
30 | "Font Software" refers to the set of files released by the Copyright
31 | Holder(s) under this license and clearly marked as such. This may
32 | include source files, build scripts and documentation.
33 |
34 | "Reserved Font Name" refers to any names specified as such after the
35 | copyright statement(s).
36 |
37 | "Original Version" refers to the collection of Font Software components as
38 | distributed by the Copyright Holder(s).
39 |
40 | "Modified Version" refers to any derivative made by adding to, deleting,
41 | or substituting -- in part or in whole -- any of the components of the
42 | Original Version, by changing formats or by porting the Font Software to a
43 | new environment.
44 |
45 | "Author" refers to any designer, engineer, programmer, technical
46 | writer or other person who contributed to the Font Software.
47 |
48 | PERMISSION & CONDITIONS
49 | Permission is hereby granted, free of charge, to any person obtaining
50 | a copy of the Font Software, to use, study, copy, merge, embed, modify,
51 | redistribute, and sell modified and unmodified copies of the Font
52 | Software, subject to the following conditions:
53 |
54 | 1) Neither the Font Software nor any of its individual components,
55 | in Original or Modified Versions, may be sold by itself.
56 |
57 | 2) Original or Modified Versions of the Font Software may be bundled,
58 | redistributed and/or sold with any software, provided that each copy
59 | contains the above copyright notice and this license. These can be
60 | included either as stand-alone text files, human-readable headers or
61 | in the appropriate machine-readable metadata fields within text or
62 | binary files as long as those fields can be easily viewed by the user.
63 |
64 | 3) No Modified Version of the Font Software may use the Reserved Font
65 | Name(s) unless explicit written permission is granted by the corresponding
66 | Copyright Holder. This restriction only applies to the primary font name as
67 | presented to the users.
68 |
69 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
70 | Software shall not be used to promote, endorse or advertise any
71 | Modified Version, except to acknowledge the contribution(s) of the
72 | Copyright Holder(s) and the Author(s) or with their explicit written
73 | permission.
74 |
75 | 5) The Font Software, modified or unmodified, in part or in whole,
76 | must be distributed entirely under this license, and must not be
77 | distributed under any other license. The requirement for fonts to
78 | remain under this license does not apply to any document created
79 | using the Font Software.
80 |
81 | TERMINATION
82 | This license becomes null and void if any of the above conditions are
83 | not met.
84 |
85 | DISCLAIMER
86 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
87 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
88 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
89 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
90 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
91 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
92 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
93 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
94 | OTHER DEALINGS IN THE FONT SOFTWARE.
95 |
--------------------------------------------------------------------------------
/parser/assets/fonts/labmono-regular-web.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gamburg/margin/baf615767bd73d86a206d8fd94e057881818fbfa/parser/assets/fonts/labmono-regular-web.woff
--------------------------------------------------------------------------------
/parser/assets/fonts/labmono-regular-web.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gamburg/margin/baf615767bd73d86a206d8fd94e057881818fbfa/parser/assets/fonts/labmono-regular-web.woff2
--------------------------------------------------------------------------------
/parser/css/styles.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: 'Lab Mono';
3 | src: url('../assets/fonts/labmono-regular-web.woff2') format('woff2'),
4 | url('../assets/fonts/labmono-regular-web.woff') format('woff');
5 | }
6 |
7 | html, body {
8 | height: 100%;
9 | font-family: 'Lab Mono', 'Courier', monospace;
10 | margin: 0;
11 | }
12 |
13 | .input, .output {
14 | font-family: inherit;
15 | font-size: .8em;
16 | height: 100%;
17 | width: 100%;
18 |
19 | padding: 2em;
20 | -moz-box-sizing: border-box;
21 | -webkit-box-sizing: border-box;
22 | box-sizing: border-box;
23 |
24 | border: none;
25 | outline: none;
26 |
27 | -moz-tab-size : 4;
28 | -o-tab-size : 4;
29 | tab-size : 4;
30 | }
31 |
32 | .input {
33 | float: left;
34 | cursor:text;
35 | }
36 |
37 | .output {
38 | float: right;
39 | white-space: pre;
40 | overflow: scroll;
41 | }
42 |
43 | header {
44 | -moz-box-sizing: border-box;
45 | -webkit-box-sizing: border-box;
46 | box-sizing: border-box;
47 | padding: 1em 2em;
48 | }
49 |
50 | input[type="radio"]:checked+label {
51 | text-decoration: underline;
52 | }
53 |
54 | input[type="radio"]+label {
55 | font-size: .9em;
56 | padding: 0 .5em 0 .2em;
57 | vertical-align: middle;
58 | white-space: nowrap;
59 | }
60 |
61 | input[type="radio"] {
62 | display: none;
63 | }
64 |
65 | input[type="radio"]+label {
66 | cursor: pointer;
67 | }
68 |
69 | h2 {
70 | font-size:2em;
71 | font-weight: bold;
72 | margin-top: .4em;
73 | margin-bottom: .5em;
74 | }
75 |
76 | .light {
77 | background: #f6f5f5;
78 | color: #33313b;
79 | }
80 |
81 | .dark {
82 | background: #33313b;
83 | color: #f6f5f5;
84 | }
85 |
86 | div {
87 | display: inline-block;
88 | height: 100%;
89 | width: 50%;
90 | }
91 |
--------------------------------------------------------------------------------
/parser/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Try Margin
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
Input
15 |
16 |
17 |
18 |
19 |
24 |
25 |
26 |
Output
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/parser/js/MarginConverter.js:
--------------------------------------------------------------------------------
1 | function convert_margin( root, output_format ) {
2 | switch(output_format) {
3 | case 'json':
4 | return JSON.stringify(root.model, null, 5);
5 | break;
6 |
7 | case 'markdown':
8 | return 'markdown output here';
9 | break;
10 |
11 | case 'pretty':
12 | return ' I have a bike ';
13 | break;
14 | }
15 | return null;
16 | }
17 |
--------------------------------------------------------------------------------
/parser/js/MarginParser.js:
--------------------------------------------------------------------------------
1 | class MarginTree extends TreeModel {
2 | }
3 |
4 | class MarginItem {
5 |
6 | constructor( parseable_text ) {
7 | this.raw_data = get_top_level_text( parseable_text );
8 | this.value = this.get_value();
9 | this.annotations = this.set_annotations();
10 | this.children = [];
11 | var _this = this; // allows this instance to be visible inside forEach loop
12 |
13 | var child_parseable_text = get_child_text_trees( parseable_text );
14 | console.log(child_parseable_text);
15 |
16 | child_parseable_text.forEach(function(child_text) {
17 | var child_item = new MarginItem( child_text );
18 | _this.children.push( child_item );
19 | });
20 | }
21 |
22 | get_value() {
23 | // leading characters regex: /^([-_> ])*/g;
24 | // trailing characters regex: /(([-_>* ])+$)/g;
25 | // annotations regex = ??????? // <-----TODO
26 | var regex_trim_these = /(^([-_>* \t])*)|(([-_>* \t])+$)/g;
27 | return this.raw_data.replace( regex_trim_these, '');
28 | }
29 |
30 | trim_characters( str, characters_to_remove, leading = true ) {
31 |
32 | }
33 |
34 | get_annotations( key = false ) {
35 | if( !key ) {
36 | return this.annotations;
37 | }
38 | return this.annotations[key];
39 | }
40 |
41 | set_annotations() {
42 | // bracketed segments regex: /\[(?:[^\]\[]+|\[(?:[^\]\[]+|\[[^\]\[]*\])*\])*\]/g
43 | var annotations = {};
44 | var key_value_separator = ':';
45 | var regex_annotations = /\[(?:[^\]\[]+|\[(?:[^\]\[]+|\[[^\]\[]*\])*\])*\]/g;
46 | var raw_annotations = this.raw_data.match( regex_annotations );
47 |
48 | if( raw_annotations ) {
49 | raw_annotations.forEach(function( raw_annotation ) {
50 | var key;
51 | var value = null;
52 | var raw_annotation_unwrapped = raw_annotation.slice(1,-1); // remove ] & [
53 | var key_value_separator_index = raw_annotation_unwrapped.indexOf( key_value_separator );
54 | if( key_value_separator_index < 0 ) { // no annotation separator found
55 | key = raw_annotation_unwrapped;
56 | } else {
57 | key = raw_annotation_unwrapped.substring(0, key_value_separator_index);
58 | value = raw_annotation_unwrapped.substring(key_value_separator_index + 1, raw_annotation_unwrapped.length);
59 | }
60 | annotations[key] = value;// <-------- TODO: assign annotation's value to annotation's key(not currently functioning)
61 | });
62 | }
63 | return annotations;
64 | }
65 | }
66 |
67 | function get_margin_item( text ) {
68 | var root_text = "root\n";
69 | var shifted_text = root_text.concat( shift_right( text ) );
70 | var parseable_text = conform_text_for_parsing( shifted_text );
71 | return new MarginItem( parseable_text );
72 | }
73 |
74 | function conform_text_for_parsing( text ) {
75 | return remove_blank_lines( text );
76 | }
77 |
78 | function remove_blank_lines( text ) {
79 | return text.replace(/^\s*[\r\n]/gm, '');
80 | }
81 |
82 | function get_child_text_trees( text_tree ) {
83 | var child_texts = [];
84 |
85 | var lines = text_tree.split('\n');
86 | var top_level = get_line_indentation_number( lines[0] );
87 |
88 | // Strip off parent text:
89 | for(var i = 0; i < lines.length; i++) {
90 | if( get_line_indentation_number( lines[i] ) === top_level ) {
91 | lines.splice(i, 1);
92 | }
93 | }
94 |
95 | return get_margin_text_from_line_array( lines );
96 |
97 | }
98 |
99 | function get_top_level_text( text_tree ) {
100 | var lines = text_tree.split('\n');
101 | return lines[0];
102 | }
103 |
104 | function get_margin_text_from_line_array( lines ) {
105 |
106 | var child_texts = [];
107 | var current_indentation = null;
108 | var current_child_text = "";
109 |
110 | for(var i = 0; i < lines.length; i++) {
111 | if( !current_indentation ) {
112 | current_indentation = get_line_indentation_number( lines[i] );
113 | current_child_text += lines[i];
114 | } else {
115 | if( get_line_indentation_number( lines[i] ) === current_indentation ) {
116 | child_texts.push( current_child_text );
117 | current_indentation = get_line_indentation_number( lines[i] );
118 | current_child_text = lines[i];
119 | } else {
120 | current_child_text += '\n' + lines[i];
121 | }
122 | }
123 | }
124 |
125 | if(current_child_text) {
126 | child_texts.push( current_child_text );
127 | }
128 |
129 | return child_texts;
130 | }
131 |
132 | function get_line_indentation_number(text) {
133 | return text.search(/\S|$/);
134 | }
135 |
136 | function shift_right( text, indenter = " " ) {
137 | var lines = text.split('\n');
138 | var shifted_lines = [];
139 |
140 | for(var i = 0; i < lines.length; i++) {
141 | shifted_lines.push( indenter.concat(lines[i]) );
142 | }
143 |
144 | return shifted_lines.join("\n");
145 | }
146 |
--------------------------------------------------------------------------------
/parser/js/MarginParserExample.js:
--------------------------------------------------------------------------------
1 | jQuery( document ).ready(function() {
2 | var input_area = jQuery('.input');
3 | var output_area = jQuery('.output');
4 | var ouput_select = jQuery('.output_wrapper input[type=radio]');
5 | var input_radios = jQuery('.input_wrapper input[type=radio]');
6 | var update_triggers = jQuery('.input, .output, input[type=radio]');
7 | var output_radio_selector = 'input[name="output"]:checked';
8 |
9 | make_textarea_margin_friendly( input_area );
10 | update_input_area_on_select( input_area, input_radios );
11 | update_output_area_on_change( update_triggers, input_area, output_area, output_radio_selector );
12 | });
13 |
14 | function update_input_area_on_select( input_area, trigger_elements ) {
15 | trigger_elements.on('change', function() {
16 | var sample_name_to_find = get_radio_input_selected( trigger_elements ).val();
17 | input_samples.forEach(function( sample ) {
18 | if( sample.name === sample_name_to_find ) {
19 | input_area.text( sample.data );
20 | }
21 | });
22 | }).triggerHandler('change');
23 | }
24 |
25 | function move_focus_to_end_of_input( e ) {
26 | val = e.val();
27 | e.focus().val("").val(val);
28 | }
29 |
30 | function update_output_area_on_change( update_triggers, input_area, output_area, output_radio_selector ) {
31 | update_triggers.on('change keyup paste', function() {
32 | var converted_text = get_converted_text( input_area.val(), get_output_format( output_radio_selector ) );
33 | switch( get_display_format(output_radio_selector) ) {
34 | case 'html':
35 | output_area.html( converted_text );
36 | break;
37 | case 'text':
38 | output_area.text( converted_text );
39 | break;
40 | }
41 | }).triggerHandler('change');
42 | }
43 |
44 | function get_output_format( selector ) {
45 | return document.querySelector(selector).value;
46 | }
47 |
48 | function get_display_format( selector ) {
49 | return document.querySelector(selector).dataset.display;
50 | }
51 |
52 | function get_radio_input_selected( input_elements ) {
53 | return input_elements.parent().find( 'input[type=radio]:checked' );
54 | }
55 |
56 | function get_converted_text( input_text, output_format ) {
57 | var sampleTree = new MarginTree();
58 | var root = sampleTree.parse( get_margin_item(input_text) );
59 | return convert_margin( root, output_format );
60 | }
61 |
62 | /*********************
63 |
64 | Global Variables
65 |
66 | **********************/
67 |
68 | var input_samples = [
69 | {
70 | name: 'shopping',
71 | data: ' ** Shopping **\n [x] Groceries\n [x] Milk\n [x] Kale\n [ ] Frozen Fish [Note: Any sort of white fish, not cod]\n\n ** Projects **\n Portfolio Website\n Front-end\n [ ] Disallow zoom on mobile\n [ ] Fix homepage grid on mobile\n Back-end\n Wordpress\n [ ] Update plugins [date: 2019/07/07]\n Server\n [ ] Renew hosting [date: 2020/01/07]\n [ ] Upgrade to PHP 7 [date: 2020/02/14]'
72 | },
73 | {
74 | name: 'notes',
75 | data: '\'Typograpy That Works\'\n\n\tCourse Notes\n\t\tGraphic design is all about lining things up (often in a grid)\n\t\tStandard Alignments\n\t\t\t> Centered: Formal, symmetrical\n\t\t\t> Justified: Economical, saves space\n\t\t\t> Flush Left: Organic\n\t\t\t> Flush Right: Unusual, lends a dynamism\n\t\tThere should be a self-contained logic to the chosen grid\n\t\tMultiple layout ideas should be tested rapidly\n\n\tClass Assignments\n\t\t- Project 1 [due: 2019/01/12]\n\t\t- Midterm [due: 2019/02/18]\n\t\t- Final Project [due: 2019/03/14]'
76 | },
77 | {
78 | name: 'reading',
79 | data: 'The Crying of Lot 49\n\t[author: Thomas Pynchon]\n\t[publication year: 1966]\n\t[publisher: J. B. Lippincott & Co.]\n\t[status: read]\n\nMy Struggle: Book 1\n\t[author: Karl Ove Knausgaard]\n\t[publication year: 2013]\n\t[publisher: Farrar, Straus and Giroux]\n\t[status: unread]\n\nTrick Mirror: Reflections on Self-Delusion\n\t[author: Jia Tolentino]\n\t[publication year: 2019]\n\t[publisher: Random House]\n\t[status: unread]'
80 | }
81 | ]
82 |
83 |
84 | /* ------------------------------------------------------------------------- */
85 |
86 | function make_textarea_margin_friendly( textarea ) {
87 | enable_tab_in_textarea( textarea );
88 | preserve_newline_indentation_in_textarea( textarea );
89 | }
90 |
91 | function enable_tab_in_textarea( textarea ) {
92 | textarea.keydown(function(e) {
93 | if(e.keyCode === 9) { // tab was pressed
94 | // get caret position/selection
95 | var start = this.selectionStart;
96 | end = this.selectionEnd;
97 |
98 | var $this = $(this);
99 |
100 | // set textarea value to: text before caret + tab + text after caret
101 | $this.val($this.val().substring(0, start)
102 | + "\t"
103 | + $this.val().substring(end));
104 |
105 | // put caret at right position again
106 | this.selectionStart = this.selectionEnd = start + 1;
107 |
108 | // prevent the focus lose
109 | return false;
110 | }
111 | });
112 | }
113 |
114 | function preserve_newline_indentation_in_textarea( textarea ) {
115 | textarea.keydown(function(e){
116 | if(e.keyCode == 13){
117 | var cursorPos = this.selectionStart;
118 | var curentLine = this.value.substr(0, this.selectionStart).split("\n").pop();
119 | var indent = curentLine.match(/^\s*/)[0];
120 | var value = this.value;
121 | var textBefore = value.substring(0, cursorPos );
122 | var textAfter = value.substring( cursorPos, value.length );
123 |
124 | e.preventDefault(); // avoid creating a new line since we do it ourself
125 | this.value = textBefore + "\n" + indent + textAfter;
126 | setCaretPosition(this, cursorPos + indent.length + 1); // +1 is for the \n
127 | }
128 | });
129 | }
130 |
131 | function setCaretPosition(ctrl, pos) {
132 | if(ctrl.setSelectionRange) {
133 | ctrl.focus();
134 | ctrl.setSelectionRange(pos,pos);
135 | }
136 | else if (ctrl.createTextRange) {
137 | var range = ctrl.createTextRange();
138 | range.collapse(true);
139 | range.moveEnd('character', pos);
140 | range.moveStart('character', pos);
141 | range.select();
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/parser/js/TreeModel.js:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | The MIT License (MIT)
4 |
5 | Copyright (c) 2013 João Nuno Silva
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in
15 | all copies or substantial portions of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 | THE SOFTWARE.
24 |
25 | */
26 |
27 | (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.TreeModel = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i 0;
95 | };
96 |
97 | function addChild(self, child, insertIndex) {
98 | var index;
99 |
100 | if (!(child instanceof Node)) {
101 | throw new TypeError('Child must be of type Node.');
102 | }
103 |
104 | child.parent = self;
105 | if (!(self.model[self.config.childrenPropertyName] instanceof Array)) {
106 | self.model[self.config.childrenPropertyName] = [];
107 | }
108 |
109 | if (hasComparatorFunction(self)) {
110 | // Find the index to insert the child
111 | index = findInsertIndex(
112 | self.config.modelComparatorFn,
113 | self.model[self.config.childrenPropertyName],
114 | child.model);
115 |
116 | // Add to the model children
117 | self.model[self.config.childrenPropertyName].splice(index, 0, child.model);
118 |
119 | // Add to the node children
120 | self.children.splice(index, 0, child);
121 | } else {
122 | if (insertIndex === undefined) {
123 | self.model[self.config.childrenPropertyName].push(child.model);
124 | self.children.push(child);
125 | } else {
126 | if (insertIndex < 0 || insertIndex > self.children.length) {
127 | throw new Error('Invalid index.');
128 | }
129 | self.model[self.config.childrenPropertyName].splice(insertIndex, 0, child.model);
130 | self.children.splice(insertIndex, 0, child);
131 | }
132 | }
133 | return child;
134 | }
135 |
136 | Node.prototype.addChild = function (child) {
137 | return addChild(this, child);
138 | };
139 |
140 | Node.prototype.addChildAtIndex = function (child, index) {
141 | if (hasComparatorFunction(this)) {
142 | throw new Error('Cannot add child at index when using a comparator function.');
143 | }
144 |
145 | return addChild(this, child, index);
146 | };
147 |
148 | Node.prototype.setIndex = function (index) {
149 | if (hasComparatorFunction(this)) {
150 | throw new Error('Cannot set node index when using a comparator function.');
151 | }
152 |
153 | if (this.isRoot()) {
154 | if (index === 0) {
155 | return this;
156 | }
157 | throw new Error('Invalid index.');
158 | }
159 |
160 | if (index < 0 || index >= this.parent.children.length) {
161 | throw new Error('Invalid index.');
162 | }
163 |
164 | var oldIndex = this.parent.children.indexOf(this);
165 |
166 | this.parent.children.splice(index, 0, this.parent.children.splice(oldIndex, 1)[0]);
167 |
168 | this.parent.model[this.parent.config.childrenPropertyName]
169 | .splice(index, 0, this.parent.model[this.parent.config.childrenPropertyName].splice(oldIndex, 1)[0]);
170 |
171 | return this;
172 | };
173 |
174 | Node.prototype.getPath = function () {
175 | var path = [];
176 | (function addToPath(node) {
177 | path.unshift(node);
178 | if (!node.isRoot()) {
179 | addToPath(node.parent);
180 | }
181 | })(this);
182 | return path;
183 | };
184 |
185 | Node.prototype.getIndex = function () {
186 | if (this.isRoot()) {
187 | return 0;
188 | }
189 | return this.parent.children.indexOf(this);
190 | };
191 |
192 | /**
193 | * Parse the arguments of traversal functions. These functions can take one optional
194 | * first argument which is an options object. If present, this object will be stored
195 | * in args.options. The only mandatory argument is the callback function which can
196 | * appear in the first or second position (if an options object is given). This
197 | * function will be saved to args.fn. The last optional argument is the context on
198 | * which the callback function will be called. It will be available in args.ctx.
199 | *
200 | * @returns Parsed arguments.
201 | */
202 | function parseArgs() {
203 | var args = {};
204 | if (arguments.length === 1) {
205 | if (typeof arguments[0] === 'function') {
206 | args.fn = arguments[0];
207 | } else {
208 | args.options = arguments[0];
209 | }
210 | } else if (arguments.length === 2) {
211 | if (typeof arguments[0] === 'function') {
212 | args.fn = arguments[0];
213 | args.ctx = arguments[1];
214 | } else {
215 | args.options = arguments[0];
216 | args.fn = arguments[1];
217 | }
218 | } else {
219 | args.options = arguments[0];
220 | args.fn = arguments[1];
221 | args.ctx = arguments[2];
222 | }
223 | args.options = args.options || {};
224 | if (!args.options.strategy) {
225 | args.options.strategy = 'pre';
226 | }
227 | if (!walkStrategies[args.options.strategy]) {
228 | throw new Error('Unknown tree walk strategy. Valid strategies are \'pre\' [default], \'post\' and \'breadth\'.');
229 | }
230 | return args;
231 | }
232 |
233 | Node.prototype.walk = function () {
234 | var args;
235 | args = parseArgs.apply(this, arguments);
236 | walkStrategies[args.options.strategy].call(this, args.fn, args.ctx);
237 | };
238 |
239 | walkStrategies.pre = function depthFirstPreOrder(callback, context) {
240 | var i, childCount, keepGoing;
241 | keepGoing = callback.call(context, this);
242 | for (i = 0, childCount = this.children.length; i < childCount; i++) {
243 | if (keepGoing === false) {
244 | return false;
245 | }
246 | keepGoing = depthFirstPreOrder.call(this.children[i], callback, context);
247 | }
248 | return keepGoing;
249 | };
250 |
251 | walkStrategies.post = function depthFirstPostOrder(callback, context) {
252 | var i, childCount, keepGoing;
253 | for (i = 0, childCount = this.children.length; i < childCount; i++) {
254 | keepGoing = depthFirstPostOrder.call(this.children[i], callback, context);
255 | if (keepGoing === false) {
256 | return false;
257 | }
258 | }
259 | keepGoing = callback.call(context, this);
260 | return keepGoing;
261 | };
262 |
263 | walkStrategies.breadth = function breadthFirst(callback, context) {
264 | var queue = [this];
265 | (function processQueue() {
266 | var i, childCount, node;
267 | if (queue.length === 0) {
268 | return;
269 | }
270 | node = queue.shift();
271 | for (i = 0, childCount = node.children.length; i < childCount; i++) {
272 | queue.push(node.children[i]);
273 | }
274 | if (callback.call(context, node) !== false) {
275 | processQueue();
276 | }
277 | })();
278 | };
279 |
280 | Node.prototype.all = function () {
281 | var args, all = [];
282 | args = parseArgs.apply(this, arguments);
283 | args.fn = args.fn || k(true);
284 | walkStrategies[args.options.strategy].call(this, function (node) {
285 | if (args.fn.call(args.ctx, node)) {
286 | all.push(node);
287 | }
288 | }, args.ctx);
289 | return all;
290 | };
291 |
292 | Node.prototype.first = function () {
293 | var args, first;
294 | args = parseArgs.apply(this, arguments);
295 | args.fn = args.fn || k(true);
296 | walkStrategies[args.options.strategy].call(this, function (node) {
297 | if (args.fn.call(args.ctx, node)) {
298 | first = node;
299 | return false;
300 | }
301 | }, args.ctx);
302 | return first;
303 | };
304 |
305 | Node.prototype.drop = function () {
306 | var indexOfChild;
307 | if (!this.isRoot()) {
308 | indexOfChild = this.parent.children.indexOf(this);
309 | this.parent.children.splice(indexOfChild, 1);
310 | this.parent.model[this.config.childrenPropertyName].splice(indexOfChild, 1);
311 | this.parent = undefined;
312 | delete this.parent;
313 | }
314 | return this;
315 | };
316 |
317 | return TreeModel;
318 | })();
319 |
320 | },{"find-insert-index":2,"mergesort":3}],2:[function(require,module,exports){
321 | module.exports = (function () {
322 | 'use strict';
323 |
324 | /**
325 | * Find the index to insert an element in array keeping the sort order.
326 | *
327 | * @param {function} comparatorFn The comparator function which sorted the array.
328 | * @param {array} arr The sorted array.
329 | * @param {object} el The element to insert.
330 | */
331 | function findInsertIndex(comparatorFn, arr, el) {
332 | var i, len;
333 | for (i = 0, len = arr.length; i < len; i++) {
334 | if (comparatorFn(arr[i], el) > 0) {
335 | break;
336 | }
337 | }
338 | return i;
339 | }
340 |
341 | return findInsertIndex;
342 | })();
343 |
344 | },{}],3:[function(require,module,exports){
345 | module.exports = (function () {
346 | 'use strict';
347 |
348 | /**
349 | * Sort an array using the merge sort algorithm.
350 | *
351 | * @param {function} comparatorFn The comparator function.
352 | * @param {array} arr The array to sort.
353 | * @returns {array} The sorted array.
354 | */
355 | function mergeSort(comparatorFn, arr) {
356 | var len = arr.length, firstHalf, secondHalf;
357 | if (len >= 2) {
358 | firstHalf = arr.slice(0, len / 2);
359 | secondHalf = arr.slice(len / 2, len);
360 | return merge(comparatorFn, mergeSort(comparatorFn, firstHalf), mergeSort(comparatorFn, secondHalf));
361 | } else {
362 | return arr.slice();
363 | }
364 | }
365 |
366 | /**
367 | * The merge part of the merge sort algorithm.
368 | *
369 | * @param {function} comparatorFn The comparator function.
370 | * @param {array} arr1 The first sorted array.
371 | * @param {array} arr2 The second sorted array.
372 | * @returns {array} The merged and sorted array.
373 | */
374 | function merge(comparatorFn, arr1, arr2) {
375 | var result = [], left1 = arr1.length, left2 = arr2.length;
376 | while (left1 > 0 && left2 > 0) {
377 | if (comparatorFn(arr1[0], arr2[0]) <= 0) {
378 | result.push(arr1.shift());
379 | left1--;
380 | } else {
381 | result.push(arr2.shift());
382 | left2--;
383 | }
384 | }
385 | if (left1 > 0) {
386 | result.push.apply(result, arr1);
387 | } else {
388 | result.push.apply(result, arr2);
389 | }
390 | return result;
391 | }
392 |
393 | return mergeSort;
394 | })();
395 |
396 | },{}]},{},[1])(1)
397 | });
398 |
--------------------------------------------------------------------------------
/parser/js/jquery-3.4.1.min.js:
--------------------------------------------------------------------------------
1 | /*! jQuery v3.4.1 | (c) JS Foundation and other contributors | jquery.org/license */
2 | !function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],E=C.document,r=Object.getPrototypeOf,s=t.slice,g=t.concat,u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.4.1",k=function(e,t){return new k.fn.init(e,t)},p=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;function d(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp($),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+$),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ne=function(e,t,n){var r="0x"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(m.childNodes),m.childNodes),t[m.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&((e?e.ownerDocument||e:m)!==C&&T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!A[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&U.test(t)){(s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=k),o=(l=h(t)).length;while(o--)l[o]="#"+s+" "+xe(l[o]);c=l.join(","),f=ee.test(t)&&ye(e.parentNode)||e}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){A(t,!0)}finally{s===k&&e.removeAttribute("id")}}}return g(t.replace(B,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[k]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:m;return r!==C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),m!==C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=k,!C.getElementsByName||!C.getElementsByName(k).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+k+"-]").length||v.push("~="),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+k+"+*").length||v.push(".#.+[+~]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",$)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e===C||e.ownerDocument===m&&y(m,e)?-1:t===C||t.ownerDocument===m&&y(m,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===C?-1:t===C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]===m?-1:s[r]===m?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if((e.ownerDocument||e)!==C&&T(e),d.matchesSelector&&E&&!A[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){A(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=p[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&p(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?k.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?k.grep(e,function(e){return e===n!==r}):"string"!=typeof n?k.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(k.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:L.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof k?t[0]:t,k.merge(this,k.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),D.test(r[1])&&k.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(k):k.makeArray(e,this)}).prototype=k.fn,q=k(E);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}k.fn.extend({has:function(e){var t=k(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,""],thead:[1,"