Repo wipe moving to V2
This commit is contained in:
		
							parent
							
								
									a0d2903141
								
							
						
					
					
						commit
						1c0dc989e9
					
				
					 28 changed files with 0 additions and 15358 deletions
				
			
		
							
								
								
									
										18
									
								
								README.md
									
										
									
									
									
								
							
							
						
						
									
										18
									
								
								README.md
									
										
									
									
									
								
							|  | @ -1,18 +0,0 @@ | |||
| # My Spells | ||||
| ...is a user friendly mobile responsive app designed to do one thing well: _View Spells_. | ||||
| 
 | ||||
| [Check it out on github.io](https://sharpshark28.github.io/my_spells/)! | ||||
| 
 | ||||
| ## Systems Supported | ||||
| * Dungeons & Dragons 5e | ||||
| * Hackmaster 4e (WIP) | ||||
| 
 | ||||
| ### Will you support _X_ system? | ||||
| Anyone who wishes to write up spells for a system in json format matching the same syntax used by the existing systems in this repo is welcome to add their system of choice. | ||||
| 
 | ||||
| ## For Developers | ||||
| 1. Clone/Fork Repo | ||||
| 2. `npm install` | ||||
| 3. `npm run develop` | ||||
| 
 | ||||
| You may wish to run a local http server such as [http-server](https://github.com/indexzero/http-server). | ||||
							
								
								
									
										
											BIN
										
									
								
								assets/.DS_Store
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								assets/.DS_Store
									
										
									
									
										vendored
									
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										231
									
								
								assets/app.css
									
										
									
									
									
								
							
							
						
						
									
										231
									
								
								assets/app.css
									
										
									
									
									
								
							|  | @ -1,231 +0,0 @@ | |||
| body { | ||||
|     background: #fafafa; | ||||
| } | ||||
| 
 | ||||
| [data-action=print], | ||||
| .printonly { | ||||
|     display: none; | ||||
| } | ||||
| 
 | ||||
| .mdl-mini-footer { | ||||
|     position: fixed; | ||||
|     bottom: 0; | ||||
|     left: 0; | ||||
|     right: 0; | ||||
|     z-index: 1; | ||||
|     padding: .5em 1em .75em 1em | ||||
| } | ||||
| 
 | ||||
| .do-nothing { | ||||
|     pointer-events: none; | ||||
| } | ||||
| 
 | ||||
| .mdl-layout-title i { | ||||
|     position: relative; | ||||
|     bottom: -.125em; | ||||
| } | ||||
| 
 | ||||
| #empty { | ||||
|     padding-bottom: 100%; | ||||
|     text-align: center; | ||||
|     background: url('wand.svg') no-repeat top center; | ||||
| } | ||||
| 
 | ||||
| .mdl-layout__header .mdl-button .mdl-badge[data-badge] { | ||||
|     margin-right: 0; | ||||
| } | ||||
| 
 | ||||
| .mdl-layout__header .mdl-button .mdl-badge[data-badge]::after { | ||||
|     left: -1em; | ||||
|     right: auto; | ||||
| } | ||||
| 
 | ||||
| .mdl-navigation .mdl-textfield__label i { | ||||
|     vertical-align: top; | ||||
|     font-size: 1.25em; | ||||
| } | ||||
| 
 | ||||
| .mdl-navigation .mdl-textfield__input { | ||||
|     box-sizing: border-box; | ||||
|     padding-left: 1em; | ||||
|     padding-right: 1em; | ||||
| } | ||||
| 
 | ||||
| .mdl-navigation .mdl-textfield__label { | ||||
|     padding-left: 1em; | ||||
| } | ||||
| 
 | ||||
| ul, | ||||
| ol { | ||||
|     padding: 0 1em; | ||||
| } | ||||
| 
 | ||||
| .text-center { | ||||
|     text-align: center; | ||||
| } | ||||
| 
 | ||||
| .left { | ||||
|     float: left; | ||||
| } | ||||
| 
 | ||||
| .right { | ||||
|     float: right; | ||||
| } | ||||
| 
 | ||||
| .page-content { | ||||
|     position: relative; | ||||
| } | ||||
| 
 | ||||
| .page-content .mdl-grid { | ||||
|     padding: 0; | ||||
| } | ||||
| 
 | ||||
| .page-content .mdl-cell { | ||||
|     margin: 0; | ||||
| } | ||||
| 
 | ||||
| [data-template=spell-details] { | ||||
|     transition: margin-top 500ms ease-out; | ||||
|     padding: 0 2rem; | ||||
| } | ||||
| 
 | ||||
| #description { | ||||
|     margin: 0; | ||||
|     max-height: 13em; | ||||
|     overflow: auto; | ||||
| } | ||||
| 
 | ||||
| #description br:last-of-type { | ||||
|     display: none; | ||||
| } | ||||
| 
 | ||||
| #description p:last-of-type { | ||||
|     margin-bottom: 0; | ||||
| } | ||||
| 
 | ||||
| #copy { | ||||
|     width: 100%; | ||||
| } | ||||
| 
 | ||||
| #details { | ||||
|     columns: 2; | ||||
|     padding: 0; | ||||
|     list-style-type: none; | ||||
| } | ||||
| 
 | ||||
| #details strong { | ||||
|     text-transform: capitalize; | ||||
| } | ||||
| 
 | ||||
| .mdl-layout__header [data-action-details=""] { | ||||
|     display: none; | ||||
|     position: absolute; | ||||
|     left: 0; | ||||
|     z-index: 10; | ||||
|     height: 4rem; | ||||
|     width: 4rem; | ||||
| } | ||||
| 
 | ||||
| .mdl-layout__header [data-action-details=""] i { | ||||
|     position: absolute; | ||||
|     top: 1rem; | ||||
|     left: 1rem; | ||||
| } | ||||
| 
 | ||||
| [data-template=spell-details] [data-action-details=""] { | ||||
|     position: absolute; | ||||
|     top: .5rem; | ||||
|     right: .5rem; | ||||
| } | ||||
| 
 | ||||
| @media (max-width: 840px) { | ||||
|     .hide-phone { | ||||
|         display: none; | ||||
|     } | ||||
| 
 | ||||
|     [data-template=spell-details] { | ||||
|         margin-top: 0 !important; | ||||
|     } | ||||
| 
 | ||||
|     #spell-list-container, | ||||
|     [data-template=spell-details] { | ||||
|         transition: left 250ms; | ||||
|     } | ||||
| 
 | ||||
|     #spell-list-container { | ||||
|         position: absolute; | ||||
|         width: 100%; | ||||
|         left: 0; | ||||
|     } | ||||
| 
 | ||||
|     body.details #spell-list-container { | ||||
|         left: -95%; | ||||
|     } | ||||
| 
 | ||||
|     body.details #spell-list-container::after { | ||||
|         content: ''; | ||||
|         position: absolute; | ||||
|         left: 0; | ||||
|         top: 0; | ||||
|         right: 0; | ||||
|         bottom: 0; | ||||
|         background: black; | ||||
|         opacity: .25; | ||||
|     } | ||||
| 
 | ||||
|     [data-template=spell-details] { | ||||
|         position: fixed; | ||||
|         width: 95%; | ||||
|         left: 100%; | ||||
|         overflow: auto; | ||||
|         max-height: calc(100% - 56px) | ||||
|     } | ||||
| 
 | ||||
|     body.details [data-template=spell-details] { | ||||
|         left: 5%; | ||||
|     } | ||||
| 
 | ||||
|     body.details .mdl-layout__header [data-action-details=""] { | ||||
|         display: block; | ||||
|     } | ||||
| 
 | ||||
|     body.details .mdl-layout__header .mdl-layout__drawer-button { | ||||
|         display: none; | ||||
|     } | ||||
| 
 | ||||
|     body.details [data-template=spell-details] [data-action-details=""] { | ||||
|         display: none; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| [data-action-details] { | ||||
|     cursor: pointer; | ||||
| } | ||||
| 
 | ||||
| [data-action-sort], | ||||
| [data-template=class-list] label, | ||||
| .classes, | ||||
| .spell-level, | ||||
| .spell-name, | ||||
| .spell-school { | ||||
|     text-transform: capitalize; | ||||
| } | ||||
| 
 | ||||
| [data-action-sort] { | ||||
|     cursor: pointer; | ||||
|     user-select: none; | ||||
| } | ||||
| 
 | ||||
| [data-action-sort]:hover { | ||||
|     background: #eee; | ||||
| } | ||||
| 
 | ||||
| [data-action-sort] i.material-icons.mdl-list__item-icon { | ||||
|     position: relative; | ||||
|     bottom: -.25em; | ||||
|     color: inherit; | ||||
| } | ||||
| 
 | ||||
| #share-url { | ||||
|     padding-left: 2em; | ||||
| } | ||||
|  | @ -1,45 +0,0 @@ | |||
| @media print { | ||||
|     body { | ||||
|         background: white; | ||||
|         font-size: 11pt; | ||||
|         box-sizing: border-box; | ||||
|         padding: 1em; | ||||
|     } | ||||
| 
 | ||||
|     body > .printonly { | ||||
|         display: block; | ||||
|     } | ||||
| 
 | ||||
|     body > :not(.printonly) { | ||||
|         display: none; | ||||
|     } | ||||
| 
 | ||||
|     th { | ||||
|         white-space: nowrap; | ||||
|         padding: 1em 1em 1em 0; | ||||
|         text-align: left; | ||||
|     } | ||||
| 
 | ||||
|     td { | ||||
|         vertical-align: top; | ||||
|     } | ||||
| 
 | ||||
|     .spell-description p { | ||||
|         font-size: 8pt; | ||||
|         line-height: 10pt; | ||||
|         margin: .75em 0; | ||||
|         color: gray; | ||||
|     } | ||||
| 
 | ||||
|     .spell-description br { | ||||
|         display: none; | ||||
|     } | ||||
| 
 | ||||
|     #details { | ||||
|         font-size: 8pt; | ||||
|         margin: 0; | ||||
|         columns: 3; | ||||
|         padding: 0; | ||||
|         list-style-type: none; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										123
									
								
								assets/wand.svg
									
										
									
									
									
								
							
							
						
						
									
										123
									
								
								assets/wand.svg
									
										
									
									
									
								
							|  | @ -1,123 +0,0 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  --> | ||||
| <svg version="1.1" | ||||
| 	 id="svg7404" xmlns:svg="http://www.w3.org/2000/svg" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||
| 	 xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="232 -592.3 824.9 1155" | ||||
| 	 style="enable-background:new 232 -592.3 824.9 1155;" xml:space="preserve"> | ||||
| <style type="text/css"> | ||||
| 	.st0{fill:#EDF9F7;} | ||||
| 	.st1{fill:#7BCBBF;} | ||||
| 	.st2{fill:#9BD8D0;} | ||||
| 	.st3{fill:#CBE9E4;} | ||||
| 	.st4{fill:#6EC3BB;} | ||||
| 	.st5{fill:#FFFFFF;} | ||||
| 	.st6{fill:#EED7B2;} | ||||
| 	.st7{fill:#DAC4BF;} | ||||
| 	.st8{fill:#CCDBB9;} | ||||
| 	.st9{fill:#DBEFBE;} | ||||
| 	.st10{fill:#D4E6BC;} | ||||
| 	.st11{fill:#F9FBF5;} | ||||
| 	.st12{fill:#D6C2BE;} | ||||
| 	.st13{fill:#E0E4DD;} | ||||
| 	.st14{fill:#B3D3C8;} | ||||
| 	.st15{fill:#9FCABF;} | ||||
| 	.st16{fill:#D3DBD9;} | ||||
| 	.st17{fill:#A6C9C4;} | ||||
| 	.st18{fill:#BCD1CD;} | ||||
| 	.st19{fill:#92C0BB;} | ||||
| 	.st20{fill:#DFEAE9;} | ||||
| </style> | ||||
| <g> | ||||
| 	<path class="st0" d="M544.6-229L544.6-229L544.6-229 M501.7-241.2L501.7-241.2l-19.1,22.8l31.1,13c0.1-1.1,0.4-2.1,1.1-2.9 | ||||
| 		c1-1.2,2.4-1.8,4-1.8c1.4,0,2.9,0.5,4.1,1.5c0.9,0.7,1.5,1.6,1.9,2.6l19.4-23.3L501.7-241.2"/> | ||||
| 	<polyline class="st1" points="474.8,-209.1 447.4,-176.2 466.8,-136.4 489.6,-163.7 465.5,-197.8 474.9,-209.1 474.8,-209.1 	"/> | ||||
| 	<path class="st2" d="M544.5-229.4l-0.2,0.2l-19.4,23.3c0.7,1.8,0.5,3.9-0.7,5.4c-0.3,0.4-0.7,0.7-1.1,0.9l21.1,32.6l19.3-23.1 | ||||
| 		L544.6-229l0,0L544.5-229.4"/> | ||||
| 	<polyline class="st3" points="489.9,-163.8 489.7,-163.6 489.6,-163.7 466.8,-136.4 466.7,-136.2 508.6,-124.3 508.6,-124.3  | ||||
| 		527,-146.3 489.9,-163.8 	"/> | ||||
| 	<path class="st2" d="M482.6-218.4l-7.8,9.3l-9.4,11.3l24.2,34.1l0.1,0.1l0.2-0.2l-0.2-0.1l29.3-35c-1-0.2-2-0.7-2.9-1.4 | ||||
| 		c-1.6-1.3-2.4-3.3-2.3-5.1L482.6-218.4L482.6-218.4"/> | ||||
| 	<path class="st4" d="M523.1-199.6c-0.8,0.6-1.9,0.8-2.9,0.8c-0.4,0-0.8,0-1.2-0.1l-29.3,35l0.2,0.1l37.1,17.5l8.2-9.7l9.1-10.9 | ||||
| 		L523.1-199.6"/> | ||||
| 	<path class="st5" d="M518.9-210c-1.5,0-3,0.6-4,1.8c-0.7,0.8-1.1,1.9-1.1,2.9c-0.1,1.8,0.7,3.7,2.3,5.1c0.9,0.7,1.9,1.2,2.9,1.4 | ||||
| 		c0.4,0.1,0.8,0.1,1.2,0.1c1,0,2.1-0.3,2.9-0.8c0.4-0.3,0.7-0.6,1.1-0.9c1.2-1.5,1.4-3.5,0.7-5.4c-0.4-1-1-1.9-1.9-2.6 | ||||
| 		C521.7-209.5,520.3-210,518.9-210"/> | ||||
| 	<path class="st6" d="M874.4,91.9c-2,9.3-4.7,18-7.1,25.7l133.5,111.7l-2.3,2.7l0,0l13.2-15.9L874.4,91.9 M577.3-176.6l2.2,53.4 | ||||
| 		L624-86.1c4.1-1.9,9-2.9,14.2-2.9c3.2,0,6.5,0.4,9.6,1.2c13,3.4,19.8,12.9,15,21.2c-0.3,0.5-0.6,1-1,1.5c-0.7,2.4-1.5,5.5-2.1,8.9 | ||||
| 		L839.8,94.6c0-0.9,0-1.9-0.1-2.8l0,0c0,0,0,0,0,0c0.3-13.5,2-27.5-1.3-32.3L577.3-176.6"/> | ||||
| 	<path class="st7" d="M867.3,117.6c-2.8,8.9-5.1,16.4-5.1,21.9c-0.1,3.7,0.4,6.8,1.2,9.5L987.6,245l10.9-13.1l2.3-2.7L867.3,117.6 | ||||
| 		 M659.7-56.2c-3,16.4-2.7,42.8,21.9,63.4c2.2,1.8,4.6,3.4,7,4.5l67.1,52.1l0,0c-0.5,0.2-1,0.4-1.5,0.7l87.3,67.6 | ||||
| 		c-0.9-10.2-1.3-22.6-1.7-37.4L659.7-56.2 M579.6-123.3l0.1,2.5l-55.1,7.4L614-44.1c-0.6-5.7-0.7-10.8-0.7-15 | ||||
| 		c0-8.5,0.7-13.6,0.7-13.6s0-0.1,0.1-0.3c-0.1-2,0.4-4,1.5-6c1.7-3,4.7-5.4,8.4-7.1L579.6-123.3"/> | ||||
| 	<path class="st8" d="M839.8,91.7L839.8,91.7c0,1,0,1.9,0.1,2.8c0.4,14.8,0.8,27.2,1.7,37.4c1.9,21.5,6,33.3,17.1,36.7 | ||||
| 		c3.4,1.1,6.4,1.5,9,1.5c4.4,0,7.6-1.2,9.9-2.6c-2.3,1.4-5.5,2.6-9.9,2.6c-2.6,0-5.6-0.4-9-1.5C841.9,163.6,841,139.4,839.8,91.7 | ||||
| 		 M806.6-3.9c-10.8,0-21.9,2-32.8,4.7l23.9,21.6c1,0,2.1-0.1,3.1-0.1c21.4,0,38,9.1,49.3,22.5c12.8,15.3,3.1,56.1,3.9,79 | ||||
| 		c0.9,22.4-5.4,36.8,27.2,40.6c0.4-0.5,0.6-0.8,0.6-0.8s-14.1-0.8-18.4-14.8c-0.8-2.7-1.3-5.8-1.2-9.5c0.1-5.4,2.4-13,5.1-21.9 | ||||
| 		c2.4-7.7,5.1-16.4,7.1-25.7c5.4-25.7,5-55.8-24.9-80.8C836.3,0,821.7-3.9,806.6-3.9 M613.2-59.1c0,4.2,0.2,9.3,0.7,15 | ||||
| 		c2.5,25.9,12.6,64.3,47.8,93.6c20.4,17,39.5,23,56.7,23c13.2,0,25.2-3.5,35.8-8.1c0.5-0.2,1-0.4,1.5-0.7l0,0 | ||||
| 		c-10.9,4.9-23.5,8.7-37.2,8.7c-17.2,0-36.3-5.9-56.7-23C618.9,13.7,613.2-35.6,613.2-59.1 M661.9-65.1c-4.1,5.4-12.5,8.6-21.6,8.6 | ||||
| 		c-1.7,0-3.4-0.1-5.1-0.3c-0.8,25.1,5.1,61.8,29.9,82.4c10.6,8.8,25.2,11.8,40.9,11.8c4.8,0,9.7-0.3,14.7-0.8l35,27.1l-67.1-52.1 | ||||
| 		c-2.3-1.1-4.7-2.6-7-4.5c-24.6-20.5-24.9-46.9-21.9-63.4C660.3-59.7,661.1-62.7,661.9-65.1"/> | ||||
| 	<path class="st9" d="M800.8,22.4c-1,0-2.1,0-3.1,0.1c0,0-0.1,0-0.1,0l40,36c0.3,0.3,0.6,0.6,0.8,0.9c3.3,4.9,1.6,18.9,1.3,32.3l0,0 | ||||
| 		c1.2,47.7,2.2,71.8,18.9,77c3.4,1.1,6.4,1.5,9,1.5c4.4,0,7.6-1.2,9.9-2.6c1.8-1.1,3-2.3,3.7-3.1c0,0,0,0,0,0 | ||||
| 		c-32.6-3.8-26.3-18.2-27.2-40.6c-0.8-22.9,8.9-63.7-3.9-79C838.8,31.5,822.2,22.4,800.8,22.4 M614.1-73c-0.1,0.2-0.1,0.3-0.1,0.3 | ||||
| 		s-0.7,5.1-0.7,13.6c0,23.6,5.7,72.8,48.5,108.6c20.4,17,39.5,23,56.7,23c13.8,0,26.3-3.8,37.2-8.7l0,0l-35-27.1 | ||||
| 		c-4.9,0.5-9.9,0.8-14.7,0.8c-15.7,0-30.3-3.1-40.9-11.8c-24.8-20.7-30.8-57.4-29.9-82.4c-1.5-0.2-3-0.5-4.5-0.9 | ||||
| 		C620.6-60.3,614.3-66.5,614.1-73"/> | ||||
| 	<path class="st10" d="M638.2-59.6c-2,0-4.1-0.7-5.9-2.2c-3.7-3.1-4.4-8.2-1.7-11.4c1.4-1.7,3.5-2.5,5.7-2.5c2,0,4.1,0.7,5.9,2.2 | ||||
| 		c3.7,3.1,4.4,8.2,1.7,11.4C642.5-60.5,640.4-59.6,638.2-59.6 M638.2-89c-5.2,0-10.1,1-14.2,2.9c-3.7,1.7-6.7,4.2-8.4,7.1 | ||||
| 		c-1.1,2-1.6,4-1.5,6c0.3,6.5,6.6,12.7,16.5,15.3c1.5,0.4,3,0.7,4.5,0.9c1.7,0.2,3.4,0.3,5.1,0.3c9.1,0,17.5-3.2,21.6-8.6 | ||||
| 		c0.4-0.5,0.7-1,1-1.5c4.7-8.3-2-17.8-15-21.2C644.6-88.6,641.4-89,638.2-89"/> | ||||
| 	<path class="st11" d="M636.3-75.8c-2.2,0-4.3,0.9-5.7,2.5c-2.7,3.3-2,8.4,1.7,11.4c1.8,1.5,3.9,2.2,5.9,2.2c2.2,0,4.3-0.9,5.7-2.5 | ||||
| 		c2.7-3.3,2-8.4-1.7-11.4C640.5-75.1,638.4-75.8,636.3-75.8"/> | ||||
| 	<polyline class="st12" points="577.3,-178.5 549.7,-145.7 522.2,-113.1 524.5,-113.4 579.7,-120.8 579.6,-123.3 577.3,-176.6  | ||||
| 		577.3,-178.5 	"/> | ||||
| 	<polyline class="st13" points="563.6,-190 563.5,-190 564.1,-188.9 537.9,-157.6 550.6,-147 577.1,-178.7 563.6,-190 	"/> | ||||
| 	<polyline class="st14" points="563.5,-190 544.2,-166.9 544.4,-166.7 537.2,-158.2 537.9,-157.6 564.1,-188.9 563.5,-190 	"/> | ||||
| 	<polyline class="st15" points="544.2,-166.9 535.1,-156 537,-158.3 537.2,-158.2 544.4,-166.7 544.2,-166.9 	"/> | ||||
| 	<polyline class="st16" points="537.9,-157.6 536.7,-156.1 536.7,-156.1 509.7,-124 508.6,-124.3 522.1,-113 550.6,-147  | ||||
| 		537.9,-157.6 	"/> | ||||
| 	<polyline class="st17" points="537.2,-158.2 536.6,-157.4 537.3,-156.8 536.7,-156.1 536.7,-156.1 537.9,-157.6 537.2,-158.2 	"/> | ||||
| 	<polyline class="st18" points="536.6,-157.4 527.2,-146.2 527,-146.3 508.6,-124.3 508.6,-124.3 509.7,-124 536.7,-156.1  | ||||
| 		537.3,-156.8 536.6,-157.4 	"/> | ||||
| 	<polyline class="st19" points="537,-158.3 535.1,-156 527,-146.3 527.2,-146.2 536.6,-157.4 537.2,-158.2 537,-158.3 	"/> | ||||
| 	<polygon class="st20" points="362.8,-106.5 366.8,-137.1 394.1,-151.2 366.3,-164.3 361.4,-194.7 340.3,-172.4 309.9,-177.1  | ||||
| 		324.6,-150 310.7,-122.6 341,-128.3 	"/> | ||||
| 	<polygon class="st20" points="394.7,-386.8 409.4,-403.2 431.2,-400.3 420.2,-419.4 429.7,-439.2 408.2,-434.6 392.3,-449.7  | ||||
| 		390,-427.9 370.7,-417.4 390.7,-408.5 	"/> | ||||
| 	<polygon class="st20" points="457,20.4 461.6,-14.7 493.1,-30.9 461.1,-46.1 455.4,-81.1 431,-55.3 396,-60.7 413,-29.6 397,2  | ||||
| 		431.8,-4.5 	"/> | ||||
| 	<polygon class="st20" points="634.6,-418.3 636.7,-434.1 650.9,-441.4 636.5,-448.2 633.9,-463.9 623,-452.4 607.2,-454.8  | ||||
| 		614.9,-440.8 607.7,-426.6 623.3,-429.5 	"/> | ||||
| 	<polygon class="st20" points="803.5,-10.6 800.3,-33.9 817.8,-49.6 794.6,-53.9 785,-75.3 773.8,-54.7 750.5,-52.1 766.7,-35.1  | ||||
| 		761.9,-12.1 783.1,-22.3 	"/> | ||||
| 	<polygon class="st20" points="608.2,41.7 610.5,23.5 626.9,15.1 610.3,7.2 607.4,-10.9 594.7,2.5 576.6,-0.4 585.4,15.8  | ||||
| 		577.1,32.1 595.1,28.8 	"/> | ||||
| 	<polygon class="st20" points="267.8,88.3 269.8,72.5 284,65.2 269.6,58.4 267,42.6 256.1,54.2 240.4,51.8 248,65.8 240.8,80  | ||||
| 		256.5,77.1 	"/> | ||||
| 	<polygon class="st20" points="489.7,348 497.5,334.2 513.4,332.8 502.6,321 506.2,305.5 491.7,312.1 478,303.9 479.8,319.7  | ||||
| 		467.8,330.2 483.4,333.4 	"/> | ||||
| 	<polygon class="st20" points="989.4,-441.9 997.3,-455.7 1013.1,-457.1 1002.4,-468.9 1005.9,-484.4 991.4,-477.8 977.8,-486  | ||||
| 		979.6,-470.2 967.5,-459.7 983.2,-456.5 	"/> | ||||
| 	<polygon class="st20" points="934.4,137.9 939.1,126.4 951.4,123.8 941.9,115.7 943.1,103.3 932.5,109.8 921.1,104.8 924,116.9  | ||||
| 		915.7,126.2 928.2,127.1 	"/> | ||||
| 	<polygon class="st20" points="326.5,108.6 324.9,96.3 334.1,87.9 321.8,85.6 316.8,74.3 310.8,85.2 298.5,86.6 307.1,95.6  | ||||
| 		304.5,107.8 315.7,102.4 	"/> | ||||
| 	<polygon class="st20" points="530.6,104.7 532,93.7 541.9,88.7 531.9,83.9 530.1,73 522.5,81 511.6,79.3 516.9,89 511.9,98.9  | ||||
| 		522.7,96.9 	"/> | ||||
| 	<polygon class="st20" points="742.1,-272 745.1,-282.7 755.5,-286.3 746.3,-292.4 746.1,-303.5 737.4,-296.6 726.8,-299.8  | ||||
| 		730.7,-289.5 724.3,-280.4 735.4,-280.9 	"/> | ||||
| 	<polygon class="st20" points="939.7,-208.2 950.1,-211.9 959.1,-205.5 958.7,-216.6 967.5,-223.3 956.9,-226.3 953.4,-236.7  | ||||
| 		947.2,-227.6 936.1,-227.4 943,-218.7 	"/> | ||||
| 	<polygon class="st20" points="825.7,-570.5 829.8,-574.5 835.4,-573.5 832.8,-578.6 835.5,-583.7 829.9,-582.8 825.9,-587  | ||||
| 		825,-581.3 819.8,-578.8 824.9,-576.2 	"/> | ||||
| 	<polygon class="st20" points="862.9,475.8 867,471.8 872.6,472.8 870,467.7 872.7,462.6 867.1,463.5 863.1,459.3 862.2,465  | ||||
| 		857,467.5 862.1,470.1 	"/> | ||||
| 	<polygon class="st20" points="503.3,-554 507.4,-558 513.1,-557 510.5,-562.1 513.2,-567.2 507.5,-566.3 503.6,-570.5  | ||||
| 		502.7,-564.8 497.4,-562.3 502.6,-559.7 	"/> | ||||
| 	<polygon class="st20" points="706.5,302 710.6,297.9 716.3,299 713.6,293.8 716.4,288.7 710.7,289.6 706.7,285.5 705.8,291.1  | ||||
| 		700.6,293.6 705.7,296.2 	"/> | ||||
| 	<polygon class="st20" points="328,488.5 333.8,487.9 337.6,492.2 338.7,486.5 344,484.2 339,481.4 338.4,475.7 334.2,479.6  | ||||
| 		328.6,478.3 331,483.6 	"/> | ||||
| </g> | ||||
| </svg> | ||||
| Before Width: | Height: | Size: 9.2 KiB | 
							
								
								
									
										418
									
								
								dist/app.js
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										418
									
								
								dist/app.js
									
										
									
									
										vendored
									
									
								
							|  | @ -1,418 +0,0 @@ | |||
| /** | ||||
|  * Misc helper functions | ||||
|  */ | ||||
| Object.values = x => Object.keys(x).reduce((y, z) => y.push(x[z]) && y, []); | ||||
| const debounce = (func, wait, immediate) => { | ||||
|     let timeout; | ||||
|     return function () { | ||||
|         let context = this, | ||||
|             args = arguments; | ||||
|         let later = function () { | ||||
|             timeout = null; | ||||
|             if (!immediate) func.apply(context, args); | ||||
|         }; | ||||
|         let callNow = immediate && !timeout; | ||||
|         clearTimeout(timeout); | ||||
|         timeout = setTimeout(later, wait); | ||||
|         if (callNow) func.apply(context, args); | ||||
|     }; | ||||
| }; | ||||
| const el = id => $(`[data-template=${ id }]`)[0] || console.error('Unable to render to', id); | ||||
| const clone = obj => JSON.parse(JSON.stringify(obj)); | ||||
| const basicDetails = ['level', 'range', 'duration', 'casting_time', 'saving_throw', 'aoe', 'source']; | ||||
| 
 | ||||
| /** | ||||
|  * Global store and view holders | ||||
|  */ | ||||
| let view = {}; | ||||
| let store = { | ||||
|     systems: { | ||||
|         data: [{ | ||||
|             friendly: 'Dungeons & Dragons 5e', | ||||
|             value: 'dnd5e' | ||||
|         }, { | ||||
|             friendly: 'HackMaster 4e (WIP)', | ||||
|             value: 'hackmaster4e' | ||||
|         }] | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * See Matching System Friendly and Value | ||||
|  */ | ||||
| const matchingSystemProp = (system, requested) => store.systems.data.find(d => d[requested === 'value' ? 'friendly' : 'value'] === system)[requested]; | ||||
| 
 | ||||
| /** | ||||
|  * Init Local Storage | ||||
|  */ | ||||
| const localStorageDefault = (key, val) => { | ||||
|     if (localStorage.getItem(key) === null) localStorage.setItem(key, val); | ||||
| }; | ||||
| let defaults = { | ||||
|     tableSortName: 'name', | ||||
|     tableSortRev: false, | ||||
|     system: 'dnd5e', | ||||
|     classes: [], | ||||
|     search: '' | ||||
| }; | ||||
| for (let cur in defaults) localStorageDefault(cur, defaults[cur]); | ||||
| 
 | ||||
| if (window.location.hash) { | ||||
|     let urlSystem = window.location.hash.substr(1).split('/')[0]; | ||||
|     localStorage.setItem('system', store.systems.data.find(d => d.value === urlSystem).value); | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Render Table Sort | ||||
|  */ | ||||
| store.tableSort = { | ||||
|     data: ['name', 'school', 'level'], | ||||
|     current: localStorage.getItem('tableSortName'), | ||||
|     rev: localStorage.getItem('tableSortRev') !== 'false' | ||||
| }; | ||||
| view.table_sort = Monkberry.render(table_sort, el('table-sort')); | ||||
| view.table_sort.update(store.tableSort); | ||||
| 
 | ||||
| /** | ||||
|  * Render Systems | ||||
|  */ | ||||
| store.systems.current = matchingSystemProp(localStorage.getItem('system'), 'friendly'); | ||||
| view.systems_list = Monkberry.render(system_list, el('system-list')); | ||||
| view.systems_list.update(store.systems); | ||||
| 
 | ||||
| /** | ||||
|  * Render Spell List | ||||
|  */ | ||||
| view.spell_list = Monkberry.render(spell_list, el('spell-list')); | ||||
| view.spell_list.update({ data: false }); | ||||
| 
 | ||||
| /** | ||||
|  * Render Spell Print List | ||||
|  */ | ||||
| view.spell_list_print = Monkberry.render(spell_list_print, el('spell-list-print')); | ||||
| view.spell_list_print.update({}); | ||||
| 
 | ||||
| /** | ||||
|  * Render Spell Details | ||||
|  */ | ||||
| view.spell_details = Monkberry.render(spell_details, el('spell-details')); | ||||
| view.spell_details.update({ data: {} }); | ||||
| 
 | ||||
| /** | ||||
|  * Render Class List | ||||
|  */ | ||||
| store.classes = { | ||||
|     data: [], | ||||
|     current: localStorage.getItem('classes') ? localStorage.getItem('classes').split(',') : [] | ||||
| }; | ||||
| view.class_list = Monkberry.render(class_list, el('class-list')); | ||||
| view.class_list.update({ data: false }); | ||||
| 
 | ||||
| /** | ||||
|  * Render Search | ||||
|  */ | ||||
| store.search = localStorage.getItem('search'); | ||||
| view.search_field = Monkberry.render(search_field, el('search-field')); | ||||
| view.search_field.update({ data: store.search }); | ||||
| 
 | ||||
| /** | ||||
|  * Discover Classes | ||||
|  */ | ||||
| const discoverClasses = spells => { | ||||
|     let classes = []; | ||||
|     spells.forEach(spell => { | ||||
|         if (!spell.classes) return; | ||||
|         spell.classes.forEach(current => { | ||||
|             if (!classes.includes(current)) classes.push(current); | ||||
|         }); | ||||
|     }); | ||||
|     return classes.sort((a, b) => a > b); | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Emphasis on important string bits | ||||
|  * @param {string} string | ||||
|  */ | ||||
| const emphasis = (str = '') => { | ||||
|     let keywords = ['constitution', 'con', 'intelligence', 'int', 'wisdom', 'wis', 'strength', 'str', 'dexterity', 'dex', 'charisma', 'cha', 'comeliness', 'com', 'saving throw', 'ability check', 'skill check']; | ||||
|     keywords.forEach(word => { | ||||
|         let r = new RegExp(` ${ word } `, 'gi'); | ||||
|         str = str.replace(r, o => ` _${ o.trim() }_ `); | ||||
|     }); | ||||
| 
 | ||||
|     str = str.replace(/[\s()<>]+\d+d*\d*(th)*[\s()<>]+/gi, o => ` **${ o.trim() }** `); | ||||
|     return str; | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Description Prettifier | ||||
|  */ | ||||
| const descriptionPrettifier = description => { | ||||
|     let md = new Remarkable(); | ||||
|     description = Array.isArray(description) ? description.join('\n') : description; | ||||
|     description = emphasis(description); | ||||
|     description = md.render(description); | ||||
|     description = description.replace(/\n/g, '<br>'); | ||||
| 
 | ||||
|     return description; | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Init Spells | ||||
|  */ | ||||
| const initSpells = s => s.map((spell, i) => { | ||||
|     spell.selected = false; | ||||
|     spell.ranking = 0; | ||||
|     spell.level = parseInt(spell.level) ? spell.level : 0; | ||||
|     return spell; | ||||
| }); | ||||
| 
 | ||||
| /** | ||||
|  * Sort Spells | ||||
|  */ | ||||
| const sortSpells = (s, sortBy, reverse) => s.sort((a, b) => { | ||||
|     let hasFilters = store.classes.current.length || store.search.length; | ||||
|     let by = sortBy || hasFilters ? 'ranking' : store.tableSort.current; | ||||
|     let rev = reverse || hasFilters ? false : store.tableSort.rev; | ||||
|     if (by) { | ||||
|         if (a[by] < b[by]) return rev ? 1 : -1; | ||||
|         if (a[by] > b[by]) return rev ? -1 : 1; | ||||
|         return 0; | ||||
|     } | ||||
| }); | ||||
| 
 | ||||
| /** | ||||
|  * Search Spells | ||||
|  * @param {Array} spells | ||||
|  * @param {String} ex 'acid spray' | ||||
|  * @return {Array} filtered spells | ||||
|  */ | ||||
| const searchSpells = (spells, search) => { | ||||
|     // Convert search to array of words
 | ||||
|     search = search.split(' '); | ||||
|     // Clone spells so we don't affect the original
 | ||||
|     spells = clone(spells); | ||||
|     // Reset rankings
 | ||||
|     spells = spells.map(s => { | ||||
|         s.ranking = 0; | ||||
|         return s; | ||||
|     }); | ||||
|     // Rank spells by # of occurances of search terms
 | ||||
|     spells = spells.map(spell => { | ||||
|         search.forEach(term => { | ||||
|             let spellText = Object.values(spell).join(' '); | ||||
|             let regFind = new RegExp(term, 'gi'); | ||||
|             spell.ranking += (spellText.match(regFind) || []).length; | ||||
|         }); | ||||
|         return spell; | ||||
|     }); | ||||
|     // Return spells that matched at least something
 | ||||
|     return spells.filter(spell => spell.ranking); | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Filter Spells by Class | ||||
|  */ | ||||
| const filterSpellsByClass = (spells, classes) => { | ||||
|     // If no classes, default to all classes
 | ||||
|     classes = classes.length ? classes : store.classes.data; | ||||
|     // Clone spells so we don't affect the original
 | ||||
|     spells = clone(spells); | ||||
|     return spells.filter(spell => { | ||||
|         let spellClasses = spell.classes.join(' '); | ||||
|         let match = false; | ||||
|         classes.forEach(c => { | ||||
|             if (spellClasses.indexOf(c) >= 0) { | ||||
|                 match = true; | ||||
|                 return true; | ||||
|             } | ||||
|         }); | ||||
|         return match; | ||||
|     }); | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Apply Filters | ||||
|  * @returns {Array} of spells ranked based on searches and filters | ||||
|  */ | ||||
| let applyFilters = () => sortSpells(searchSpells(filterSpellsByClass(store.spells, store.classes.current), store.search)); | ||||
| 
 | ||||
| /** | ||||
|  * Spell Details Updating | ||||
|  */ | ||||
| const spellDetails = name => { | ||||
|     if (!name) { | ||||
|         view.spell_details.update({ data: {} }); | ||||
|         $('body').removeClass('details'); | ||||
|     } else { | ||||
|         let data = clone(store.spells.find(spell => name === spell.name)); | ||||
|         data.description = descriptionPrettifier(data.description); | ||||
|         data.details = basicDetails.map(detail => { | ||||
|             if (data[detail]) { | ||||
|                 return { | ||||
|                     label: detail.replace('_', ' '), | ||||
|                     value: data[detail] | ||||
|                 }; | ||||
|             } | ||||
|         }); | ||||
|         if (data.components && data.components.raw) { | ||||
|             data.details.push({ label: 'components', value: data.components.raw }); | ||||
|         } | ||||
| 
 | ||||
|         view.spell_details.update({ | ||||
|             data, | ||||
|             url: window.location.href | ||||
|         }); | ||||
|         componentHandler.upgradeDom(); | ||||
|         $('body').addClass('details'); | ||||
|         let clipboard = new Clipboard('.copy-to-clipboard'); | ||||
|         clipboard.on('success', e => $('#toast')[0].MaterialSnackbar.showSnackbar({ message: 'Copied link' })).on('error', e => $('#toast')[0].MaterialSnackbar.showSnackbar({ message: 'Sorry! Unable to copy link' })); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Render Print Page | ||||
|  */ | ||||
| const renderPrint = () => { | ||||
|     let selectedSpells = $('form[data-selected]') | ||||
|     // Get array of items in form
 | ||||
|     .serializeArray() | ||||
|     // Find spells based on array from form
 | ||||
|     .map(sel => store.spells.find(spell => sel.value === spell.name)) | ||||
|     // Sort by level then alphabetically
 | ||||
|     .sort((a, b) => { | ||||
|         let aName = a.name.toLowerCase(); | ||||
|         let bName = b.name.toLowerCase(); | ||||
|         if (a.level > b.level) return 1; | ||||
|         if (a.level < b.level) return -1; | ||||
|         if (aName > bName) return 1; | ||||
|         if (aName < bName) return -1; | ||||
|         return 0; | ||||
|     }) | ||||
|     // Prettify Descriptions
 | ||||
|     .map(spell => { | ||||
|         spell = clone(spell); | ||||
|         spell.description = descriptionPrettifier(spell.description); | ||||
|         spell.details = basicDetails.map(detail => { | ||||
|             if (spell[detail]) { | ||||
|                 return { | ||||
|                     label: detail.replace('_', ' '), | ||||
|                     value: spell[detail] | ||||
|                 }; | ||||
|             } | ||||
|         }); | ||||
|         if (spell.components && spell.components.raw) { | ||||
|             spell.details.push({ label: 'components', value: spell.components.raw }); | ||||
|         } | ||||
|         return spell; | ||||
|     }); | ||||
|     view.spell_list_print.update({ data: selectedSpells }); | ||||
|     if (selectedSpells.length) { | ||||
|         $('[data-action=print] [data-badge]').attr('data-badge', selectedSpells.length); | ||||
|         $('[data-action=print]').slideDown('fast'); | ||||
|     } else { | ||||
|         $('[data-action=print]').slideUp('fast'); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Event Bindings | ||||
|  */ | ||||
| $('body') | ||||
| // Listen for header sorts
 | ||||
| .on('click', '[data-action-sort]', e => { | ||||
|     let name = $(e.currentTarget).attr('data-action-sort'); | ||||
|     let rev = store.tableSort.current === name && !store.tableSort.rev; | ||||
|     store.tableSort.current = name; | ||||
|     store.tableSort.rev = rev; | ||||
|     localStorage.setItem('tableSortName', name); | ||||
|     localStorage.setItem('tableSortRev', rev); | ||||
|     view.spell_list.update({ data: sortSpells(store.spells) }); | ||||
|     view.table_sort.update(store.tableSort); | ||||
|     componentHandler.upgradeDom(); | ||||
| }) | ||||
| // Listen for checkbox changes to filter spells
 | ||||
| .on('change', '[data-action-classtoggle]', e => { | ||||
|     let name = $(e.currentTarget).attr('data-action-classtoggle'); | ||||
|     let add = $(e.currentTarget).prop('checked'); | ||||
|     let index = store.classes.current.indexOf(name); | ||||
|     if (index === -1 && add) { | ||||
|         store.classes.current.push(name); | ||||
|     } else if (!add) store.classes.current.splice(index, 1); | ||||
|     store.tableSort.current = store.classes.current.length || store.search.length ? 'ranking' : null; | ||||
|     localStorage.setItem('tableSortName', store.tableSort.current); | ||||
|     localStorage.setItem('classes', store.classes.current); | ||||
|     view.spell_list.update({ data: applyFilters() }); | ||||
|     view.table_sort.update({ current: store.tableSort.current }); | ||||
|     componentHandler.upgradeDom(); | ||||
| }) | ||||
| // Listen to search to filter by
 | ||||
| .on('change keyup cut paste', '[data-action-search]', e => { | ||||
|     setTimeout(() => { | ||||
|         // Delay for value to change
 | ||||
|         store.search = $(e.currentTarget).val(); | ||||
|         store.tableSort.current = store.search.length || store.classes.current.length ? 'ranking' : null; | ||||
|         store.tableSort.rev = false; | ||||
|         localStorage.setItem('search', store.search); | ||||
|         localStorage.setItem('tableSortName', store.tableSort.current); | ||||
|         localStorage.setItem('tableSortRev', store.tableSort.rev); | ||||
|         view.spell_list.update({ data: applyFilters() }); | ||||
|         view.table_sort.update(store.tableSort); | ||||
|         componentHandler.upgradeDom(); | ||||
|     }, 0); | ||||
| }) | ||||
| // Listen for click on spells to open details
 | ||||
| .on('click', '[data-action-details]', e => { | ||||
|     let name = $(e.currentTarget).attr('data-action-details'); | ||||
|     if (name) { | ||||
|         window.location.hash = matchingSystemProp(store.systems.current, 'value') + '/' + name; | ||||
|     } else { | ||||
|         window.location.hash = ''; | ||||
|     } | ||||
|     spellDetails(name); | ||||
| }) | ||||
| // Stop propogation if dontprop clicked
 | ||||
| .on('click', '.dontprop', e => { | ||||
|     e.stopPropagation(); | ||||
| }) | ||||
| // Toggle All
 | ||||
| .on('change', 'label[for=table-header] input[type=checkbox]', e => { | ||||
|     $(e.target).closest('form').find('[name=selected]').each(function () { | ||||
|         this.checked = e.target.checked; | ||||
|         if (this.checked) $(this).closest('label').addClass('is-checked');else $(this).closest('label').removeClass('is-checked'); | ||||
|     }); | ||||
|     renderPrint(); | ||||
| }).on('change', 'input[name=selected][type=checkbox]', renderPrint).on('click', '[data-action=print]', e => { | ||||
|     window.print(); | ||||
| }); | ||||
| // Article Scroll with User
 | ||||
| $('.mdl-layout__content').on('scroll', debounce(() => { | ||||
|     let distance = $('.mdl-layout__content')[0].scrollTop; | ||||
|     $('[data-template=spell-details]').css('margin-top', distance); | ||||
| }, 10)); | ||||
| // System changed
 | ||||
| $('[data-action=system]').on('change', e => { | ||||
|     let system = $(e.currentTarget).val(); | ||||
|     let systemValue = matchingSystemProp(system, 'value'); | ||||
|     window.location.hash = ''; | ||||
|     spellDetails(''); | ||||
|     store.systems.current = system; | ||||
|     localStorage.setItem('system', systemValue); | ||||
|     view.spell_list.update({ data: false }); | ||||
|     view.class_list.update({ data: false }); | ||||
|     fetchSpells(systemValue); | ||||
| }); | ||||
| 
 | ||||
| /** | ||||
|  * Fetch Spells | ||||
|  */ | ||||
| const fetchSpells = (system = matchingSystemProp(store.systems.current, 'value')) => fetch(`./systems/${ system }.json`).then(response => response.json()).then(spells => initSpells(spells)).then(spells => { | ||||
|     store.spells = spells; | ||||
|     store.classes.data = discoverClasses(spells); | ||||
|     view.spell_list.update({ data: applyFilters() }); | ||||
|     view.class_list.update(store.classes); | ||||
|     componentHandler.upgradeDom(); | ||||
|     if (window.location.hash) spellDetails(window.location.hash.substr(1).split('/')[1]); | ||||
|     return spells; | ||||
| }).catch(reason => console.error('Unable to retrieve spells list:', reason)); | ||||
| fetchSpells(); | ||||
							
								
								
									
										7
									
								
								dist/clipboard.min.js
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								dist/clipboard.min.js
									
										
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										3
									
								
								dist/getmdl-select.min.css
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								dist/getmdl-select.min.css
									
										
									
									
										vendored
									
									
								
							|  | @ -1,3 +0,0 @@ | |||
| .getmdl-select .mdl-icon-toggle__label{float:right;margin-top:-30px;color:rgba(0,0,0,0.4)}.getmdl-select.is-focused .mdl-icon-toggle__label{color:#3f51b5}.getmdl-select .mdl-menu__container{width:100% !important}.getmdl-select .mdl-menu__container .mdl-menu{width:100%} | ||||
| 
 | ||||
| /*# sourceMappingURL=getmdl-select.min.css.map */ | ||||
							
								
								
									
										2
									
								
								dist/getmdl-select.min.js
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								dist/getmdl-select.min.js
									
										
									
									
										vendored
									
									
								
							|  | @ -1,2 +0,0 @@ | |||
| "use strict";window.onload=function(){getmdlSelect.init(".getmdl-select"),document.addEventListener("DOMNodeInserted",function(e){componentHandler.upgradeDom()},!1)};var getmdlSelect={addEventListeners:function(e){var t=e.querySelector("input"),n=e.querySelectorAll("li");[].forEach.call(n,function(e){e.onclick=function(){if(t.value=e.textContent,"createEvent"in document){var n=document.createEvent("HTMLEvents");n.initEvent("change",!1,!0),t.dispatchEvent(n)}else t.fireEvent("onchange")}})},init:function(e){var t=document.querySelectorAll(e);[].forEach.call(t,function(e){getmdlSelect.addEventListeners(e)})}}; | ||||
| //# sourceMappingURL=getmdl-select.min.js.map
 | ||||
							
								
								
									
										4
									
								
								dist/jquery.min.js
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								dist/jquery.min.js
									
										
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										385
									
								
								dist/monkberry.js
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										385
									
								
								dist/monkberry.js
									
										
									
									
										vendored
									
									
								
							|  | @ -1,385 +0,0 @@ | |||
| /**                                      _    _ | ||||
|  *                     /\/\   ___  _ __ | | _| |__   ___ _ __ _ __ _   _ | ||||
|  *                    /    \ / _ \| '_ \| |/ / '_ \ / _ \ '__| '__| | | | | ||||
|  *                   / /\/\ \ (_) | | | |   <| |_) |  __/ |  | |  | |_| | | ||||
|  *                   \/    \/\___/|_| |_|_|\_\_.__/ \___|_|  |_|   \__, | | ||||
|  *                                                                 |___/ | ||||
|  * | ||||
|  *        +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ | ||||
|  *  Enter ->  |       |                                   |           |           |       | | ||||
|  *        +   +   +   +---+   +---+---+   +---+---+   +   +   +---+   +   +---+   +   +   + | ||||
|  *        |       |           |                   |   |       |       |   |   |       |   | | ||||
|  *        +---+---+---+---+---+   +---+---+---+---+   +---+---+   +---+   +   +---+---+   + | ||||
|  *        |       |               |       |           |       |       |   |           |   | | ||||
|  *        +   +   +   +---+---+---+   +   +   +---+---+   +   +---+   +   +---+---+   +   + | ||||
|  *        |   |       |           |   |   |       |       |               |   |           | | ||||
|  *        +   +---+---+   +---+   +   +   +---+   +   +---+---+---+---+---+   +   +   +---+ | ||||
|  *        |   |       |       |       |       |   |   |       |       |   |       |   |   | | ||||
|  *        +   +---+   +---+   +---+---+---+   +   +   +   +   +   +   +   +---+---+   +   + | ||||
|  *        |           |       |       |   |       |       |   |   |   |           |   |   | | ||||
|  *        +---+---+---+   +---+   +   +   +   +---+---+---+   +---+   +---+---+   +   +   + | ||||
|  *        |   |       |           |       |   |       |       |       |               |   | | ||||
|  *        +   +   +   +---+---+---+   +---+   +   +   +   +---+   +---+---+   +---+---+   + | ||||
|  *        |   |   |           |           |   |   |   |       |   |       |   |           | | ||||
|  *        +   +   +---+---+   +---+---+---+   +---+   +---+   +   +   +   +   +   +---+   + | ||||
|  *        |       |                           |       |   |       |   |       |   |       | | ||||
|  *        +---+---+   +   +   +---+---+---+---+   +---+   +---+   +   +---+---+   +   +---+ | ||||
|  *        |           |   |                               |       |               |       -> Exit | ||||
|  *        +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ | ||||
|  */ | ||||
| (function (document) { | ||||
|   /** | ||||
|    * Monkberry | ||||
|    * @class | ||||
|    */ | ||||
|   function Monkberry() { | ||||
|     this.parent = null; | ||||
|     this.nested = []; | ||||
|     this.nodes = []; | ||||
|     this.filters = null; | ||||
|     this.directives = null; | ||||
|     this.context = null; | ||||
|     this.unbind = null; | ||||
|     this.onRender = null; | ||||
|     this.onUpdate = null; | ||||
|     this.onRemove = null; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Render template and attach it to node. | ||||
|    * @param {Monkberry} template | ||||
|    * @param {Element} node | ||||
|    * @param {Object=} options | ||||
|    * @return {Monkberry} | ||||
|    */ | ||||
|   Monkberry.render = function (template, node, options) { | ||||
|     var view; | ||||
| 
 | ||||
|     if (options && options.noCache) { | ||||
|       view = new template(); | ||||
|     } else { | ||||
|       view = template.pool.pop() || new template(); | ||||
|     } | ||||
| 
 | ||||
|     if (node.nodeType == 8) { | ||||
|       view.insertBefore(node); | ||||
|     } else { | ||||
|       view.appendTo(node); | ||||
|     } | ||||
| 
 | ||||
|     if (options) { | ||||
|       if (options.parent) { | ||||
|         view.parent = options.parent; | ||||
|       } | ||||
| 
 | ||||
|       if (options.context) { | ||||
|         view.context = options.context; | ||||
|       } | ||||
| 
 | ||||
|       if (options.filters) { | ||||
|         view.filters = options.filters; | ||||
|       } | ||||
| 
 | ||||
|       if (options.directives) { | ||||
|         view.directives = options.directives; | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     if (view.onRender) { | ||||
|       view.onRender(); | ||||
|     } | ||||
| 
 | ||||
|     return view; | ||||
|   }; | ||||
| 
 | ||||
|   /** | ||||
|    * Prerepder template for future usage. | ||||
|    * @param {Monkberry} template - Template name. | ||||
|    * @param {Number} times - Times of prerender. | ||||
|    */ | ||||
|   Monkberry.prerender = function (template, times) { | ||||
|     while (times--) { | ||||
|       template.pool.push(new template()); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   /** | ||||
|    * Main loops processor. | ||||
|    */ | ||||
|   Monkberry.loop = function (parent, node, map, template, array, options) { | ||||
|     var i, j, len, keys, transform, arrayLength, childrenSize = map.length; | ||||
| 
 | ||||
|     // Get array length, and convert object to array if needed.
 | ||||
|     if (Array.isArray(array)) { | ||||
|       transform = transformArray; | ||||
|       arrayLength = array.length; | ||||
|     } else { | ||||
|       transform = transformObject; | ||||
|       keys = Object.keys(array); | ||||
|       arrayLength = keys.length; | ||||
|     } | ||||
| 
 | ||||
|     // If new array contains less items what before, remove surpluses.
 | ||||
|     len = childrenSize - arrayLength; | ||||
|     for (i in map.items) { | ||||
|       if (len-- > 0) { | ||||
|         map.items[i].remove(); | ||||
|       } else { | ||||
|         break; | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     // If there is already some views, update there loop state.
 | ||||
|     j = 0; | ||||
|     for (i in map.items) { | ||||
|       map.items[i].__state__ = transform(array, keys, j, options); | ||||
|       j++; | ||||
|     } | ||||
| 
 | ||||
|     // If new array contains more items when previous, render new views and append them.
 | ||||
|     for (j = childrenSize, len = arrayLength; j < len; j++) { | ||||
|       // Render new view.
 | ||||
|       var view = Monkberry.render(template, node, {parent: parent, context: parent.context, filters: parent.filters, directives: parent.directives}); | ||||
| 
 | ||||
|       // Set view hierarchy.
 | ||||
|       parent.nested.push(view); | ||||
| 
 | ||||
|       // Remember to remove from children map on view remove.
 | ||||
|       i = map.push(view); | ||||
|       view.unbind = (function (i) { | ||||
|         return function () { | ||||
|           map.remove(i); | ||||
|         }; | ||||
|       })(i); | ||||
| 
 | ||||
|       // Set view state for later update in onUpdate.
 | ||||
|       view.__state__ = transform(array, keys, j, options); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   /** | ||||
|    * Main if processor. | ||||
|    */ | ||||
|   Monkberry.cond = function (parent, node, child/*.ref*/, template, test) { | ||||
|     if (child.ref) { // If view was already inserted, update or remove it.
 | ||||
|       if (!test) { | ||||
|         child.ref.remove(); | ||||
|       } | ||||
|     } else if (test) { | ||||
|       // Render new view.
 | ||||
|       var view = Monkberry.render(template, node, {parent: parent, context: parent.context, filters: parent.filters, directives: parent.directives}); | ||||
| 
 | ||||
|       // Set view hierarchy.
 | ||||
|       parent.nested.push(view); | ||||
| 
 | ||||
|       // Remember to remove child ref on remove of view.
 | ||||
|       child.ref = view; | ||||
|       view.unbind = function () { | ||||
|         child.ref = null; | ||||
|       }; | ||||
|     } | ||||
| 
 | ||||
|     return test; | ||||
|   }; | ||||
| 
 | ||||
|   /** | ||||
|    * Main custom tags processor. | ||||
|    */ | ||||
|   Monkberry.insert = function (parent, node, child/*.ref*/, template, data) { | ||||
|     if (child.ref) { // If view was already inserted, update or remove it.
 | ||||
|       child.ref.update(data); | ||||
|     } else { | ||||
|       // Render new view.
 | ||||
|       var view = Monkberry.render(template, node, {parent: parent, context: parent.context, filters: parent.filters, directives: parent.directives}); | ||||
| 
 | ||||
|       // Set view hierarchy.
 | ||||
|       parent.nested.push(view); | ||||
| 
 | ||||
|       // Remember to remove child ref on remove of view.
 | ||||
|       child.ref = view; | ||||
|       view.unbind = function () { | ||||
|         child.ref = null; | ||||
|       }; | ||||
| 
 | ||||
|       // Set view data (note what it must be after adding nodes to DOM).
 | ||||
|       view.update(data); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   /** | ||||
|    * Remove view from DOM. | ||||
|    */ | ||||
|   Monkberry.prototype.remove = function () { | ||||
|     // Remove appended nodes.
 | ||||
|     var i = this.nodes.length; | ||||
|     while (i--) { | ||||
|       this.nodes[i].parentNode.removeChild(this.nodes[i]); | ||||
|     } | ||||
| 
 | ||||
|     // Remove self from parent's children map or child ref.
 | ||||
|     if (this.unbind) { | ||||
|       this.unbind(); | ||||
|     } | ||||
| 
 | ||||
|     // Remove all nested views.
 | ||||
|     i = this.nested.length; | ||||
|     while (i--) { | ||||
|       this.nested[i].remove(); | ||||
|     } | ||||
| 
 | ||||
|     // Remove this view from parent's nested views.
 | ||||
|     if (this.parent) { | ||||
|       i = this.parent.nested.indexOf(this); | ||||
|       this.parent.nested.splice(i, 1); | ||||
|       this.parent = null; | ||||
|     } | ||||
| 
 | ||||
|     // Call on remove callback.
 | ||||
|     if (this.onRemove) { | ||||
|       this.onRemove(); | ||||
|     } | ||||
| 
 | ||||
|     // Store view in pool for reuse in future.
 | ||||
|     this.constructor.pool.push(this); | ||||
|   }; | ||||
| 
 | ||||
|   /** | ||||
|    * @param {Element} toNode | ||||
|    */ | ||||
|   Monkberry.prototype.appendTo = function (toNode) { | ||||
|     for (var i = 0, len = this.nodes.length; i < len; i++) { | ||||
|       toNode.appendChild(this.nodes[i]); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   /** | ||||
|    * @param {Element} toNode | ||||
|    */ | ||||
|   Monkberry.prototype.insertBefore = function (toNode) { | ||||
|     if (toNode.parentNode) { | ||||
|       for (var i = 0, len = this.nodes.length; i < len; i++) { | ||||
|         toNode.parentNode.insertBefore(this.nodes[i], toNode); | ||||
|       } | ||||
|     } else { | ||||
|       throw new Error( | ||||
|         "Can not insert child view into parent node. " + | ||||
|         "You need append your view first and then update." | ||||
|       ); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   /** | ||||
|    * Return rendered node, or DocumentFragment of rendered nodes if more then one root node in template. | ||||
|    * @returns {Element|DocumentFragment} | ||||
|    */ | ||||
|   Monkberry.prototype.createDocument = function () { | ||||
|     if (this.nodes.length == 1) { | ||||
|       return this.nodes[0]; | ||||
|     } else { | ||||
|       var fragment = document.createDocumentFragment(); | ||||
|       for (var i = 0, len = this.nodes.length; i < len; i++) { | ||||
|         fragment.appendChild(this.nodes[i]); | ||||
|       } | ||||
|       return fragment; | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   /** | ||||
|    * @param {string} query | ||||
|    * @returns {Element} | ||||
|    */ | ||||
|   Monkberry.prototype.querySelector = function (query) { | ||||
|     for (var i = 0; i < this.nodes.length; i++) { | ||||
|       if (this.nodes[i].matches && this.nodes[i].matches(query)) { | ||||
|         return this.nodes[i]; | ||||
|       } | ||||
| 
 | ||||
|       if (this.nodes[i].nodeType === 8) { | ||||
|         throw new Error('Can not use querySelector with non-element nodes on first level.'); | ||||
|       } | ||||
| 
 | ||||
|       if (this.nodes[i].querySelector) { | ||||
|         var element = this.nodes[i].querySelector(query); | ||||
|         if (element) { | ||||
|           return element; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     return null; | ||||
|   }; | ||||
| 
 | ||||
| 
 | ||||
|   /** | ||||
|    * Simple Map implementation with length property. | ||||
|    */ | ||||
|   function Map() { | ||||
|     this.items = Object.create(null); | ||||
|     this.length = 0; | ||||
|     this.next = 0; | ||||
|   } | ||||
| 
 | ||||
|   Map.prototype.push = function (element) { | ||||
|     this.items[this.next] = element; | ||||
|     this.length += 1; | ||||
|     this.next += 1; | ||||
|     return this.next - 1; | ||||
|   }; | ||||
| 
 | ||||
|   Map.prototype.remove = function (i) { | ||||
|     if (i in this.items) { | ||||
|       delete this.items[i]; | ||||
|       this.length -= 1; | ||||
|     } else { | ||||
|       throw new Error('You are trying to delete not existing element "' + i + '" form map.'); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   Map.prototype.forEach = function (callback) { | ||||
|     for (var i in this.items) { | ||||
|       callback(this.items[i]); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   Monkberry.Map = Map; | ||||
| 
 | ||||
|   //
 | ||||
|   // Helper function for working with foreach loops data.
 | ||||
|   // Will transform data for "key, value of array" constructions.
 | ||||
|   //
 | ||||
| 
 | ||||
|   function transformArray(array, keys, i, options) { | ||||
|     if (options) { | ||||
|       var t = {__index__: i}; | ||||
|       t[options.value] = array[i]; | ||||
| 
 | ||||
|       if (options.key) { | ||||
|         t[options.key] = i; | ||||
|       } | ||||
| 
 | ||||
|       return t; | ||||
|     } else { | ||||
|       return array[i]; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   function transformObject(array, keys, i, options) { | ||||
|     if (options) { | ||||
|       var t = {__index__: i}; | ||||
|       t[options.value] = array[keys[i]]; | ||||
| 
 | ||||
|       if (options.key) { | ||||
|         t[options.key] = keys[i]; | ||||
|       } | ||||
| 
 | ||||
|       return t; | ||||
|     } else { | ||||
|       return array[keys[i]]; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   if (typeof module !== 'undefined') { | ||||
|     module.exports = Monkberry; | ||||
|   } else { | ||||
|     window.Monkberry = Monkberry; | ||||
|   } | ||||
| })(window.document); | ||||
							
								
								
									
										4
									
								
								dist/remarkable.min.js
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								dist/remarkable.min.js
									
										
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										1241
									
								
								dist/view.js
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										1241
									
								
								dist/view.js
									
										
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										1
									
								
								dist/view.js.map
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								dist/view.js.map
									
										
									
									
										vendored
									
									
								
							|  | @ -1 +0,0 @@ | |||
| {"version":3,"sources":["class-list.monk","search-field.monk","spell-details.monk","spell-list-print.monk","spell-list.monk","system-list.monk","table-sort.monk"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,mEAAM,IAAN,C;AAAA,oE;;;;;;AAAA;AAAA;AAAA,K;AAAA;AAAA;AAAA,K;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACI,kEAAc,IAAd,kB;;;;;;AAAA;AAAA;AAAA;AAAA,O;;;;;;;;;;;;;;;;;;;;;;;;;;EACI,6C;EACI,yC;;;;EAMI,2C;;;;;EAAM,4BAAO,mBAAP,E;;;EANL,2BAAO,+CAAP,E;;EADF,6BAAO,sBAAP,E;;;;;;AAEC,4EAAM,QAAQ,QAAR,CAAiB,GAAjB,CAAN,C;AAAA,6E;;;AAMI,0BAAG,G;;;;;;AANP;AAAA;AAAA,K;AAAA;AAAA;AAAA,K;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EACI,6C;;;EAAO,sB;EAA4C,4BAAM,OAAN,E;EAAa,4BAAM,UAAN,E;EAAgB,6BAAO,mBAAP,E;;;;;AAAjE,qDAA4B,GAA5B,E;;;;;;;;;;;;;;;;;;;;;;;EAEf,6C;;;EAA2C,4BAAM,OAAN,E;EAAa,4BAAM,UAAN,E;EAAgB,6BAAO,mBAAP,E;;;;;AAAjE,qDAA4B,GAA5B,E;;;;;;;;;;;;;;;;;;;;;;;EASvB,yC;;;EAAK,2BAAO,sCAAP,E;;;;;;;;;;AAhBT;AAAA;;;;;;;;;ECAA,6C;;;EAA0B,6BAAO,sBAAP,E;EAA6B,8C;EAAmB,4BAAM,MAAN,E;EAAY,YAAI,yBAAJ,C;;;;;AAA/E,qBAAU,IAAV,C;;;;;;;;;;;;;;;AAAP;AAAA;;;;;;;;;;;;;;;;;;;;ACAA,sEAAM,KAAK,IAAX,C;AAAA,uE;;;;;;AAAA;AAAA;AAAA,K;AAAA;AAAA;AAAA,K;;;;;;;;;;;;;;;;;;;;;;;;EACI,+C;EACE,qC;EAEF,uC;;EACA,uC;;EAOA,qC;;EAEA,yC;EACI,6C;EACI,qC;EAEJ,6C;;;;EAhBC,yBAAO,gBAAP,E;;EADG,gD;EAAuB,8BAAO,+DAAP,E;;EAG3B,0BAAO,oDAAP,E;EACA,SAAI,SAAJ,C;EAOD,QAAI,aAAJ,C;;EAIQ,yBAAO,gBAAP,E;;EADA,6BAAO,6DAAP,E;EAAoE,2BAAK,WAAL,E;EAAgB,6CAAuB,YAAvB,E;EAGpF,oC;EAAS,6BAAO,sBAAP,E;EAA6B,4BAAM,MAAN,E;EAAY,YAAI,WAAJ,C;;;EAJxD,2BAAO,gCAAP,E;EAAuC,UAAI,MAAJ,C;;;;;AAVmB,0BAAG,KAAK,I;AAEnE,oEAAiB,KAAK,OAAtB,qB;AAMgB,iCAAU,KAAK,WAAf,C;;;AAMwD,qBAAU,GAAV,C;;;;;;AAZxE;AAAA;AAAA;AAAA,O;;;;;;;;;;;;;;;;;;;;;;;;;;;EACI,uC;EACI,+C;;;;;;;;;;;;;AAAQ,0BAAG,OAAO,K;AAAuB,0BAAG,OAAO,K;;;;;;;;;;;;;;;;;;;;;;;EAa/D,yC;EACI,uC;;;;EAAI,0BAAO,uBAAP,E;;EADH,UAAI,OAAJ,C;;;;;;;;;;AArBT;AAAA;;;;;;;;;;;;;;;;;;ACAA,oEAAgB,IAAhB,oB;;;;;;AAAA;AAAA;AAAA;AAAA,O;;;;;;;;;;;;;;;;;;;;;;;;;EACI,uC;EACI,uC;EACI,+C;;EAIJ,uC;;EAGA,uC;EACI,uC;;;;;;;;EATA,0BAAO,YAAP,E;;EAKA,0BAAO,aAAP,E;EAII,SAAI,SAAJ,C;;;EADJ,0BAAO,mBAAP,E;;;;;;;;AANI,0BAAG,MAAM,I;AAIb,0BAAG,MAAM,K;AAIL,wEAAiB,MAAM,OAAvB,qB;AAOJ,sCAAU,MAAM,WAAhB,C;;;;;;AAPI;AAAA;AAAA;AAAA,O;;;;;;;;;;;;;;;;;;;;;;;;EACI,uC;EACI,+C;;;;;;;;;;;;;AAAQ,0BAAG,OAAO,K;AAAuB,0BAAG,OAAO,K;;;;;;;;;;;;;;;AAd3E;AAAA;;;;;;;;;;;;;;;;;;ACAA,mEAAM,KAAK,MAAX,C;AAAA,oE;;;;;;AAAA;AAAA;AAAA,K;AAAA;AAAA;AAAA,K;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACI,kEAAgB,IAAhB,oB;;;;;;AAAA;AAAA;AAAA;AAAA,O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACI,mEAAM,MAAM,IAAZ,C;;;;;;AAAA;AAAA;AAAA,K;;;;;;;;;;;;;;;;;;;;;;;EACI,uC;EACI,uC;EACI,6C;EACI,6C;EAGR,uC;EACI,+C;;EAIJ,uC;;EAGA,uC;;;;EAXe,4BAAM,UAAN,E;EAAgB,4BAAM,UAAN,E;EAAyC,6BAAO,8BAAP,E;;EAD7D,6BAAO,mFAAP,E;;EADP,0BAAO,YAAP,E;;;EAKA,0BAAO,8CAAP,E;;EAKA,0BAAO,gDAAP,E;;EAGA,0BAAO,aAAP,E;;;;;;;;;AAX2C,qBAAU,MAAM,IAAhB,C;AAKvC,0BAAG,MAAM,I;AAIb,0BAAG,MAAM,M;AAGT,2BAAG,MAAM,K;AAfb,8CAAwB,MAAM,IAA9B,E;;;;;;;;;;;;;;;;;;;;;;;;EAqBZ,uC;EACI,uC;;;;;EAAI,4BAAS,GAAT,E;;EADJ,0BAAO,YAAP,E;;;;;;AAEI,wEAAM,IAAN,C;AAAA,yE;;;;;;AAAA;AAAA;AAAA,K;AAAA;AAAA;AAAA,K;;;;;;;;;;;;;;;;;;;;;;;EACI,yC;EACI,qC;EAGA,uC;EACA,uC;;;;EAJG,yBAAO,+DAAP,E;;;;;;EADF,2BAAO,aAAP,E;;;;;;;;;;;;;;;;;;EAQL,yC;;;EAAK,2BAAO,sCAAP,E;;;;;;;;;;AAnCrB;AAAA;;;;;;;;;;;;;;;;ACAA,2DAAM,IAAN,C;;;;;;AAAA;AAAA;AAAA,K;;;;;;;;;;;;;;;;;;;;;;;;EACI,yC;EACI,6C;EACA,6C;EACA,uC;;;;EAFO,6BAAO,sBAAP,E;EAA6B,mCAAa,QAAb,E;EAA2C,4BAAM,MAAN,E;EAAY,YAAI,QAAJ,C;EAAY,oC;EAAS,gCAAU,IAAV,E;;EACzG,6BAAO,4CAAP,E;EAAmD,2BAAK,QAAL,E;EACtD,0BAAO,4CAAP,E;EAAmD,wBAAK,QAAL,E;;;;EAHtD,2BAAO,4EAAP,E;;;;;AACwD,qBAAU,OAAV,C;;;AAGrD,kEAAiB,IAAjB,qB;;;;;;AAAA;AAAA;AAAA;AAAA,O;;;;;;;;;;;;;;;;;;;;;;;;;;;EACI,uC;;;;;EAAI,0BAAO,gBAAP,E;;;;;AAAuB,0BAAG,OAAO,Q;;;;;;;;;;;;;;;AANrD;AAAA;;;;;;;;;;ECAA,uC;EACI,6C;EACI,6C;;;;;EAAO,4BAAM,UAAN,E;EAAgB,YAAI,cAAJ,C;EAAkB,6BAAO,qBAAP,E;;EADtC,6BAAO,0EAAP,E;EAAiF,2BAAK,cAAL,E;;EADxF,0BAAO,YAAP,E;;;;;AAKJ,8DAAe,IAAf,mB;;;;;;AAAA;AAAA;AAAA;AAAA,O;;;;;;;;;;;;;;;;;;;;;;;;;;EACI,uC;EACI,qC;;;;;;;EAYA,2C;;EAIA,qC;;;;;;;EAhBG,yBAAO,oCAAP,E;;;;EAgBA,yBAAO,8DAAP,E;;;;EAjB2B,0BAAO,oCAAP,E;;;;;AAE1B,+DAAM,YAAS,OAAT,CAAN,C;AAGA,+DAAM,YAAS,MAAT,CAAN,C;AAGA,+DAAM,YAAS,QAAT,CAAN,C;AAMO,0BAAG,I;AAdd,2CAAqB,IAArB,E;;;AAkBI,0BAAG,QAAM,mBAAN,GAA4B,qB;;;AADhC,gCAAO,8DAAP,KAAsE,aAAS,OAAT,KAAmB,0BAAnB,GAAgD,0BAAtH,G;;;AAjB2B,iCAAO,oCAAP,KAA4C,gBAAY,SAAZ,KAAwB,qCAAxB,GAAgE,EAA5G,G;;;;;;AAE1B;AAAA;AAAA,K;AAGA;AAAA;AAAA,K;AAGA;AAAA;AAAA,K;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gBANyB,qC;;;;;;;;;;;;;;;gBAGD,qC;;;;;;;;;;;;;;;gBAGE,mC;;;;;;;AAdtC;AAAA","file":"view.js"} | ||||
							
								
								
									
										116
									
								
								index.html
									
										
									
									
									
								
							
							
						
						
									
										116
									
								
								index.html
									
										
									
									
									
								
							|  | @ -1,116 +0,0 @@ | |||
| <!DOCTYPE html> | ||||
| <html> | ||||
|     <head> | ||||
|         <title>My Spells</title> | ||||
|         <meta charset="UTF-8"> | ||||
|         <meta name="viewport" content="width=device-width, initial-scale=1"> | ||||
|         <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700" type="text/css"> | ||||
|         <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons"> | ||||
|         <link rel="stylesheet" href="https://code.getmdl.io/1.1.3/material.teal-pink.min.css" /> | ||||
|         <link rel="stylesheet" href="./dist/getmdl-select.min.css" /> | ||||
|         <link rel="stylesheet" href="./assets/app.css" /> | ||||
|         <link rel="stylesheet" href="./assets/print.css" /> | ||||
|     </head> | ||||
|     <body> | ||||
|         <div class="mdl-layout mdl-js-layout mdl-layout--fixed-drawer mdl-layout--fixed-header"> | ||||
|             <header class="mdl-layout__header"> | ||||
|                 <div class="mdl-layout__header-row"> | ||||
|                     <div data-template="system-list"></div> | ||||
|                     <div class="mdl-layout-spacer"></div> | ||||
|                     <button data-action="print" class="mdl-button mdl-js-button mdl-js-ripple-effect mdl-color-text--white"> | ||||
|                         <span class="mdl-badge" data-badge="0"> | ||||
|                             <i class="material-icons">print</i> | ||||
|                             Print | ||||
|                         </span> | ||||
|                     </button> | ||||
|                     <div data-action-details="" role="button" tabindex="0"><i class="material-icons">keyboard_arrow_left</i></div> | ||||
|                 </div> | ||||
|             </header> | ||||
|             <aside class="mdl-layout__drawer"> | ||||
|                 <span class="mdl-layout-title mdl-color-text--pink-600"> | ||||
|                     <i class="material-icons">whatshot</i> | ||||
|                     My Spells | ||||
|                 </span> | ||||
|                 <nav class="mdl-navigation"> | ||||
|                     <form> | ||||
|                         <div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label"> | ||||
|                             <div data-template="search-field"></div> | ||||
|                             <label class="mdl-textfield__label"> | ||||
|                                 <i class="material-icons">search</i> | ||||
|                                 Search | ||||
|                             </label> | ||||
|                         </div> | ||||
|                     </form> | ||||
| 
 | ||||
|                     <form data-template="class-list"> | ||||
|                     </form> | ||||
|                 </nav> | ||||
|             </aside> | ||||
|             <main class="mdl-layout__content"> | ||||
|                 <div class="page-content"> | ||||
|                     <form class="mdl-grid" id="selected-spells" data-selected> | ||||
|                         <table id="spell-list-container" class="mdl-cell mdl-cell--12-col mdl-cell--6-col-desktop mdl-data-table mdl-shadow--2dp"> | ||||
|                             <thead> | ||||
|                                 <tr data-template="table-sort"></tr> | ||||
|                             </thead> | ||||
|                             <tbody data-template="spell-list"></tbody> | ||||
|                         </table> | ||||
|                         <article data-template="spell-details" class="mdl-cell mdl-cell--12-col mdl-cell--6-col-desktop mdl-color-text--grey-600"></article> | ||||
|                     </form> | ||||
|                 </div> | ||||
|             </main> | ||||
| 
 | ||||
|             <footer class="mdl-mini-footer"> | ||||
|                 <div class="mdl-mini-footer__right-section"> | ||||
|                     <div class="mdl-logo hide-phone">My Spells</div> | ||||
|                     <ul class="mdl-mini-footer__link-list"> | ||||
|                         <li> | ||||
|                             <a class="hide-phone mdl-navigation__link mdl-color-text--teal-100" href="https://github.com/sharpshark28/my_spells"> | ||||
|                                 <i class="material-icons">code</i> | ||||
|                                 Fork Me On Github | ||||
|                             </a> | ||||
|                         </li> | ||||
|                         <li> | ||||
|                             <a class="mdl-navigation__link" href="https://dark12222000.github.io/lootsplit/"> | ||||
|                                 <i class="material-icons">local_atm</i> | ||||
|                                 Loot Split | ||||
|                             </a> | ||||
|                         </li> | ||||
|                         <li> | ||||
|                             <a class="mdl-navigation__link" href="http://paulvmoreau.github.io/BeltFedNPCs/"> | ||||
|                                 <i class="material-icons">people</i> | ||||
|                                 NPC Generator | ||||
|                             </a> | ||||
|                         </li> | ||||
|                     </ul> | ||||
|                 </div> | ||||
|             </footer> | ||||
| 
 | ||||
|             <div id="toast" class="mdl-js-snackbar mdl-snackbar"> | ||||
|                 <div class="mdl-snackbar__text"></div> | ||||
|                 <button class="mdl-snackbar__action" type="button"></button> | ||||
|             </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <table class="printonly"> | ||||
|             <thead> | ||||
|                 <tr> | ||||
|                     <th>Spell Name</th> | ||||
|                     <th>Level</th> | ||||
|                     <th>Description</th> | ||||
|                 </tr> | ||||
|             </thead> | ||||
|             <tbody data-template="spell-list-print"> | ||||
|             </tbody> | ||||
|         </table> | ||||
| 
 | ||||
|         <script src="https://code.getmdl.io/1.1.3/material.min.js"></script> | ||||
|         <script src="./dist/getmdl-select.min.js"></script> | ||||
|         <script src="./dist/jquery.min.js"></script> | ||||
|         <script src="./dist/monkberry.js"></script> | ||||
|         <script src="./dist/remarkable.min.js"></script> | ||||
|         <script src="./dist/clipboard.min.js"></script> | ||||
|         <script src="./dist/view.js"></script> | ||||
|         <script src="./dist/app.js"></script> | ||||
|     </body> | ||||
| </html> | ||||
							
								
								
									
										133
									
								
								ogl.html
									
										
									
									
									
								
							
							
						
						
									
										133
									
								
								ogl.html
									
										
									
									
									
								
							|  | @ -1,133 +0,0 @@ | |||
| <html> | ||||
| 
 | ||||
| <head> | ||||
| <title>Open Game License v0.1 Simplified</title> | ||||
| </head> | ||||
| 
 | ||||
| <body> | ||||
| 
 | ||||
| <center><a href="./index.html">OGF Main</a> | | ||||
| <a href="./licenses.html">List of Licenses</a> | | ||||
| Open Game License Text</center> | ||||
| 
 | ||||
| <P>THIS LICENSE IS APPROVED FOR GENERAL USE.  PERMISSION TO DISTRIBUTE THIS LICENSE | ||||
| IS MADE BY WIZARDS OF THE COAST!</P> | ||||
| 
 | ||||
| <P>OPEN GAME LICENSE Version  1.0a</P> | ||||
| 
 | ||||
| <P>The following text is the property of Wizards of the Coast, Inc. and is | ||||
| Copyright 2000 Wizards of the Coast, Inc ("Wizards"). All Rights Reserved.</P> | ||||
| 
 | ||||
| <P>1. Definitions: (a)"Contributors" means the copyright and/or trademark | ||||
| owners who have contributed Open Game Content; (b)"Derivative Material" | ||||
| means copyrighted material including derivative works and translations | ||||
| (including into other computer languages), potation, modification, | ||||
| correction, addition, extension, upgrade, improvement, compilation, | ||||
| abridgment or other form in which an existing work may be recast, | ||||
| transformed or adapted;  (c) "Distribute" means to reproduce, license, rent, | ||||
| lease, sell, broadcast, publicly display, transmit or otherwise distribute; | ||||
| (d)"Open Game Content" means the game mechanic and includes the methods, | ||||
| procedures, processes and routines to the extent such content does not | ||||
| embody the Product Identity and is an enhancement over the prior art and any | ||||
| additional content clearly identified as Open Game Content by the | ||||
| Contributor,  and means any work covered by this License, including | ||||
| translations and derivative works under copyright law, but specifically | ||||
| excludes Product Identity. (e) "Product Identity" means product and product | ||||
| line names, logos and identifying marks including trade dress; artifacts; | ||||
| creatures characters; stories, storylines, plots, thematic elements, | ||||
| dialogue, incidents, language, artwork, symbols, designs, depictions, | ||||
| likenesses, formats, poses, concepts, themes and graphic, photographic and | ||||
| other visual or audio representations; names and descriptions of characters, | ||||
| spells, enchantments, personalities, teams, personas, likenesses and special | ||||
| abilities; places, locations, environments, creatures, equipment, magical or | ||||
| supernatural abilities or effects, logos, symbols, or graphic designs; and | ||||
| any other trademark or registered trademark clearly identified as Product | ||||
| identity by the owner of the Product Identity, and which specifically | ||||
| excludes the Open Game Content; (f) "Trademark" means the logos, names, | ||||
| mark, sign, motto, designs that are used by a Contributor to identify itself | ||||
| or its products or the associated products contributed to the Open Game | ||||
| License by the Contributor (g) "Use", "Used" or "Using" means to use, | ||||
| Distribute, copy, edit, format, modify, translate and otherwise create | ||||
| Derivative Material of Open Game Content. (h) "You" or "Your" means the | ||||
| licensee in terms of this agreement.</P> | ||||
| 
 | ||||
| <P>2. The License:  This License applies to any Open Game Content that contains | ||||
| a notice indicating that the Open Game Content may only be Used under and in | ||||
| terms of this License. You must affix such a notice to any Open Game Content | ||||
| that you Use. No terms may be added to or subtracted from this License | ||||
| except as described by the License itself. No other terms or conditions may | ||||
| be applied to any Open Game Content distributed using this License.</P> | ||||
| 
 | ||||
| <P>3.Offer and Acceptance: By Using the Open Game Content You indicate Your | ||||
| acceptance of the terms of this License.</P> | ||||
| 
 | ||||
| <P>4. Grant and Consideration: In consideration for agreeing to use this | ||||
| License, the Contributors grant You a perpetual, worldwide, royalty-free, | ||||
| non-exclusive license with the exact terms of this License to Use, the Open | ||||
| Game Content.</P> | ||||
| 
 | ||||
| <P>5.Representation of Authority to Contribute: If You are contributing | ||||
| original material as Open Game Content, You represent that Your | ||||
| Contributions are Your original creation and/or You have sufficient rights | ||||
| to grant the rights conveyed by this License.</P> | ||||
| 
 | ||||
| <P>6.Notice of License Copyright: You must update the COPYRIGHT NOTICE portion | ||||
| of this License to include the exact text of the COPYRIGHT NOTICE of any | ||||
| Open Game Content You are copying, modifying or distributing, and You must | ||||
| add the title, the copyright date, and the copyright holder's name to the | ||||
| COPYRIGHT NOTICE of any original Open Game Content you Distribute.</P> | ||||
| 
 | ||||
| <P>7. Use of Product Identity:  You agree not to Use any Product Identity, | ||||
| including as an indication as to compatibility, except as expressly licensed | ||||
| in another, independent Agreement with the owner of each element of that | ||||
| Product Identity.  You agree not to indicate compatibility or | ||||
| co-adaptability with any Trademark or Registered Trademark in conjunction with a work containing | ||||
| Open Game Content except as expressly licensed in another, independent | ||||
| Agreement with the owner of such Trademark or Registered Trademark. The use of any Product Identity | ||||
| in Open Game Content does not constitute a challenge to the ownership of | ||||
| that Product Identity.  The owner of any Product Identity used in Open Game | ||||
| Content shall retain all rights, title and interest in and to that Product | ||||
| Identity.</P> | ||||
| 
 | ||||
| <P>8. Identification: If you distribute Open Game Content You must clearly | ||||
| indicate which portions of the work that you are distributing are Open Game | ||||
| Content.</P> | ||||
| 
 | ||||
| <P>9. Updating the License:  Wizards or its designated Agents may publish | ||||
| updated versions of this License.  You may use any authorized version of | ||||
| this License to copy, modify and distribute any Open Game Content originally | ||||
| distributed under any version of this License.</P> | ||||
| 
 | ||||
| <P>10 Copy of this License:  You MUST include a copy of this License with every | ||||
| copy of the Open Game Content You Distribute.</P> | ||||
| 
 | ||||
| <P>11. Use of Contributor Credits: You may not market or advertise the Open | ||||
| Game Content using the name of any Contributor unless You have written | ||||
| permission from the Contributor to do so.</P> | ||||
| 
 | ||||
| <P>12 Inability to Comply: If it is impossible for You to comply with any of | ||||
| the terms of this License with respect to some or all of the Open Game | ||||
| Content due to statute, judicial order, or governmental regulation then You | ||||
| may not Use any Open Game Material so affected.</P> | ||||
| 
 | ||||
| <P>13 Termination: This License will terminate automatically if You fail to | ||||
| comply with all terms herein and fail to cure such breach within 30 days of | ||||
| becoming aware of the breach. All sublicenses shall survive the termination | ||||
| of this License.</P> | ||||
| 
 | ||||
| <P>14 Reformation: If any provision of this License is held to be | ||||
| unenforceable, such provision shall be reformed only to the extent necessary | ||||
| to make it enforceable.</P> | ||||
| 
 | ||||
| <P>15 COPYRIGHT NOTICE<br> | ||||
| Open Game License v 1.0 Copyright 2000, Wizards of the Coast, Inc.</P> | ||||
| 
 | ||||
| <p> | ||||
| 
 | ||||
| <center><a href="./index.html">OGF Main</a></Center> | ||||
| 
 | ||||
| </p> | ||||
| 
 | ||||
| </body> | ||||
| 
 | ||||
| </html> | ||||
							
								
								
									
										31
									
								
								package.json
									
										
									
									
									
								
							
							
						
						
									
										31
									
								
								package.json
									
										
									
									
									
								
							|  | @ -1,31 +0,0 @@ | |||
| { | ||||
|   "name": "my_spells_5e", | ||||
|   "version": "1.0.0", | ||||
|   "description": "5e Spells by Class", | ||||
|   "main": "", | ||||
|   "watch": { | ||||
|     "views": "views/*.monk" | ||||
|   }, | ||||
|   "scripts": { | ||||
|     "postinstall": "mkdir -p dist && cp node_modules/clipboard/dist/clipboard.min.js dist && cp node_modules/jquery/dist/jquery.min.js dist && cp node_modules/monkberry/monkberry.js dist && cp node_modules/remarkable/dist/remarkable.min.js dist && cp node_modules/getmdl-select/getmdl-select.min.css dist && cp node_modules/getmdl-select/getmdl-select.min.js dist", | ||||
|     "views": "monkberry src/views/*.monk --source-map --output dist/view.js", | ||||
|     "js": "babel src/app.js --out-file dist/app.js", | ||||
|     "develop": "nodemon --watch src -e monk,js --exec 'npm run views && npm run js'" | ||||
|   }, | ||||
|   "author": "Joe Wroten <sharpshark28@gmail.com>", | ||||
|   "license": "ISC", | ||||
|   "devDependencies": { | ||||
|     "babel-cli": "^6.11.4", | ||||
|     "babel-plugin-transform-runtime": "^6.12.0", | ||||
|     "babel-preset-es2017": "^1.6.1", | ||||
|     "nodemon": "^1.10.0", | ||||
|     "npm-watch": "^0.1.5" | ||||
|   }, | ||||
|   "dependencies": { | ||||
|     "clipboard": "^1.5.12", | ||||
|     "getmdl-select": "^1.0.4", | ||||
|     "jquery": "^3.1.0", | ||||
|     "monkberry": "^4.0.7", | ||||
|     "remarkable": "^1.6.2" | ||||
|   } | ||||
| } | ||||
							
								
								
									
										
											BIN
										
									
								
								src/.DS_Store
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/.DS_Store
									
										
									
									
										vendored
									
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										435
									
								
								src/app.js
									
										
									
									
									
								
							
							
						
						
									
										435
									
								
								src/app.js
									
										
									
									
									
								
							|  | @ -1,435 +0,0 @@ | |||
| /** | ||||
|  * Misc helper functions | ||||
|  */ | ||||
| Object.values = x => | ||||
|   Object.keys(x).reduce((y, z) => | ||||
|     y.push(x[z]) && y, []); | ||||
| const debounce = (func, wait, immediate) => { | ||||
|     let timeout; | ||||
|     return function() { | ||||
|         let context = this, args = arguments; | ||||
|         let later = function() { | ||||
|             timeout = null; | ||||
|             if (!immediate) func.apply(context, args); | ||||
|         }; | ||||
|         let callNow = immediate && !timeout; | ||||
|         clearTimeout(timeout); | ||||
|         timeout = setTimeout(later, wait); | ||||
|         if (callNow) func.apply(context, args); | ||||
|     }; | ||||
| }; | ||||
| const el = id => $(`[data-template=${id}]`)[0] || console.error('Unable to render to', id); | ||||
| const clone = obj => JSON.parse(JSON.stringify(obj)); | ||||
| const basicDetails = ['level', 'range', 'duration', 'casting_time', 'saving_throw', 'aoe', 'source']; | ||||
| 
 | ||||
| /** | ||||
|  * Global store and view holders | ||||
|  */ | ||||
| let view = {}; | ||||
| let store = { | ||||
|     systems: { | ||||
|         data: [{ | ||||
|             friendly: 'Dungeons & Dragons 5e', | ||||
|             value: 'dnd5e' | ||||
|         }, { | ||||
|             friendly: 'HackMaster 4e (WIP)', | ||||
|             value: 'hackmaster4e' | ||||
|         }] | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * See Matching System Friendly and Value | ||||
|  */ | ||||
| const matchingSystemProp = (system, requested) => store.systems.data.find(d => d[requested === 'value' ? 'friendly' : 'value'] === system)[requested]; | ||||
| 
 | ||||
| /** | ||||
|  * Init Local Storage | ||||
|  */ | ||||
| const localStorageDefault = (key, val) => { | ||||
|     if (localStorage.getItem(key) === null) localStorage.setItem(key, val); | ||||
| }; | ||||
| let defaults = { | ||||
|     tableSortName: 'name', | ||||
|     tableSortRev: false, | ||||
|     system: 'dnd5e', | ||||
|     classes: [], | ||||
|     search: '' | ||||
| }; | ||||
| for (let cur in defaults) localStorageDefault(cur, defaults[cur]); | ||||
| 
 | ||||
| if (window.location.hash) { | ||||
|     let urlSystem = window.location.hash.substr(1).split('/')[0]; | ||||
|     localStorage.setItem('system', store.systems.data.find(d => d.value === urlSystem).value); | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Render Table Sort | ||||
|  */ | ||||
| store.tableSort = { | ||||
|     data: ['name', 'school', 'level'], | ||||
|     current: localStorage.getItem('tableSortName'), | ||||
|     rev: localStorage.getItem('tableSortRev') !== 'false' | ||||
| }; | ||||
| view.table_sort = Monkberry.render(table_sort, el('table-sort')); | ||||
| view.table_sort.update(store.tableSort); | ||||
| 
 | ||||
| /** | ||||
|  * Render Systems | ||||
|  */ | ||||
| store.systems.current = matchingSystemProp(localStorage.getItem('system'), 'friendly'); | ||||
| view.systems_list = Monkberry.render(system_list, el('system-list')); | ||||
| view.systems_list.update(store.systems); | ||||
| 
 | ||||
| /** | ||||
|  * Render Spell List | ||||
|  */ | ||||
| view.spell_list = Monkberry.render(spell_list, el('spell-list')); | ||||
| view.spell_list.update({data: false}); | ||||
| 
 | ||||
| /** | ||||
|  * Render Spell Print List | ||||
|  */ | ||||
| view.spell_list_print = Monkberry.render(spell_list_print, el('spell-list-print')); | ||||
| view.spell_list_print.update({}); | ||||
| 
 | ||||
| /** | ||||
|  * Render Spell Details | ||||
|  */ | ||||
| view.spell_details = Monkberry.render(spell_details, el('spell-details')); | ||||
| view.spell_details.update({data: {}}); | ||||
| 
 | ||||
| /** | ||||
|  * Render Class List | ||||
|  */ | ||||
| store.classes = { | ||||
|     data: [], | ||||
|     current: localStorage.getItem('classes') ? localStorage.getItem('classes').split(',') : [] | ||||
| }; | ||||
| view.class_list = Monkberry.render(class_list, el('class-list')); | ||||
| view.class_list.update({data: false}); | ||||
| 
 | ||||
| /** | ||||
|  * Render Search | ||||
|  */ | ||||
| store.search = localStorage.getItem('search'); | ||||
| view.search_field = Monkberry.render(search_field, el('search-field')); | ||||
| view.search_field.update({data: store.search}); | ||||
| 
 | ||||
| /** | ||||
|  * Discover Classes | ||||
|  */ | ||||
| const discoverClasses = spells => { | ||||
|     let classes = []; | ||||
|     spells.forEach(spell => { | ||||
|         if (!spell.classes) return; | ||||
|         spell.classes.forEach(current => { | ||||
|             if (!classes.includes(current)) classes.push(current); | ||||
|         }); | ||||
|     }); | ||||
|     return classes.sort((a, b) => a > b); | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Emphasis on important string bits | ||||
|  * @param {string} string | ||||
|  */ | ||||
| const emphasis = (str = '') => { | ||||
|     let keywords = ['constitution', 'con', 'intelligence', 'int', 'wisdom', 'wis', 'strength', 'str', 'dexterity', 'dex', 'charisma', 'cha', 'comeliness', 'com', 'saving throw', 'ability check', 'skill check']; | ||||
|     keywords.forEach(word => { | ||||
|         let r = new RegExp(` ${word} `, 'gi'); | ||||
|         str = str.replace(r, o => ` _${o.trim()}_ `); | ||||
|     }); | ||||
| 
 | ||||
|     str = str.replace(/[\s()<>]+\d+d*\d*(th)*[\s()<>]+/gi, o => ` **${o.trim()}** `); | ||||
|     return str; | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Description Prettifier | ||||
|  */ | ||||
| const descriptionPrettifier = description => { | ||||
|     let md = new Remarkable(); | ||||
|     description = Array.isArray(description) ? description.join('\n') : description; | ||||
|     description = emphasis(description); | ||||
|     description = md.render(description); | ||||
|     description = description.replace(/\n/g, '<br>'); | ||||
| 
 | ||||
|     return description; | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Init Spells | ||||
|  */ | ||||
| const initSpells = s => s.map((spell, i) => { | ||||
|     spell.selected = false; | ||||
|     spell.ranking = 0; | ||||
|     spell.level = parseInt(spell.level) ? spell.level : 0; | ||||
|     return spell; | ||||
| }); | ||||
| 
 | ||||
| /** | ||||
|  * Sort Spells | ||||
|  */ | ||||
| const sortSpells = (s, sortBy, reverse) => s.sort((a, b) => { | ||||
|     let hasFilters = store.classes.current.length || store.search.length; | ||||
|     let by = sortBy || hasFilters ? 'ranking' : store.tableSort.current; | ||||
|     let rev = reverse || hasFilters ? false : store.tableSort.rev; | ||||
|     if (by) { | ||||
|         if (a[by] < b[by]) return rev ? 1 : -1; | ||||
|         if (a[by] > b[by]) return rev ? -1 : 1; | ||||
|         return 0; | ||||
|     } | ||||
| }); | ||||
| 
 | ||||
| /** | ||||
|  * Search Spells | ||||
|  * @param {Array} spells | ||||
|  * @param {String} ex 'acid spray' | ||||
|  * @return {Array} filtered spells | ||||
|  */ | ||||
| const searchSpells = (spells, search) => { | ||||
|     // Convert search to array of words
 | ||||
|     search = search.split(' '); | ||||
|     // Clone spells so we don't affect the original
 | ||||
|     spells = clone(spells); | ||||
|     // Reset rankings
 | ||||
|     spells = spells.map(s => { | ||||
|         s.ranking = 0; | ||||
|         return s; | ||||
|     }); | ||||
|     // Rank spells by # of occurances of search terms
 | ||||
|     spells = spells.map(spell => { | ||||
|         search.forEach(term => { | ||||
|             let spellText = Object.values(spell).join(' '); | ||||
|             let regFind = new RegExp(term, 'gi'); | ||||
|             spell.ranking += (spellText.match(regFind) || []).length; | ||||
|         }); | ||||
|         return spell; | ||||
|     }); | ||||
|     // Return spells that matched at least something
 | ||||
|     return spells.filter(spell => spell.ranking); | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Filter Spells by Class | ||||
|  */ | ||||
| const filterSpellsByClass = (spells, classes) => { | ||||
|     // If no classes, default to all classes
 | ||||
|     classes = classes.length ? classes : store.classes.data; | ||||
|     // Clone spells so we don't affect the original
 | ||||
|     spells = clone(spells); | ||||
|     return spells.filter(spell => { | ||||
|         let spellClasses = spell.classes.join(' '); | ||||
|         let match = false; | ||||
|         classes.forEach(c => { | ||||
|             if (spellClasses.indexOf(c) >= 0) { | ||||
|                 match = true; | ||||
|                 return true; | ||||
|             } | ||||
|         }); | ||||
|         return match; | ||||
|     }); | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Apply Filters | ||||
|  * @returns {Array} of spells ranked based on searches and filters | ||||
|  */ | ||||
| let applyFilters = () => sortSpells( | ||||
|     searchSpells( | ||||
|         filterSpellsByClass( | ||||
|             store.spells, | ||||
|             store.classes.current | ||||
|         ), | ||||
|         store.search | ||||
|     ) | ||||
| ); | ||||
| 
 | ||||
| /** | ||||
|  * Spell Details Updating | ||||
|  */ | ||||
| const spellDetails = name => { | ||||
|     if (!name) { | ||||
|         view.spell_details.update({data: {}}); | ||||
|         $('body').removeClass('details'); | ||||
|     } else { | ||||
|         let data = clone(store.spells.find(spell => name === spell.name)); | ||||
|         data.description = descriptionPrettifier(data.description); | ||||
|         data.details = basicDetails.map(detail => { | ||||
|             if (data[detail]) { | ||||
|                 return { | ||||
|                     label: detail.replace('_', ' '), | ||||
|                     value: data[detail] | ||||
|                 }; | ||||
|             } | ||||
|         }); | ||||
|         if (data.components && data.components.raw) { | ||||
|             data.details.push({label: 'components', value: data.components.raw}); | ||||
|         } | ||||
| 
 | ||||
|         view.spell_details.update({ | ||||
|             data, | ||||
|             url: window.location.href | ||||
|         }); | ||||
|         componentHandler.upgradeDom(); | ||||
|         $('body').addClass('details'); | ||||
|         let clipboard = new Clipboard('.copy-to-clipboard'); | ||||
|         clipboard | ||||
|             .on('success', e => $('#toast')[0].MaterialSnackbar.showSnackbar({message: 'Copied link'})) | ||||
|             .on('error', e => $('#toast')[0].MaterialSnackbar.showSnackbar({message: 'Sorry! Unable to copy link'})); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Render Print Page | ||||
|  */ | ||||
| const renderPrint = () => { | ||||
|     let selectedSpells = $('form[data-selected]') | ||||
|         // Get array of items in form
 | ||||
|         .serializeArray() | ||||
|         // Find spells based on array from form
 | ||||
|         .map(sel => store.spells.find(spell => sel.value === spell.name)) | ||||
|         // Sort by level then alphabetically
 | ||||
|         .sort((a, b) => { | ||||
|             let aName = a.name.toLowerCase(); | ||||
|             let bName = b.name.toLowerCase(); | ||||
|             if (a.level > b.level) return 1; | ||||
|             if (a.level < b.level) return -1; | ||||
|             if (aName > bName) return 1; | ||||
|             if (aName < bName) return -1; | ||||
|             return 0; | ||||
|         }) | ||||
|         // Prettify Descriptions
 | ||||
|         .map(spell => { | ||||
|             spell = clone(spell); | ||||
|             spell.description = descriptionPrettifier(spell.description); | ||||
|             spell.details = basicDetails.map(detail => { | ||||
|                 if (spell[detail]) { | ||||
|                     return { | ||||
|                         label: detail.replace('_', ' '), | ||||
|                         value: spell[detail] | ||||
|                     }; | ||||
|                 } | ||||
|             }); | ||||
|             if (spell.components && spell.components.raw) { | ||||
|                 spell.details.push({label: 'components', value: spell.components.raw}); | ||||
|             } | ||||
|             return spell; | ||||
|         }); | ||||
|     view.spell_list_print.update({data: selectedSpells}); | ||||
|     if (selectedSpells.length) { | ||||
|         $('[data-action=print] [data-badge]').attr('data-badge', selectedSpells.length); | ||||
|         $('[data-action=print]').slideDown('fast'); | ||||
|     } else { | ||||
|         $('[data-action=print]').slideUp('fast'); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Event Bindings | ||||
|  */ | ||||
| $('body') | ||||
| // Listen for header sorts
 | ||||
| .on('click', '[data-action-sort]', e => { | ||||
|     let name = $(e.currentTarget).attr('data-action-sort'); | ||||
|     let rev = store.tableSort.current === name && !store.tableSort.rev; | ||||
|     store.tableSort.current = name; | ||||
|     store.tableSort.rev = rev; | ||||
|     localStorage.setItem('tableSortName', name); | ||||
|     localStorage.setItem('tableSortRev', rev); | ||||
|     view.spell_list.update({data: sortSpells(store.spells)}); | ||||
|     view.table_sort.update(store.tableSort); | ||||
|     componentHandler.upgradeDom(); | ||||
| }) | ||||
| // Listen for checkbox changes to filter spells
 | ||||
| .on('change', '[data-action-classtoggle]', e => { | ||||
|     let name = $(e.currentTarget).attr('data-action-classtoggle'); | ||||
|     let add = $(e.currentTarget).prop('checked'); | ||||
|     let index = store.classes.current.indexOf(name); | ||||
|     if (index === -1 && add) { | ||||
|         store.classes.current.push(name); | ||||
|     } else if (!add) store.classes.current.splice(index, 1); | ||||
|     store.tableSort.current = store.classes.current.length || store.search.length ? 'ranking' : null; | ||||
|     localStorage.setItem('tableSortName', store.tableSort.current); | ||||
|     localStorage.setItem('classes', store.classes.current); | ||||
|     view.spell_list.update({data: applyFilters()}); | ||||
|     view.table_sort.update({current: store.tableSort.current}); | ||||
|     componentHandler.upgradeDom(); | ||||
| }) | ||||
| // Listen to search to filter by
 | ||||
| .on('change keyup cut paste', '[data-action-search]', e => { | ||||
|     setTimeout(() => { // Delay for value to change
 | ||||
|         store.search = $(e.currentTarget).val(); | ||||
|         store.tableSort.current = store.search.length || store.classes.current.length ? 'ranking' : null; | ||||
|         store.tableSort.rev = false; | ||||
|         localStorage.setItem('search', store.search); | ||||
|         localStorage.setItem('tableSortName', store.tableSort.current); | ||||
|         localStorage.setItem('tableSortRev', store.tableSort.rev); | ||||
|         view.spell_list.update({data: applyFilters()}); | ||||
|         view.table_sort.update(store.tableSort); | ||||
|         componentHandler.upgradeDom(); | ||||
|     }, 0); | ||||
| }) | ||||
| // Listen for click on spells to open details
 | ||||
| .on('click', '[data-action-details]', e => { | ||||
|     let name = $(e.currentTarget).attr('data-action-details'); | ||||
|     if (name) { | ||||
|         window.location.hash = matchingSystemProp(store.systems.current, 'value') + '/' + name; | ||||
|     } else { | ||||
|         window.location.hash = ''; | ||||
|     } | ||||
|     spellDetails(name); | ||||
| }) | ||||
| // Stop propogation if dontprop clicked
 | ||||
| .on('click', '.dontprop', e => { | ||||
|     e.stopPropagation(); | ||||
| }) | ||||
| // Toggle All
 | ||||
| .on('change', 'label[for=table-header] input[type=checkbox]', e => { | ||||
|     $(e.target).closest('form').find('[name=selected]').each(function() { | ||||
|         this.checked = e.target.checked; | ||||
|         if(this.checked) $(this).closest('label').addClass('is-checked'); | ||||
|         else $(this).closest('label').removeClass('is-checked'); | ||||
|     }); | ||||
|     renderPrint(); | ||||
| }) | ||||
| .on('change', 'input[name=selected][type=checkbox]', renderPrint) | ||||
| .on('click', '[data-action=print]', e => { | ||||
|     window.print(); | ||||
| }); | ||||
| // Article Scroll with User
 | ||||
| $('.mdl-layout__content').on('scroll', debounce(() => { | ||||
|     let distance = $('.mdl-layout__content')[0].scrollTop; | ||||
|     $('[data-template=spell-details]').css('margin-top', distance); | ||||
| }, 10)); | ||||
| // System changed
 | ||||
| $('[data-action=system]').on('change', e => { | ||||
|     let system = $(e.currentTarget).val(); | ||||
|     let systemValue = matchingSystemProp(system, 'value'); | ||||
|     window.location.hash = ''; | ||||
|     spellDetails(''); | ||||
|     store.systems.current = system; | ||||
|     localStorage.setItem('system', systemValue); | ||||
|     view.spell_list.update({data: false}); | ||||
|     view.class_list.update({data: false}); | ||||
|     fetchSpells(systemValue); | ||||
| }) | ||||
| 
 | ||||
| /** | ||||
|  * Fetch Spells | ||||
|  */ | ||||
| const fetchSpells = (system = matchingSystemProp(store.systems.current, 'value')) => fetch(`./systems/${system}.json`) | ||||
|     .then(response => response.json()) | ||||
|     .then(spells => initSpells(spells)) | ||||
|     .then(spells => { | ||||
|         store.spells = spells; | ||||
|         store.classes.data = discoverClasses(spells); | ||||
|         view.spell_list.update({data: applyFilters()}); | ||||
|         view.class_list.update(store.classes); | ||||
|         componentHandler.upgradeDom(); | ||||
|         if (window.location.hash) spellDetails(window.location.hash.substr(1).split('/')[1]); | ||||
|         return spells; | ||||
|     }) | ||||
|     .catch(reason => console.error('Unable to retrieve spells list:', reason)); | ||||
| fetchSpells(); | ||||
|  | @ -1,19 +0,0 @@ | |||
| {% if data %} | ||||
|     {% for cur of data %} | ||||
|         <label class="mdl-navigation__link"> | ||||
|             <div class="mdl-switch mdl-js-switch mdl-js-ripple-effect"> | ||||
|                 {% if current.includes(cur) %} | ||||
|                     <input checked data-action-classtoggle="{{ cur }}" name="class" type="checkbox" class="mdl-switch__input" /> | ||||
|                 {% else %} | ||||
|                     <input data-action-classtoggle="{{ cur }}" name="class" type="checkbox" class="mdl-switch__input" /> | ||||
|                 {% endif %} | ||||
|                 <span class="mdl-switch__label"> | ||||
|                     {{ cur }} | ||||
|                 </span> | ||||
|             </div> | ||||
|         </label> | ||||
|     {% endfor %} | ||||
| {% else %} | ||||
|     <div class="mdl-spinner mdl-js-spinner is-active"></div> | ||||
| {% endif %} | ||||
| 
 | ||||
|  | @ -1 +0,0 @@ | |||
| <input value="{{ data }}" class="mdl-textfield__input" data-action-search type="text" id="fixed-header-drawer-exp" /> | ||||
|  | @ -1,27 +0,0 @@ | |||
| {% if data.name %} | ||||
|     <button data-action-details="" class="mdl-button mdl-js-button mdl-button--fab mdl-button--mini-fab"> | ||||
|       <i class="material-icons">close</i> | ||||
|     </button> | ||||
|     <h5 class="mdl-typography--display-1 mdl-color-text--teal-600">{{ data.name }}</h5> | ||||
|     <ul id="details"> | ||||
|         {% for detail of data.details %} | ||||
|             <li> | ||||
|                 <strong>{{ detail.label }}</strong> {{ detail.value }} | ||||
|             </li> | ||||
|         {% endfor %} | ||||
|     </ul> | ||||
|     <p id="description">{% unsafe data.description %}</p> | ||||
| 
 | ||||
|     <div class="mdl-textfield mdl-js-textfield" id="copy"> | ||||
|         <label class="mdl-button mdl-js-button mdl-button--icon copy-to-clipboard" for="share-url" data-clipboard-target="#share-url"> | ||||
|             <i class="material-icons">content_copy</i> | ||||
|         </label> | ||||
|         <input readonly class="mdl-textfield__input" type="text" id="share-url" value="{{ url }}"> | ||||
|     </div> | ||||
| {% else %} | ||||
|     <div id="empty"> | ||||
|         <h6 class="mdl-typography--title"> | ||||
|             Choose a Spell | ||||
|         </h6> | ||||
|     </div> | ||||
| {% endif %} | ||||
|  | @ -1,23 +0,0 @@ | |||
| {% for spell of data %} | ||||
|     <tr> | ||||
|         <td class="spell-name"> | ||||
|             <strong> | ||||
|                 {{ spell.name }} | ||||
|             </strong> | ||||
|         </td> | ||||
|         <td class="spell-level"> | ||||
|             {{ spell.level }} | ||||
|         </td> | ||||
|         <td class="spell-description"> | ||||
|             <ul id="details"> | ||||
|                 {% for detail of spell.details %} | ||||
|                     <li> | ||||
|                         <strong>{{ detail.label }}</strong> {{ detail.value }} | ||||
|                     </li> | ||||
|                 {% endfor %} | ||||
|             </ul> | ||||
| 
 | ||||
|             {% unsafe spell.description %} | ||||
|         </td> | ||||
|     </tr> | ||||
| {% endfor %} | ||||
|  | @ -1,40 +0,0 @@ | |||
| {% if data.length %} | ||||
|     {% for spell of data %} | ||||
|         {% if spell.name %} | ||||
|             <tr data-action-details="{{ spell.name }}"> | ||||
|                 <td class="hide-phone"> | ||||
|                     <label class="mdl-checkbox mdl-js-checkbox mdl-js-ripple-effect mdl-data-table__select dontprop"> | ||||
|                         <input type="checkbox" name="selected" value="{{ spell.name }}" class="mdl-checkbox__input dontprop" /> | ||||
|                     </label> | ||||
|                 </td> | ||||
|                 <td class="spell-name mdl-data-table__cell--non-numeric"> | ||||
|                     <strong> | ||||
|                         {{ spell.name }} | ||||
|                     </strong> | ||||
|                 </td> | ||||
|                 <td class="spell-school mdl-data-table__cell--non-numeric"> | ||||
|                     {{ spell.school }} | ||||
|                 </td> | ||||
|                 <td class="spell-level"> | ||||
|                     {{ spell.level }} | ||||
|                 </td> | ||||
|             </tr> | ||||
|         {% endif %} | ||||
|     {% endfor %} | ||||
| {% else %} | ||||
|     <tr class="do-nothing"> | ||||
|         <td colspan="4"> | ||||
|             {% if data %} | ||||
|                 <div class="text-center"> | ||||
|                     <i class="material-icons mdl-list__item-icon mdl-color-text--orange-600"> | ||||
|                         warning | ||||
|                     </i> | ||||
|                     <h5>No Results</h5> | ||||
|                     <h6>Try refining your filters in the sidebar.</h6> | ||||
|                 </div> | ||||
|             {% else %} | ||||
|                 <div class="mdl-spinner mdl-js-spinner is-active"></div> | ||||
|             {% endif %} | ||||
|         </td> | ||||
|     </tr> | ||||
| {% endif %} | ||||
|  | @ -1,11 +0,0 @@ | |||
| {% if data %} | ||||
|     <div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label getmdl-select"> | ||||
|         <input class="mdl-textfield__input" data-action="system" value="{{ current }}" type="text" id="system" readonly tabIndex="-1"/> | ||||
|         <label class="mdl-textfield__label mdl-color-text--white" for="system">System</label> | ||||
|         <ul class="mdl-menu mdl-menu--bottom-left mdl-js-menu" for="system"> | ||||
|             {% for system of data %} | ||||
|                 <li class="mdl-menu__item">{{ system.friendly }}</li> | ||||
|             {% endfor %} | ||||
|         </ul> | ||||
|     </div> | ||||
| {% endif %} | ||||
|  | @ -1,28 +0,0 @@ | |||
| <th class="hide-phone"> | ||||
|     <label class="mdl-checkbox mdl-js-checkbox mdl-js-ripple-effect mdl-data-table__select" for="table-header"> | ||||
|         <input type="checkbox" id="table-header" class="mdl-checkbox__input" /> | ||||
|     </label> | ||||
| </th> | ||||
| {% for name of data %} | ||||
|     <th data-action-sort="{{ name }}" class="mdl-data-table__cell--non-numeric {{ current === 'ranking' ? 'mdl-color-text--grey-200 do-nothing' : '' }}"> | ||||
|         <i class="material-icons mdl-list__item-icon"> | ||||
|             {% if name === 'level' %} | ||||
|                 exposure | ||||
|             {% endif %} | ||||
|             {% if name === 'name' %} | ||||
|                 flash_on | ||||
|             {% endif %} | ||||
|             {% if name === 'school' %} | ||||
|                 school | ||||
|             {% endif %} | ||||
|         </i> | ||||
| 
 | ||||
|         <span> | ||||
|               {{ name }} | ||||
|         </span> | ||||
| 
 | ||||
|         <i class="material-icons mdl-color-text--teal-600 mdl-list__item-icon {{ name === current ? 'mdl-color-text--teal-600' : 'mdl-color-text--grey-300' }}"> | ||||
|             {{ rev ? 'keyboard_arrow_up' : 'keyboard_arrow_down' }} | ||||
|         </i> | ||||
|     </th> | ||||
| {% endfor %} | ||||
							
								
								
									
										10890
									
								
								systems/dnd5e.json
									
										
									
									
									
								
							
							
						
						
									
										10890
									
								
								systems/dnd5e.json
									
										
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 sharpshark28
						sharpshark28