├── .gitignore ├── README.md ├── assets ├── icons │ ├── icon128.png │ ├── icon16.png │ └── icon48.png ├── logo.png └── logo_dark.png ├── css ├── designr.css └── styles.css ├── index.html ├── js ├── background.js ├── designr.js ├── libs │ ├── autorefresh.js │ ├── codemirror.css │ ├── codemirror.js │ ├── css.js │ ├── formatting.js │ ├── html-hint.js │ ├── htmlmixed.js │ ├── index.css │ ├── javascript.js │ ├── monokai.min.css │ ├── show-hint.css │ ├── show-hint.js │ ├── xml-hint.js │ └── xml.js └── script.js └── manifest.json /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | .env 21 | 22 | npm-debug.log* 23 | yarn-debug.log* 24 | yarn-error.log* 25 | 26 | /extension 27 | /designr/.env -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

designr logo

2 | 3 |

designr inspects CSS styles and saves snapshots of web components and designs

4 | 5 |

Chrome Web Store 6 | 7 |


8 | 9 |

🎨   Functionality  

10 |

designr is an open-source browser extension designed to inspect and save CSS styling on web pages. designr provides information about element styles and save the styles into a palette for later use. designr is a simple and intuitive way for designers and web developers to save CSS references.

11 |
12 | 13 |

🛠   Setup  

14 |

To get started with development, fork or clone the repository. Once the repository is installed, go to the extensions page in your brower. For example, the extension manager page for Chrome is chrome://extensions which will let you edit and upload the extension package. On the extension manager page, toggle Developer Mode on, click Load unpacked, and select the folder of the downloaded extension.

15 | 16 |
17 | 18 |

⚙️   Code Structure  

19 |
20 | The code for designr adheres to the following structure:

21 | 22 | | | | 23 | |---|---| 24 | |assets/| includes all assets for the extension | 25 | |css/designr.css| CSS file for the designr element inspector view| 26 | |css/styles.css|CSS file for the designr popup view| 27 | |js/libs|contains all JS code for libraries| 28 | |js/background.js|background JS code for designr| 29 | |js/designr.js|JS code for the designr element inspector view| 30 | |js/script.js|JS code for the designr popup view| 31 | |index.html|HTML code for the designr popup view | 32 |
33 | 34 |
35 | 36 |

💜   Contributing  

37 |

If you would like to contibute new features, bug fixes, or have any recommendations on how the extension can be improved, feel free to contribute by forking this repository, contributing a change that either resolve an issue or adds a new feature, and submitting a PR for review.

38 | -------------------------------------------------------------------------------- /assets/icons/icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ANG13T/designr/c3a2f370f1685b0e6226894f0bafc0836738263f/assets/icons/icon128.png -------------------------------------------------------------------------------- /assets/icons/icon16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ANG13T/designr/c3a2f370f1685b0e6226894f0bafc0836738263f/assets/icons/icon16.png -------------------------------------------------------------------------------- /assets/icons/icon48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ANG13T/designr/c3a2f370f1685b0e6226894f0bafc0836738263f/assets/icons/icon48.png -------------------------------------------------------------------------------- /assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ANG13T/designr/c3a2f370f1685b0e6226894f0bafc0836738263f/assets/logo.png -------------------------------------------------------------------------------- /assets/logo_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ANG13T/designr/c3a2f370f1685b0e6226894f0bafc0836738263f/assets/logo_dark.png -------------------------------------------------------------------------------- /css/designr.css: -------------------------------------------------------------------------------- 1 | #designr_block, 2 | #designr_center, 3 | #designr_footer, 4 | .designr_category, 5 | span.designr_property, 6 | #designr_block h1, 7 | #designr_block h2, 8 | #designr_block ul, 9 | #designr_block li, 10 | #designr_block span 11 | { 12 | font-family:"Lucida sans", helvetica, sans-serif !important; 13 | font-size:10px !important; 14 | z-index:9999 !important; 15 | padding:0 !important; 16 | margin:0 !important; 17 | text-indent:0px !important; 18 | text-align:left !important; 19 | visibility: visible !important; 20 | width:auto !important; 21 | height:auto !important; 22 | line-height: 20px; 23 | } 24 | 25 | #designr_block 26 | { 27 | display:none; 28 | min-width:300px !important; 29 | font-size:10px !important; 30 | color:#555 !important; 31 | position:absolute !important; 32 | background-color: #212328 !important; 33 | border: 1.5px solid white; 34 | } 35 | 36 | #designr_center 37 | { 38 | padding:10px 32px 0 32px !important; 39 | overflow:hidden !important; 40 | } 41 | 42 | #designr_footer 43 | { 44 | padding-top:10px; 45 | color: rgb(176, 195, 211) !important; 46 | text-align:center !important; 47 | width:332px !important; 48 | height:30px !important; 49 | display:block !important; 50 | } 51 | 52 | .designr_category 53 | { 54 | padding:0 5px !important; 55 | } 56 | 57 | #designr_block h2 58 | { 59 | padding-top:6px !important; 60 | color:#63a3eb !important; 61 | font-size:12px !important; 62 | text-align:left !important; 63 | letter-spacing:-0.5px !important; 64 | } 65 | 66 | #designr_block ul 67 | { 68 | padding:0px !important; 69 | padding-bottom: 10px !important; 70 | list-style:none !important; 71 | width:250px !important; 72 | } 73 | 74 | #designr_block li 75 | { 76 | padding-left:0px !important; 77 | color:#b6b6b6 !important; 78 | } 79 | 80 | 81 | #designr_block span.designr_property 82 | { 83 | color: white !important; 84 | float:left !important; 85 | width:100px !important; 86 | display:block !important; 87 | overflow:hidden !important; 88 | } 89 | -------------------------------------------------------------------------------- /css/styles.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | width: 25rem; 4 | height: 36rem; 5 | background-color: #212328; 6 | } 7 | 8 | body { 9 | margin: 0px; 10 | } 11 | 12 | .logo { 13 | height: 20vmin; 14 | margin-top: 4rem; 15 | pointer-events: none; 16 | } 17 | 18 | .caption { 19 | color: white; 20 | font-size: 16px; 21 | margin-bottom: 5px; 22 | } 23 | 24 | .App-header { 25 | background-color: #212328; 26 | min-height: 100vh; 27 | display: flex; 28 | flex-direction: column; 29 | align-items: center; 30 | justify-content: center; 31 | font-size: calc(10px + 2vmin); 32 | color: white; 33 | } 34 | 35 | .App-link { 36 | color: #61dafb; 37 | } 38 | 39 | .captions { 40 | text-align: left; 41 | margin-left: 3.5rem; 42 | } 43 | 44 | #view-settings:hover, #create-palette:hover, #back-palette-button:hover, #edit-palette-button:hover, #delete-palette-button:hover { 45 | background-color: white; 46 | color: black; 47 | transition: 0.5s; 48 | } 49 | 50 | .c-button { 51 | text-align: center !important; 52 | min-width: 80vw; 53 | padding: 15px; 54 | font-size: 1rem; 55 | transition: 0.4s; 56 | } 57 | 58 | .customButton { 59 | text-align: center !important; 60 | min-width: 70vw !important; 61 | padding: 15px; 62 | font-size: 1rem; 63 | transition: 0.5s; 64 | color: white; 65 | margin: auto; 66 | border: 2px solid white; 67 | text-decoration: none; 68 | outline: none; 69 | background: transparent; 70 | font-weight: bold; 71 | margin-bottom: 30px !important; 72 | display: block; 73 | border-radius: 5px; 74 | margin-top: 2rem; 75 | cursor: pointer; 76 | } 77 | 78 | .githubButton { 79 | margin-top: 0.5rem; 80 | margin-left: 32px; 81 | margin-right: 32px; 82 | } 83 | 84 | .customButton:hover { 85 | background: white; 86 | color: black; 87 | } 88 | 89 | 90 | .border-gradient { 91 | --angle: 0deg; 92 | border: 10px solid; 93 | border-radius: 5px; 94 | border-image: linear-gradient(var(--angle), #12c2e9, #c471ed, #f64f59) 1; 95 | animation: 5s rotate linear infinite; 96 | } 97 | 98 | .link { 99 | color: white; 100 | font-weight: bold; 101 | } 102 | 103 | .bottom { 104 | color: white; 105 | margin-top: 3rem; 106 | } 107 | 108 | @keyframes rotate { 109 | to { 110 | --angle: 360deg; 111 | } 112 | } 113 | 114 | @property --angle { 115 | syntax: ''; 116 | initial-value: 0deg; 117 | inherits: false; 118 | } 119 | 120 | 121 | /* Main Page */ 122 | 123 | .logo-nav { 124 | height: 3rem; 125 | } 126 | 127 | .nav { 128 | display: flex; 129 | justify-content: space-between; 130 | padding: 1.2rem; 131 | border-bottom: 1px solid white; 132 | } 133 | 134 | .nav .buttons { 135 | display: flex; 136 | width: 7rem; 137 | justify-content: space-around; 138 | margin-top: 6.5px; 139 | /* background-color: red; */ 140 | } 141 | 142 | .nav .buttons button, .nav .back-button { 143 | color: white; 144 | border: 1.5px solid white; 145 | border-radius: 4px; 146 | height: 2.4rem; 147 | width: 2.4rem; 148 | font-size: 15px; 149 | background: transparent; 150 | padding: 5px; 151 | } 152 | 153 | #main .table { 154 | width: 100%; 155 | color: white; 156 | text-align: left; 157 | margin-top: 10px; 158 | font-size: 14px !important; 159 | } 160 | 161 | 162 | #main .table-cell { 163 | display: flex; 164 | padding: 5px; 165 | margin-left: 15px; 166 | font-size: 15px; 167 | } 168 | 169 | #main .none-palette { 170 | color: white; 171 | font-size: 20px; 172 | margin-top: 7.7rem; 173 | } 174 | 175 | .sub-icon { 176 | font-size: 50px; 177 | margin-bottom: 15px; 178 | } 179 | 180 | #paletteTable { 181 | border-collapse:collapse; 182 | } 183 | 184 | #paletteTable tr { 185 | cursor: pointer; 186 | transition: 0.5s; 187 | height: 34px; 188 | padding-left: 10px; 189 | } 190 | 191 | #paletteTable .customcheckbox { 192 | padding-left: 10px; 193 | } 194 | 195 | #paletteTable tr:hover { 196 | background-color: #2e2f31; 197 | } 198 | 199 | #paletteTable .headRow:hover { 200 | cursor:default; 201 | background-color: transparent !important; 202 | } 203 | 204 | #paletteElementsTable .headRow:hover { 205 | cursor:default; 206 | background-color: transparent !important; 207 | } 208 | 209 | #paletteElementsTable .headRow { 210 | cursor: default; 211 | font-weight: bold; 212 | background-color: transparent !important; 213 | font-size: 14px; 214 | } 215 | 216 | #paletteElementsTable { 217 | border-collapse:collapse; 218 | width: 100%; 219 | color: white; 220 | display: block; 221 | height: 355px; 222 | overflow-y: scroll; 223 | margin-top: 10px; 224 | text-align: left; 225 | } 226 | 227 | #paletteElementsTable ::-webkit-scrollbar-thumb { 228 | background: white; 229 | } 230 | 231 | #paletteElementsTable td { 232 | width: 400px; 233 | } 234 | 235 | #paletteElementsTable tr { 236 | cursor: pointer; 237 | transition: 0.5s; 238 | height: 34px; 239 | width: 400px !important; 240 | padding-left: 10px; 241 | } 242 | 243 | 244 | #paletteElementsTable tr:hover { 245 | background-color: #2e2f31; 246 | } 247 | 248 | 249 | /* Modal */ 250 | 251 | .modal { 252 | display: flex; 253 | margin: auto !important; 254 | flex-direction: column; 255 | justify-content: center; 256 | gap: 0.4rem; 257 | width: 250px; 258 | padding: 1rem; 259 | min-height: 250px; 260 | position: absolute; 261 | z-index: 2; 262 | top: 22%; 263 | left: 15%; 264 | background-color: white; 265 | border: 1px solid #ddd; 266 | border-radius: 8px; 267 | } 268 | 269 | .error { 270 | border: 1.5px solid red !important; 271 | } 272 | 273 | .modal .flex { 274 | display: flex; 275 | align-items: center; 276 | justify-content: space-between; 277 | } 278 | 279 | .modal input { 280 | padding: 0.7rem 1rem; 281 | border: 1px solid #ddd; 282 | border-radius: 5px; 283 | font-size: 0.9em; 284 | } 285 | 286 | .modal p { 287 | font-size: 0.9rem; 288 | color: #777; 289 | margin: 0.4rem 0 0.2rem; 290 | } 291 | 292 | button { 293 | cursor: pointer; 294 | border: none; 295 | font-weight: 600; 296 | } 297 | 298 | #paletteNameInput { 299 | margin-bottom: 12px !important; 300 | font-size: 13px; 301 | outline: none; 302 | } 303 | 304 | .btn { 305 | padding: 0.8rem 1.4rem; 306 | font-weight: 700; 307 | background-color: #212328; 308 | color: white; 309 | margin-top: 10px; 310 | border-radius: 5px; 311 | text-align: center; 312 | font-size: 1em; 313 | transition: 0.4s; 314 | } 315 | 316 | .btn:hover { 317 | background-color: #000000; 318 | } 319 | 320 | .modal-title { 321 | margin-top: 0px; 322 | } 323 | 324 | .btn-close-modal { 325 | background-color: rgb(63, 62, 62); 326 | transition: 0.4s; 327 | } 328 | 329 | .btn-close-modal:hover { 330 | background-color: #343435; 331 | } 332 | 333 | #paletteLabel, #elementLabel { 334 | text-align: left; 335 | font-weight: bold; 336 | color: #2e2f31; 337 | margin-top: 4px; 338 | font-size: 12px; 339 | } 340 | 341 | .btn-open { 342 | position: absolute; 343 | bottom: 150px; 344 | } 345 | 346 | .btn-close { 347 | transform: translate(10px, -20px); 348 | padding: 0.5rem 0.7rem; 349 | background: #eee; 350 | border-radius: 50%; 351 | } 352 | 353 | .overlay { 354 | position: fixed; 355 | top: 0; 356 | bottom: 0; 357 | left: 0; 358 | right: 0; 359 | width: 100%; 360 | height: 100%; 361 | background: rgba(0, 0, 0, 0.5); 362 | backdrop-filter: blur(3px); 363 | z-index: 1; 364 | } 365 | 366 | .hidden { 367 | display: none; 368 | } 369 | 370 | #view-palette .palette-title, #view-element .palette-title { 371 | color: white; 372 | text-align: left; 373 | margin-left: 13px; 374 | font-weight: bold; 375 | font-size: 15px; 376 | margin-bottom: 0px; 377 | margin-top: 0px; 378 | } 379 | 380 | #view-palette .front-section, #view-element .front-section { 381 | display: flex; 382 | align-items: center; 383 | margin-top: 6.5px; 384 | } 385 | 386 | #view-element .back-button, #edit-element-button, #delete-element-button { 387 | transition: 0.4s; 388 | } 389 | 390 | #view-element .back-button:hover, #edit-element-button:hover, #delete-element-button:hover { 391 | color: #343435; 392 | background-color: white; 393 | } 394 | 395 | /* Elements View Display */ 396 | 397 | #select-element-button, #save-element-styles { 398 | padding: 0.8rem 1.4rem; 399 | width: 90%; 400 | margin: auto; 401 | margin-top: 20px; 402 | font-weight: 700; 403 | background-color: #212328; 404 | border: 2px solid white; 405 | color: white; 406 | border-radius: 5px; 407 | text-align: center; 408 | font-size: 1em; 409 | transition: 0.4s; 410 | } 411 | 412 | #select-element-button:hover, #save-element-styles:hover { 413 | color: #343435; 414 | background-color: white; 415 | } 416 | 417 | #view-palette .none-palette-element { 418 | color: white; 419 | font-size: 20px; 420 | margin-top: 5rem; 421 | } 422 | 423 | .firstCol { 424 | padding-left: 15px; 425 | } 426 | 427 | /* */ 428 | .editor { 429 | width: 100%; 430 | height: 68vh; 431 | overflow-y: scroll; 432 | background: rgb(41, 40, 40); 433 | } 434 | 435 | .code-display { 436 | min-height: 200px; 437 | } 438 | 439 | .code { 440 | width: 100%; 441 | height: 100%; 442 | } 443 | 444 | .code-section .title { 445 | color: white; 446 | } 447 | 448 | .sec-top { 449 | color: white; 450 | display: flex; 451 | justify-content: space-between; 452 | padding: 1.2rem; 453 | padding-top: 1rem; 454 | padding-bottom: 0.3rem; 455 | } 456 | 457 | .sec-buttons button { 458 | color: white; 459 | border: 1.5px solid white; 460 | border-radius: 4px; 461 | height: 1.8rem; 462 | width: 1.8rem; 463 | font-size: 12px; 464 | background: transparent; 465 | padding: 5px; 466 | } 467 | 468 | .code-title { 469 | margin-top: 10px; 470 | } -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 | 17 | 18 |
19 |

20 | 21 | Create custom web design palettes 22 |

23 | 24 |

25 | 26 | Save properties of selected elements 27 |

28 | 29 |

30 | 31 | Share and export designs with others 32 |

33 |
34 | 35 | 36 | 39 | 40 | 41 | 42 | Star on GitHub 43 | 44 | 45 |

Made with by Angelina Tsuboi

47 | 48 | 49 |
50 | 51 |
52 | 53 | 64 | 65 |
66 |

67 | 68 |
69 | No palettes created yet!
Click + above to make one!
70 | 71 |

72 |
73 | 74 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 |
NameCreated DateElements
99 | 100 |
101 | 102 |
103 | 121 | 122 | 132 | 133 | 134 | 135 | 144 | 145 | 146 | 147 |
148 |

149 | 150 |
151 | No elements selected yet!
Click + below to select one!
152 | 153 |

154 |
155 | 156 | 157 | 161 | 162 | 166 | 167 | 168 |
169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 |
Name
178 |
179 | 180 |
181 | 182 | 183 |
184 | 202 | 203 |
204 |
205 |

CSS Editor

206 |
207 | 210 | 211 | 214 | 215 | 218 |
219 |
220 | 221 |
222 |
223 |
224 |
225 |
226 |
227 | 228 | 238 | 239 | 240 | 241 | 250 | 251 | 252 | 253 |
254 |
255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | -------------------------------------------------------------------------------- /js/background.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * designr, A Google Chrome Extension for inspect CSS styles and save snapshots of web components and designs. 3 | * https://github.com/ANG13T/designr 4 | */ 5 | 6 | var designrLoaded = false; 7 | var selectedPaletteName = ""; 8 | 9 | chrome.runtime.onMessage.addListener ( 10 | function (request, sender, sendResponse) { 11 | if (request.action == "initiateElementSelect") { 12 | iniateElementSelect(request.data.tab); 13 | selectedPaletteName = request.data.palette; 14 | } 15 | 16 | if (request.action == "clickElement") { 17 | selectElementClick(request.data); 18 | } 19 | } 20 | ); 21 | 22 | function iniateElementSelect(tab) { 23 | if(tab == null || tab.url.indexOf("https://chrome.google.com") == 0 || tab.url.indexOf("chrome://") == 0 ) 24 | { 25 | console.log( "designr doesn't work on Google Chrome webstore!" ); 26 | 27 | return; 28 | } 29 | 30 | chrome.scripting.executeScript({target: {tabId: tab.id}, files:['js/designr.js']}); 31 | chrome.scripting.insertCSS({target: {tabId: tab.id}, files:['css/designr.css']}); 32 | 33 | designrLoaded = true; 34 | } 35 | 36 | function selectElementClick(element) { 37 | chrome.storage.local.get({ palettes: [] }, function (result) { 38 | let resultPal = result.palettes; 39 | resultPal.forEach((pal) => { 40 | if(pal.name == selectedPaletteName) { 41 | if(pal.elementsData) { 42 | var contains = false; 43 | pal.elementsData.forEach((eData) => { 44 | if(eData.css == element.css) { 45 | contains = true; 46 | } 47 | }) 48 | 49 | if (!contains) { 50 | pal.elementsData.push(element); 51 | } 52 | } else { 53 | pal.elementsData = []; 54 | } 55 | } 56 | }); 57 | 58 | chrome.storage.local.set({ palettes: resultPal }) 59 | }); 60 | } 61 | 62 | 63 | function cssCiewerDebugEl( info, tab ) 64 | { 65 | chrome.scripting.executeScript({ 66 | target: {tabId: tab.id}, 67 | func:'designrCopyCssToConsole("el")' 68 | }) 69 | } 70 | 71 | function cssCiewerDebugElId( info, tab ) 72 | { 73 | chrome.scripting.executeScript({ 74 | target: {tabId: tab.id}, 75 | func:'designrCopyCssToConsole("id")' 76 | }) 77 | } 78 | 79 | function cssCiewerDebugElTagName( info, tab ) 80 | { 81 | chrome.scripting.executeScript({ 82 | target: {tabId: tab.id}, 83 | func: 'designrCopyCssToConsole("tagName")' 84 | }) 85 | } 86 | 87 | function cssCiewerDebugElClassName( info, tab ) 88 | { 89 | chrome.scripting.executeScript({ 90 | target: {tabId: tab.id}, 91 | func: 'designrCopyCssToConsole("className")' 92 | }) 93 | } 94 | 95 | function cssCiewerDebugElStyle( info, tab ) 96 | { 97 | chrome.scripting.executeScript({ 98 | target: {tabId: tab.id}, 99 | func: 'designrCopyCssToConsole("style")' 100 | }) 101 | } 102 | 103 | function cssCiewerDebugElCssText( info, tab ) 104 | { 105 | chrome.scripting.executeScript({ 106 | target: {tabId: tab.id}, 107 | func: 'designrCopyCssToConsole("cssText")' 108 | }) 109 | } 110 | 111 | function cssCiewerDebugElGetComputedStyle( info, tab ) 112 | { 113 | chrome.scripting.executeScript({ 114 | target: {tabId: tab.id}, 115 | func: 'designrCopyCssToConsole("getComputedStyle")' 116 | }) 117 | } 118 | 119 | function cssCiewerDebugElSimpleCssDefinition( info, tab ) 120 | { 121 | chrome.scripting.executeScript({ 122 | target: {tabId: tab.id}, 123 | func: 'designrCopyCssToConsole("simpleCssDefinition")' 124 | }) 125 | } 126 | -------------------------------------------------------------------------------- /js/designr.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * designr, A Google Chrome Extension for inspect CSS styles and save snapshots of web components and designs. 3 | * https://github.com/ANG13T/designr 4 | */ 5 | 6 | var designr_element 7 | 8 | var designr_element_cssDefinition 9 | 10 | var designr_container 11 | 12 | var designr_current_element 13 | 14 | // CSS Properties 15 | 16 | var designr_pGeneral = new Array( 17 | 'element', 18 | 'class' 19 | ); 20 | 21 | var designr_pFont = new Array( 22 | 'font-family', 23 | 'font-size', 24 | 'font-style', 25 | 'font-variant', 26 | 'font-weight', 27 | 'letter-spacing', 28 | 'line-height', 29 | 'text-decoration', 30 | 'text-align', 31 | 'text-indent', 32 | 'text-transform', 33 | 'vertical-align', 34 | 'white-space', 35 | 'word-spacing' 36 | ); 37 | 38 | var designr_pColorBg = new Array( 39 | 'background-attachment', 40 | 'background-color', 41 | 'background-image', 42 | 'background-position', 43 | 'background-repeat', 44 | 'color' 45 | ); 46 | 47 | var designr_pBox = new Array( 48 | 'height', 49 | 'width', 50 | 'border', 51 | 'border-top', 52 | 'border-right', 53 | 'border-bottom', 54 | 'border-left', 55 | 'margin', 56 | 'padding', 57 | 'max-height', 58 | 'min-height', 59 | 'max-width', 60 | 'min-width' 61 | ); 62 | 63 | var designr_pPositioning = new Array( 64 | 'position', 65 | 'top', 66 | 'bottom', 67 | 'right', 68 | 'left', 69 | 'float', 70 | 'display', 71 | 'clear', 72 | 'z-index' 73 | ); 74 | 75 | var designr_pList = new Array( 76 | 'list-style-image', 77 | 'list-style-type', 78 | 'list-style-position' 79 | ); 80 | 81 | var designr_pTable = new Array( 82 | 'border-collapse', 83 | 'border-spacing', 84 | 'caption-side', 85 | 'empty-cells', 86 | 'table-layout' 87 | ); 88 | 89 | var designr_pMisc = new Array( 90 | 'overflow', 91 | 'cursor', 92 | 'visibility' 93 | ); 94 | 95 | var designr_pEffect = new Array( 96 | 'transform', 97 | 'transition', 98 | 'outline', 99 | 'outline-offset', 100 | 'box-sizing', 101 | 'resize', 102 | 'text-shadow', 103 | 'text-overflow', 104 | 'word-wrap', 105 | 'box-shadow', 106 | 'border-top-left-radius', 107 | 'border-top-right-radius', 108 | 'border-bottom-left-radius', 109 | 'border-bottom-right-radius' 110 | ); 111 | 112 | // CSS Property categories 113 | var designr_categories = { 114 | 'pGeneral' : designr_pGeneral, 115 | 'pFontText' : designr_pFont, 116 | 'pColorBg' : designr_pColorBg, 117 | 'pBox' : designr_pBox, 118 | 'pPositioning' : designr_pPositioning, 119 | 'pList' : designr_pList, 120 | 'pTable' : designr_pTable, 121 | 'pMisc' : designr_pMisc, 122 | 'pEffect' : designr_pEffect 123 | }; 124 | 125 | var designr_categoriesTitle = { 126 | 'pGeneral' : 'Element & Class', 127 | 'pFontText' : 'Font & Text', 128 | 'pColorBg' : 'Color & Background', 129 | 'pBox' : 'Box', 130 | 'pPositioning' : 'Positioning', 131 | 'pList' : 'List', 132 | 'pTable' : 'Table', 133 | 'pMisc' : 'Miscellaneous', 134 | 'pEffect' : 'Effects' 135 | }; 136 | 137 | // Table tagnames 138 | var designr_tableTagNames = new Array( 139 | 'TABLE', 140 | 'CAPTION', 141 | 'THEAD', 142 | 'TBODY', 143 | 'TFOOT', 144 | 'COLGROUP', 145 | 'COL', 146 | 'TR', 147 | 'TH', 148 | 'TD' 149 | ); 150 | 151 | var designr_listTagNames = new Array( 152 | 'UL', 153 | 'LI', 154 | 'DD', 155 | 'DT', 156 | 'OL' 157 | ); 158 | 159 | // Hexadecimal 160 | var designr_hexa = new Array( 161 | '0', 162 | '1', 163 | '2', 164 | '3', 165 | '4', 166 | '5', 167 | '6', 168 | '7', 169 | '8', 170 | '9', 171 | 'A', 172 | 'B', 173 | 'C', 174 | 'D', 175 | 'E', 176 | 'F' 177 | ); 178 | 179 | /* 180 | ** Utils 181 | */ 182 | 183 | function GetCurrentDocument() 184 | { 185 | return window.document; 186 | } 187 | 188 | function IsInArray(array, name) 189 | { 190 | for (var i = 0; i < array.length; i++) { 191 | if (name == array[i]) 192 | return true; 193 | } 194 | 195 | return false; 196 | } 197 | 198 | function DecToHex(nb) 199 | { 200 | var nbHexa = ''; 201 | 202 | nbHexa += designr_hexa[Math.floor(nb / 16)]; 203 | nb = nb % 16; 204 | nbHexa += designr_hexa[nb]; 205 | 206 | return nbHexa; 207 | } 208 | 209 | function RGBToHex(str) 210 | { 211 | var start = str.search(/\(/) + 1; 212 | var end = str.search(/\)/); 213 | 214 | str = str.slice(start, end); 215 | 216 | var hexValues = str.split(', '); 217 | var hexStr = '#'; 218 | 219 | for (var i = 0; i < hexValues.length; i++) { 220 | hexStr += DecToHex(hexValues[i]); 221 | } 222 | 223 | if( hexStr == "#00000000" ){ 224 | hexStr = "#FFFFFF"; 225 | } 226 | 227 | hexStr = ' ' + hexStr; 228 | 229 | return hexStr; 230 | } 231 | 232 | function GetFileName(str) 233 | { 234 | var start = str.search(/\(/) + 1; 235 | var end = str.search(/\)/); 236 | 237 | str = str.slice(start, end); 238 | 239 | var path = str.split('/'); 240 | 241 | return path[path.length - 1]; 242 | } 243 | 244 | function RemoveExtraFloat(nb) 245 | { 246 | nb = nb.substr(0, nb.length - 2); 247 | 248 | return Math.round(nb) + 'px'; 249 | } 250 | 251 | /* 252 | * CSSFunc 253 | */ 254 | 255 | function GetCSSProperty(element, property) 256 | { 257 | return element.getPropertyValue(property); 258 | } 259 | 260 | function SetCSSProperty(element, property, tagName = '', className = '', id = '') 261 | { 262 | var document = GetCurrentDocument(); 263 | var li = document.getElementById('designr_' + property); 264 | 265 | if (property == "element") { 266 | li.lastChild.innerHTML = " : " + tagName.toLowerCase(); 267 | } else if(property == "class") { 268 | li.lastChild.innerHTML = " : " + (id == '' ? '' : ' #' + id) + (className == '' ? '' : ' .' + className) + "\n"; 269 | } else { 270 | li.lastChild.innerHTML = " : " + element.getPropertyValue(property); 271 | } 272 | } 273 | 274 | function SetCSSPropertyIf(element, property, condition) 275 | { 276 | var document = GetCurrentDocument(); 277 | var li = document.getElementById('designr_' + property); 278 | 279 | if (condition) { 280 | li.lastChild.innerHTML = " : " + element.getPropertyValue(property); 281 | li.style.display = 'block'; 282 | 283 | return 1; 284 | } 285 | else { 286 | li.style.display = 'none'; 287 | 288 | return 0; 289 | } 290 | } 291 | 292 | function SetCSSPropertyValue(element, property, value) 293 | { 294 | var document = GetCurrentDocument(); 295 | var li = document.getElementById('designr_' + property); 296 | 297 | li.lastChild.innerHTML = " : " + value; 298 | li.style.display = 'block'; 299 | } 300 | 301 | function SetCSSPropertyValueIf(element, property, value, condition) 302 | { 303 | var document = GetCurrentDocument(); 304 | var li = document.getElementById('designr_' + property); 305 | 306 | if (condition) { 307 | li.lastChild.innerHTML = " : " + value; 308 | li.style.display = 'block'; 309 | 310 | return 1; 311 | } 312 | else { 313 | li.style.display = 'none'; 314 | 315 | return 0; 316 | } 317 | } 318 | 319 | function HideCSSProperty(property) 320 | { 321 | var document = GetCurrentDocument(); 322 | var li = document.getElementById('designr_' + property); 323 | 324 | li.style.display = 'none'; 325 | } 326 | 327 | function HideCSSCategory(category) 328 | { 329 | var document = GetCurrentDocument(); 330 | var div = document.getElementById('designr_' + category); 331 | 332 | div.style.display = 'none'; 333 | } 334 | 335 | function ShowCSSCategory(category) 336 | { 337 | var document = GetCurrentDocument(); 338 | var div = document.getElementById('designr_' + category); 339 | 340 | div.style.display = 'block'; 341 | } 342 | 343 | function UpdateGeneral(element, tagName, className, id) 344 | { 345 | SetCSSProperty(element, 'element', tagName, className, id); 346 | SetCSSProperty(element, 'class', tagName, className, id); 347 | } 348 | 349 | function UpdatefontText(element) 350 | { 351 | // Font 352 | SetCSSProperty(element, 'font-family'); 353 | SetCSSProperty(element, 'font-size'); 354 | 355 | SetCSSPropertyIf(element, 'font-weight' , GetCSSProperty(element, 'font-weight') != '400'); 356 | SetCSSPropertyIf(element, 'font-variant' , GetCSSProperty(element, 'font-variant') != 'normal'); 357 | SetCSSPropertyIf(element, 'font-style' , GetCSSProperty(element, 'font-style') != 'normal'); 358 | 359 | // Text 360 | SetCSSPropertyIf(element, 'letter-spacing' , GetCSSProperty(element, 'letter-spacing') != 'normal'); 361 | SetCSSPropertyIf(element, 'line-height' , GetCSSProperty(element, 'line-height') != 'normal'); 362 | SetCSSPropertyIf(element, 'text-decoration', GetCSSProperty(element, 'text-decoration') != 'none'); 363 | SetCSSPropertyIf(element, 'text-align' , GetCSSProperty(element, 'text-align') != 'start'); 364 | SetCSSPropertyIf(element, 'text-indent' , GetCSSProperty(element, 'text-indent') != '0px'); 365 | SetCSSPropertyIf(element, 'text-transform' , GetCSSProperty(element, 'text-transform') != 'none'); 366 | SetCSSPropertyIf(element, 'vertical-align' , GetCSSProperty(element, 'vertical-align') != 'baseline'); 367 | SetCSSPropertyIf(element, 'white-space' , GetCSSProperty(element, 'white-space') != 'normal'); 368 | SetCSSPropertyIf(element, 'word-spacing' , GetCSSProperty(element, 'word-spacing') != 'normal'); 369 | } 370 | 371 | function UpdateColorBg(element) 372 | { 373 | // Color 374 | SetCSSPropertyValue(element, 'color', RGBToHex(GetCSSProperty(element, 'color'))); 375 | 376 | // Background 377 | SetCSSPropertyValueIf(element, 'background-color', RGBToHex(GetCSSProperty(element, 'background-color')), GetCSSProperty(element, 'background-color') != 'transparent'); 378 | SetCSSPropertyIf(element, 'background-attachment', GetCSSProperty(element, 'background-attachment') != 'scroll'); 379 | SetCSSPropertyValueIf(element, 'background-image', GetFileName(GetCSSProperty(element, 'background-image')), GetCSSProperty(element, 'background-image') != 'none'); 380 | SetCSSPropertyIf(element, 'background-position' , GetCSSProperty(element, 'background-position') != ''); 381 | SetCSSPropertyIf(element, 'background-repeat' , GetCSSProperty(element, 'background-repeat') != 'repeat'); 382 | } 383 | 384 | function UpdateBox(element) 385 | { 386 | // Width/Height 387 | SetCSSPropertyIf(element, 'height', RemoveExtraFloat(GetCSSProperty(element, 'height')) != 'auto'); 388 | SetCSSPropertyIf(element, 'width', RemoveExtraFloat(GetCSSProperty(element, 'width')) != 'auto'); 389 | 390 | // Border 391 | var borderTop = RemoveExtraFloat(GetCSSProperty(element, 'border-top-width')) + ' ' + GetCSSProperty(element, 'border-top-style') + ' ' + RGBToHex(GetCSSProperty(element, 'border-top-color')); 392 | var borderBottom = RemoveExtraFloat(GetCSSProperty(element, 'border-bottom-width')) + ' ' + GetCSSProperty(element, 'border-bottom-style') + ' ' + RGBToHex(GetCSSProperty(element, 'border-bottom-color')); 393 | var borderRight = RemoveExtraFloat(GetCSSProperty(element, 'border-right-width')) + ' ' + GetCSSProperty(element, 'border-right-style') + ' ' + RGBToHex(GetCSSProperty(element, 'border-right-color')); 394 | var borderLeft = RemoveExtraFloat(GetCSSProperty(element, 'border-left-width')) + ' ' + GetCSSProperty(element, 'border-left-style') + ' ' + RGBToHex(GetCSSProperty(element, 'border-left-color')); 395 | 396 | if (borderTop == borderBottom && borderBottom == borderRight && borderRight == borderLeft && GetCSSProperty(element, 'border-top-style') != 'none') { 397 | SetCSSPropertyValue(element, 'border', borderTop); 398 | 399 | HideCSSProperty('border-top'); 400 | HideCSSProperty('border-bottom'); 401 | HideCSSProperty('border-right'); 402 | HideCSSProperty('border-left'); 403 | } 404 | else { 405 | SetCSSPropertyValueIf(element, 'border-top' , borderTop , GetCSSProperty(element, 'border-top-style') != 'none'); 406 | SetCSSPropertyValueIf(element, 'border-bottom', borderBottom, GetCSSProperty(element, 'border-bottom-style') != 'none'); 407 | SetCSSPropertyValueIf(element, 'border-right' , borderRight , GetCSSProperty(element, 'border-right-style') != 'none'); 408 | SetCSSPropertyValueIf(element, 'border-left' , borderLeft , GetCSSProperty(element, 'border-left-style') != 'none'); 409 | 410 | HideCSSProperty('border'); 411 | } 412 | 413 | // Margin 414 | var marginTop = RemoveExtraFloat(GetCSSProperty(element, 'margin-top')); 415 | var marginBottom = RemoveExtraFloat(GetCSSProperty(element, 'margin-bottom')); 416 | var marginRight = RemoveExtraFloat(GetCSSProperty(element, 'margin-right')); 417 | var marginLeft = RemoveExtraFloat(GetCSSProperty(element, 'margin-left')); 418 | var margin = (marginTop == '0px' ? '0' : marginTop) + ' ' + (marginRight == '0px' ? '0' : marginRight) + ' ' + (marginBottom == '0px' ? '0' : marginBottom) + ' ' + (marginLeft == '0px' ? '0' : marginLeft); 419 | 420 | SetCSSPropertyValueIf(element, 'margin', margin, margin != '0 0 0 0'); 421 | 422 | // padding 423 | var paddingTop = RemoveExtraFloat(GetCSSProperty(element, 'padding-top')); 424 | var paddingBottom = RemoveExtraFloat(GetCSSProperty(element, 'padding-bottom')); 425 | var paddingRight = RemoveExtraFloat(GetCSSProperty(element, 'padding-right')); 426 | var paddingLeft = RemoveExtraFloat(GetCSSProperty(element, 'padding-left')); 427 | var padding = (paddingTop == '0px' ? '0' : paddingTop) + ' ' + (paddingRight == '0px' ? '0' : paddingRight) + ' ' + (paddingBottom == '0px' ? '0' : paddingBottom) + ' ' + (paddingLeft == '0px' ? '0' : paddingLeft); 428 | 429 | SetCSSPropertyValueIf(element, 'padding', padding, padding != '0 0 0 0'); 430 | 431 | // Max/Min Width/Height 432 | SetCSSPropertyIf(element, 'min-height', GetCSSProperty(element, 'min-height') != '0px'); 433 | SetCSSPropertyIf(element, 'max-height', GetCSSProperty(element, 'max-height') != 'none'); 434 | SetCSSPropertyIf(element, 'min-width' , GetCSSProperty(element, 'min-width') != '0px'); 435 | SetCSSPropertyIf(element, 'max-width' , GetCSSProperty(element, 'max-width') != 'none'); 436 | } 437 | 438 | function UpdatePositioning(element) 439 | { 440 | SetCSSPropertyIf(element, 'position', GetCSSProperty(element, 'position') != 'static'); 441 | SetCSSPropertyIf(element, 'top' , GetCSSProperty(element, 'top') != 'auto'); 442 | SetCSSPropertyIf(element, 'bottom' , GetCSSProperty(element, 'bottom') != 'auto'); 443 | SetCSSPropertyIf(element, 'right' , GetCSSProperty(element, 'right') != 'auto'); 444 | SetCSSPropertyIf(element, 'left' , GetCSSProperty(element, 'left') != 'auto'); 445 | SetCSSPropertyIf(element, 'float' , GetCSSProperty(element, 'float') != 'none'); 446 | 447 | SetCSSProperty(element, 'display'); 448 | 449 | SetCSSPropertyIf(element, 'clear' , GetCSSProperty(element, 'clear') != 'none'); 450 | SetCSSPropertyIf(element, 'z-index' , GetCSSProperty(element, 'z-index') != 'auto'); 451 | } 452 | 453 | function UpdateTable(element, tagName) 454 | { 455 | if (IsInArray(designr_tableTagNames, tagName)) { 456 | var nbProperties = 0; 457 | 458 | nbProperties += SetCSSPropertyIf(element, 'border-collapse', GetCSSProperty(element, 'border-collapse') != 'separate'); 459 | nbProperties += SetCSSPropertyIf(element, 'border-spacing' , GetCSSProperty(element, 'border-spacing') != '0px 0px'); 460 | nbProperties += SetCSSPropertyIf(element, 'caption-side' , GetCSSProperty(element, 'caption-side') != 'top'); 461 | nbProperties += SetCSSPropertyIf(element, 'empty-cells' , GetCSSProperty(element, 'empty-cells') != 'show'); 462 | nbProperties += SetCSSPropertyIf(element, 'table-layout' , GetCSSProperty(element, 'table-layout') != 'auto'); 463 | 464 | if (nbProperties > 0) 465 | ShowCSSCategory('pTable'); 466 | else 467 | HideCSSCategory('pTable'); 468 | } 469 | else { 470 | HideCSSCategory('pTable'); 471 | } 472 | } 473 | 474 | function UpdateList(element, tagName) 475 | { 476 | if (IsInArray(designr_listTagNames, tagName)) { 477 | ShowCSSCategory('pList'); 478 | 479 | var listStyleImage = GetCSSProperty(element, 'list-style-image'); 480 | 481 | if (listStyleImage == 'none') { 482 | SetCSSProperty(element, 'list-style-type'); 483 | HideCSSProperty('list-style-image'); 484 | } 485 | else { 486 | SetCSSPropertyValue(element, 'list-style-image', listStyleImage); 487 | HideCSSProperty('list-style-type'); 488 | } 489 | 490 | SetCSSProperty(element, 'list-style-position'); 491 | } 492 | else { 493 | HideCSSCategory('pList'); 494 | } 495 | } 496 | 497 | function UpdateMisc(element) 498 | { 499 | var nbProperties = 0; 500 | 501 | nbProperties += SetCSSPropertyIf(element, 'overflow' , GetCSSProperty(element, 'overflow') != 'visible'); 502 | nbProperties += SetCSSPropertyIf(element, 'cursor' , GetCSSProperty(element, 'cursor') != 'auto'); 503 | nbProperties += SetCSSPropertyIf(element, 'visibility', GetCSSProperty(element, 'visibility') != 'visible'); 504 | 505 | if (nbProperties > 0) 506 | ShowCSSCategory('pMisc'); 507 | else 508 | HideCSSCategory('pMisc'); 509 | } 510 | 511 | function UpdateEffects(element) 512 | { 513 | var nbProperties = 0; 514 | 515 | nbProperties += SetCSSPropertyIf(element, 'transform' , GetCSSProperty(element, 'transform') ); 516 | nbProperties += SetCSSPropertyIf(element, 'transition' , GetCSSProperty(element, 'transition') ); 517 | nbProperties += SetCSSPropertyIf(element, 'outline' , GetCSSProperty(element, 'outline') ); 518 | nbProperties += SetCSSPropertyIf(element, 'outline-offset' , GetCSSProperty(element, 'outline-offset') != '0px'); 519 | nbProperties += SetCSSPropertyIf(element, 'box-sizing' , GetCSSProperty(element, 'box-sizing') != 'content-box'); 520 | nbProperties += SetCSSPropertyIf(element, 'resize' , GetCSSProperty(element, 'resize') != 'none'); 521 | 522 | nbProperties += SetCSSPropertyIf(element, 'text-shadow' , GetCSSProperty(element, 'text-shadow') != 'none'); 523 | nbProperties += SetCSSPropertyIf(element, 'text-overflow' , GetCSSProperty(element, 'text-overflow') != 'clip'); 524 | nbProperties += SetCSSPropertyIf(element, 'word-wrap' , GetCSSProperty(element, 'word-wrap') != 'normal'); 525 | nbProperties += SetCSSPropertyIf(element, 'box-shadow' , GetCSSProperty(element, 'box-shadow') != 'none'); 526 | 527 | nbProperties += SetCSSPropertyIf(element, 'border-top-left-radius' , GetCSSProperty(element, 'border-top-left-radius') != '0px'); 528 | nbProperties += SetCSSPropertyIf(element, 'border-top-right-radius' , GetCSSProperty(element, 'border-top-right-radius') != '0px'); 529 | nbProperties += SetCSSPropertyIf(element, 'border-bottom-left-radius' , GetCSSProperty(element, 'border-bottom-left-radius') != '0px'); 530 | nbProperties += SetCSSPropertyIf(element, 'border-bottom-right-radius', GetCSSProperty(element, 'border-bottom-right-radius') != '0px'); 531 | 532 | if (nbProperties > 0) 533 | ShowCSSCategory('pEffect'); 534 | else 535 | HideCSSCategory('pEffect'); 536 | } 537 | 538 | /* 539 | ** Event Handlers 540 | */ 541 | 542 | function designrClick(e) 543 | { 544 | var element = document.defaultView.getComputedStyle(this, null); 545 | console.log("click something", element) 546 | 547 | let result = {}; 548 | 549 | var designr_element_title = this.tagName.toLowerCase() + (this.id == '' ? '' : ' #' + this.id) + (this.className == '' ? '' : ' .' + this.className); 550 | 551 | designr_element_cssDefinition = this.tagName.toLowerCase() + (this.id == '' ? '' : ' #' + this.id) + (this.className == '' ? '' : ' .' + this.className) + " {\n"; 552 | 553 | designr_element_cssDefinition += "\t/* Font & Text */\n"; 554 | for (var i = 0; i < designr_pFont.length; i++) { 555 | result[designr_pFont[i]] = element.getPropertyValue( designr_pFont[i] ); 556 | designr_element_cssDefinition += "\t" + designr_pFont[i] + ': ' + element.getPropertyValue( designr_pFont[i] ) + ";\n"; 557 | } 558 | 559 | designr_element_cssDefinition += "\n\t/* Color & Background */\n"; 560 | 561 | for (var i = 0; i < designr_pColorBg.length; i++) { 562 | result[designr_pColorBg[i]] = element.getPropertyValue( designr_pColorBg[i] ); 563 | designr_element_cssDefinition += "\t" + designr_pColorBg[i] + ': ' + element.getPropertyValue( designr_pColorBg[i] ) + ";\n"; 564 | } 565 | 566 | designr_element_cssDefinition += "\n\t/* Box */\n"; 567 | 568 | for (var i = 0; i < designr_pBox.length; i++) { 569 | result[designr_pBox[i]] = element.getPropertyValue( designr_pBox[i] ); 570 | designr_element_cssDefinition += "\t" + designr_pBox[i] + ': ' + element.getPropertyValue( designr_pBox[i] ) + ";\n"; 571 | } 572 | 573 | designr_element_cssDefinition += "\n\t/* Positioning */\n"; 574 | 575 | for (var i = 0; i < designr_pPositioning.length; i++) { 576 | result[designr_pPositioning[i]] = element.getPropertyValue( designr_pPositioning[i] ); 577 | designr_element_cssDefinition += "\t" + designr_pPositioning[i] + ': ' + element.getPropertyValue( designr_pPositioning[i] ) + ";\n"; 578 | } 579 | 580 | designr_element_cssDefinition += "\n\t/* List */\n"; 581 | 582 | for (var i = 0; i < designr_pList.length; i++) { 583 | result[designr_pList[i]] = element.getPropertyValue( designr_pList[i] ); 584 | designr_element_cssDefinition += "\t" + designr_pList[i] + ': ' + element.getPropertyValue( designr_pList[i] ) + ";\n"; 585 | } 586 | 587 | designr_element_cssDefinition += "\n\t/* Table */\n"; 588 | 589 | for (var i = 0; i < designr_pTable.length; i++) { 590 | result[designr_pTable[i]] = element.getPropertyValue( designr_pTable[i] ); 591 | designr_element_cssDefinition += "\t" + designr_pTable[i] + ': ' + element.getPropertyValue( designr_pTable[i] ) + ";\n"; 592 | } 593 | 594 | designr_element_cssDefinition += "\n\t/* Miscellaneous */\n"; 595 | 596 | for (var i = 0; i < designr_pMisc.length; i++) { 597 | result[designr_pMisc[i] ] = element.getPropertyValue( designr_pMisc[i] ); 598 | designr_element_cssDefinition += "\t" + designr_pMisc[i] + ': ' + element.getPropertyValue( designr_pMisc[i] ) + ";\n"; 599 | } 600 | 601 | designr_element_cssDefinition += "\n\t/* Effects */\n"; 602 | 603 | for (var i = 0; i < designr_pEffect.length; i++) { 604 | result[designr_pEffect[i]] = element.getPropertyValue( designr_pEffect[i] ); 605 | designr_element_cssDefinition += "\t" + designr_pEffect[i] + ': ' + element.getPropertyValue( designr_pEffect[i] ) + ";\n"; 606 | } 607 | 608 | designr_element_cssDefinition += "}"; 609 | 610 | console.log( element.cssText ); 611 | 612 | chrome.runtime.sendMessage({ data: {props: result, css: designr_element_cssDefinition, title: designr_element_title}, action: "clickElement" }) 613 | 614 | designrInsertMessage( "Element saved into palette!" ); 615 | } 616 | 617 | function designrMouseOver(e) 618 | { 619 | // Block 620 | var document = GetCurrentDocument(); 621 | var block = document.getElementById('designr_block'); 622 | 623 | if( ! block ){ 624 | return; 625 | } 626 | 627 | // Outline element 628 | if (this.tagName != 'body') { 629 | this.style.outline = '1.5px dashed #63a3eb'; 630 | designr_current_element = this; 631 | } 632 | 633 | // Updating CSS properties 634 | var element = document.defaultView.getComputedStyle(this, null); 635 | 636 | UpdateGeneral(element, this.tagName, this.className, this.id); 637 | UpdatefontText(element); 638 | UpdateColorBg(element); 639 | UpdateBox(element); 640 | UpdatePositioning(element); 641 | UpdateTable(element, this.tagName); 642 | UpdateList(element, this.tagName); 643 | UpdateMisc(element); 644 | UpdateEffects(element); 645 | 646 | designr_element = this; 647 | 648 | designrRemoveElement("designrInsertMessage"); 649 | 650 | e.stopPropagation(); 651 | 652 | // generate simple css definition 653 | designr_element_cssDefinition = this.tagName.toLowerCase() + (this.id == '' ? '' : ' #' + this.id) + (this.className == '' ? '' : ' .' + this.className) + " {\n"; 654 | 655 | designr_element_cssDefinition += "\t/* Font & Text */\n"; 656 | for (var i = 0; i < designr_pFont.length; i++) 657 | designr_element_cssDefinition += "\t" + designr_pFont[i] + ': ' + element.getPropertyValue( designr_pFont[i] ) + ";\n"; 658 | 659 | designr_element_cssDefinition += "\n\t/* Color & Background */\n"; 660 | for (var i = 0; i < designr_pColorBg.length; i++) 661 | designr_element_cssDefinition += "\t" + designr_pColorBg[i] + ': ' + element.getPropertyValue( designr_pColorBg[i] ) + ";\n"; 662 | 663 | designr_element_cssDefinition += "\n\t/* Box */\n"; 664 | for (var i = 0; i < designr_pBox.length; i++) 665 | designr_element_cssDefinition += "\t" + designr_pBox[i] + ': ' + element.getPropertyValue( designr_pBox[i] ) + ";\n"; 666 | 667 | designr_element_cssDefinition += "\n\t/* Positioning */\n"; 668 | for (var i = 0; i < designr_pPositioning.length; i++) 669 | designr_element_cssDefinition += "\t" + designr_pPositioning[i] + ': ' + element.getPropertyValue( designr_pPositioning[i] ) + ";\n"; 670 | 671 | designr_element_cssDefinition += "\n\t/* List */\n"; 672 | for (var i = 0; i < designr_pList.length; i++) 673 | designr_element_cssDefinition += "\t" + designr_pList[i] + ': ' + element.getPropertyValue( designr_pList[i] ) + ";\n"; 674 | 675 | designr_element_cssDefinition += "\n\t/* Table */\n"; 676 | for (var i = 0; i < designr_pTable.length; i++) 677 | designr_element_cssDefinition += "\t" + designr_pTable[i] + ': ' + element.getPropertyValue( designr_pTable[i] ) + ";\n"; 678 | 679 | designr_element_cssDefinition += "\n\t/* Miscellaneous */\n"; 680 | for (var i = 0; i < designr_pMisc.length; i++) 681 | designr_element_cssDefinition += "\t" + designr_pMisc[i] + ': ' + element.getPropertyValue( designr_pMisc[i] ) + ";\n"; 682 | 683 | designr_element_cssDefinition += "\n\t/* Effects */\n"; 684 | for (var i = 0; i < designr_pEffect.length; i++) 685 | designr_element_cssDefinition += "\t" + designr_pEffect[i] + ': ' + element.getPropertyValue( designr_pEffect[i] ) + ";\n"; 686 | 687 | designr_element_cssDefinition += "}"; 688 | 689 | console.log( element.cssText ); 690 | } 691 | 692 | function designrMouseOut(e) 693 | { 694 | this.style.outline = ''; 695 | 696 | e.stopPropagation(); 697 | } 698 | 699 | function designrMouseMove(e) 700 | { 701 | var document = GetCurrentDocument(); 702 | var block = document.getElementById('designr_block'); 703 | 704 | if( ! block ){ 705 | return; 706 | } 707 | 708 | block.style.display = 'block'; 709 | 710 | var pageWidth = window.innerWidth; 711 | var pageHeight = window.innerHeight; 712 | var blockWidth = 332; 713 | var blockHeight = document.defaultView.getComputedStyle(block, null).getPropertyValue('height'); 714 | 715 | blockHeight = blockHeight.substr(0, blockHeight.length - 2) * 1; 716 | 717 | if ((e.pageX + blockWidth) > pageWidth) { 718 | if ((e.pageX - blockWidth - 10) > 0) 719 | block.style.left = e.pageX - blockWidth - 40 + 'px'; 720 | else 721 | block.style.left = 0 + 'px'; 722 | } 723 | else 724 | block.style.left = (e.pageX + 20) + 'px'; 725 | 726 | if ((e.pageY + blockHeight) > pageHeight) { 727 | if ((e.pageY - blockHeight - 10) > 0) 728 | block.style.top = e.pageY - blockHeight - 20 + 'px'; 729 | else 730 | block.style.top = 0 + 'px'; 731 | } 732 | else 733 | block.style.top = (e.pageY + 20) + 'px'; 734 | 735 | // adapt block top to screen offset 736 | inView = designrIsElementInViewport(block); 737 | 738 | if( ! inView ) 739 | block.style.top = ( window.pageYOffset + 20 ) + 'px'; 740 | 741 | e.stopPropagation(); 742 | } 743 | 744 | // http://stackoverflow.com/a/7557433 745 | function designrIsElementInViewport(el) { 746 | var rect = el.getBoundingClientRect(); 747 | 748 | return ( 749 | rect.top >= 0 && 750 | rect.left >= 0 && 751 | rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && 752 | rect.right <= (window.innerWidth || document.documentElement.clientWidth) 753 | ); 754 | } 755 | 756 | /* 757 | * designr Class 758 | */ 759 | function designr() 760 | { 761 | // Create a block to display informations 762 | this.CreateBlock = function() { 763 | var document = GetCurrentDocument(); 764 | var block; 765 | 766 | if (document) { 767 | // Create a div block 768 | block = document.createElement('div'); 769 | block.id = 'designr_block'; 770 | 771 | var header = document.createElement('h1'); 772 | header.appendChild(document.createTextNode('')); 773 | block.appendChild(header); 774 | 775 | // Insert all properties 776 | var center = document.createElement('div'); 777 | 778 | center.id = 'designr_center'; 779 | 780 | for (var cat in designr_categories) { 781 | var div = document.createElement('div'); 782 | 783 | div.id = 'designr_' + cat; 784 | div.className = 'designr_category'; 785 | 786 | var h2 = document.createElement('h2'); 787 | 788 | h2.appendChild(document.createTextNode(designr_categoriesTitle[cat])); 789 | 790 | var ul = document.createElement('ul'); 791 | var properties = designr_categories[cat]; 792 | 793 | for (var i = 0; i < properties.length; i++) { 794 | var li = document.createElement('li'); 795 | 796 | li.id = 'designr_' + properties[i]; 797 | 798 | var spanName = document.createElement('span'); 799 | 800 | spanName.className = 'designr_property'; 801 | 802 | var spanValue = document.createElement('span'); 803 | 804 | spanName.appendChild(document.createTextNode(properties[i])); 805 | li.appendChild(spanName); 806 | li.appendChild(spanValue); 807 | ul.appendChild(li); 808 | } 809 | 810 | div.appendChild(h2); 811 | div.appendChild(ul); 812 | center.appendChild(div); 813 | } 814 | 815 | block.appendChild(center); 816 | 817 | // Insert a footer 818 | var footer = document.createElement('div'); 819 | 820 | footer.id = 'designr_footer'; 821 | 822 | //< 823 | footer.appendChild( document.createTextNode('designr (1.0.0) [Esc] Close out of popup') ); 824 | block.appendChild(footer); 825 | } 826 | 827 | designrInsertMessage( "Hover over any element to inspect in the page and click on an element to save it." ); 828 | 829 | return block; 830 | } 831 | 832 | // Get all elements within the given element 833 | this.GetAllElements = function(element) 834 | { 835 | var elements = new Array(); 836 | 837 | if (element && element.hasChildNodes()) { 838 | elements.push(element); 839 | 840 | var childs = element.childNodes; 841 | 842 | for (var i = 0; i < childs.length; i++) { 843 | if (childs[i].hasChildNodes()) { 844 | elements = elements.concat(this.GetAllElements(childs[i])); 845 | } 846 | else if (childs[i].nodeType == 1) { 847 | elements.push(childs[i]); 848 | } 849 | } 850 | } 851 | 852 | return elements; 853 | } 854 | 855 | // Add bool for knowing all elements having event listeners or not 856 | this.haveEventListeners = false; 857 | 858 | // Add event listeners for all elements in the current document 859 | this.AddEventListeners = function() 860 | { 861 | var document = GetCurrentDocument(); 862 | var elements = this.GetAllElements(document.body); 863 | console.log("dasklsdajlksdjs") 864 | 865 | for (var i = 0; i < elements.length; i++) { 866 | elements[i].addEventListener("mouseover", designrMouseOver, false); 867 | elements[i].addEventListener("click", designrClick, false); 868 | elements[i].addEventListener("mouseout", designrMouseOut, false); 869 | elements[i].addEventListener("mousemove", designrMouseMove, false); 870 | } 871 | this.haveEventListeners = true; 872 | } 873 | 874 | // Remove event listeners for all elements in the current document 875 | this.RemoveEventListeners = function() 876 | { 877 | var document = GetCurrentDocument(); 878 | var elements = this.GetAllElements(document.body); 879 | 880 | for (var i = 0; i < elements.length; i++){ 881 | elements[i].removeEventListener("mouseover", designrMouseOver, false); 882 | elements[i].removeEventListener("click", designrClick, false); 883 | elements[i].removeEventListener("mouseout", designrMouseOut, false); 884 | elements[i].removeEventListener("mousemove", designrMouseMove, false); 885 | } 886 | this.haveEventListeners = false; 887 | } 888 | 889 | // Set the title of the block 890 | this.SetTitle = function() 891 | {} 892 | 893 | // Add a stylesheet to the current document 894 | this.AddCSS = function(cssFile) 895 | { 896 | var document = GetCurrentDocument(); 897 | var link = document.createElement("link"); 898 | 899 | link.setAttribute("href", cssFile); 900 | link.setAttribute("rel", "stylesheet"); 901 | link.setAttribute("type", "text/css"); 902 | 903 | var heads = document.getElementsByTagName("head"); 904 | 905 | if(heads.length > 0) 906 | heads[0].appendChild(link); 907 | else 908 | document.documentElement.appendChild(link); 909 | } 910 | 911 | this.RemoveCSS = function(cssFile) 912 | { 913 | var document = GetCurrentDocument(); 914 | var links = document.getElementsByTagName('link'); 915 | 916 | for (var i = 0; i < links.length; i++) { 917 | if (links[i].rel == "stylesheet" && links[i].href == cssFile) { 918 | var heads = document.getElementsByTagName("head"); 919 | 920 | if(heads.length > 0) { 921 | heads[0].removeChild(links[i]); 922 | } 923 | 924 | return; 925 | } 926 | } 927 | } 928 | } 929 | 930 | /* 931 | * Check if designr is enabled 932 | */ 933 | designr.prototype.IsEnabled = function() 934 | { 935 | var document = GetCurrentDocument(); 936 | 937 | if (document.getElementById('designr_block')) { 938 | return true; 939 | } 940 | 941 | return false; 942 | } 943 | 944 | /* 945 | * Enable designr 946 | */ 947 | designr.prototype.Enable = function() 948 | { 949 | var document = GetCurrentDocument(); 950 | var block = document.getElementById('designr_block'); 951 | 952 | if (!block){ 953 | block = this.CreateBlock(); 954 | document.body.appendChild(block); 955 | this.AddEventListeners(); 956 | 957 | return true; 958 | } 959 | 960 | return false; 961 | } 962 | 963 | /* 964 | * Disable designr 965 | */ 966 | designr.prototype.Disable = function() 967 | { 968 | var document = GetCurrentDocument(); 969 | var block = document.getElementById('designr_block'); 970 | var insertMessage = document.getElementById("designrInsertMessage"); 971 | 972 | if (block || insertMessage) { 973 | if(block) document.body.removeChild(block); 974 | if(insertMessage) document.body.removeChild(insertMessage); 975 | this.RemoveEventListeners(); 976 | 977 | return true; 978 | } 979 | 980 | return false; 981 | } 982 | 983 | /* 984 | * Display the notification message 985 | */ 986 | function designrInsertMessage( msg ) 987 | { 988 | var oNewP = document.createElement("p"); 989 | var oText = document.createTextNode( msg ); 990 | 991 | oNewP.appendChild(oText); 992 | oNewP.id = 'designrInsertMessage'; 993 | oNewP.style.backgroundColor = '#275e9d'; 994 | oNewP.style.color = '#ffffff'; 995 | oNewP.style.position = "fixed"; 996 | oNewP.style.top = '10px'; 997 | oNewP.style.left = '10px'; 998 | oNewP.style.zIndex = '9999'; 999 | oNewP.style.fontSize = '15px'; 1000 | oNewP.style.padding = '3px'; 1001 | document.body.appendChild(oNewP); 1002 | } 1003 | 1004 | /* 1005 | * Removes and element from the dom, used to remove the notification message 1006 | */ 1007 | function designrRemoveElement(divid) 1008 | { 1009 | var n = document.getElementById(divid); 1010 | 1011 | if(n){ 1012 | document.body.removeChild(n); 1013 | } 1014 | } 1015 | 1016 | /* 1017 | * Copy current element css to chrome console 1018 | */ 1019 | function designrCopyCssToConsole(type) 1020 | { 1021 | if( 'el' == type ) return console.log( designr_element ); 1022 | if( 'id' == type ) return console.log( designr_element.id ); 1023 | if( 'tagName' == type ) return console.log( designr_element.tagName ); 1024 | if( 'className' == type ) return console.log( designr_element.className ); 1025 | if( 'style' == type ) return console.log( designr_element.style ); 1026 | if( 'cssText' == type ) return console.log( document.defaultView.getComputedStyle(designr_element, null).cssText ); 1027 | if( 'getComputedStyle' == type ) return console.log( document.defaultView.getComputedStyle(designr_element, null) ); 1028 | if( 'simpleCssDefinition' == type ) return console.log( designr_element_cssDefinition ); 1029 | } 1030 | 1031 | /* 1032 | * Close css viewer on clicking 'esc' key 1033 | * Freeze css viewer on clicking 'f' key 1034 | */ 1035 | function designrKeyMap(e) { 1036 | if( ! designr.IsEnabled() ) 1037 | return; 1038 | 1039 | // ESC: Close the css viewer if the designr is enabled. 1040 | if ( e.keyCode === 27 ){ 1041 | // Remove the red outline 1042 | designr_current_element.style.outline = ''; 1043 | designr.Disable(); 1044 | } 1045 | 1046 | if( e.altKey || e.ctrlKey ) 1047 | return; 1048 | 1049 | // c: Show code css for selected element. 1050 | // window.prompt should suffice for now. 1051 | if ( e.keyCode === 67 ){ 1052 | window.prompt("Simple Css Definition :\n\nYou may copy the code below then hit escape to continue.", designr_element_cssDefinition); 1053 | } 1054 | } 1055 | 1056 | 1057 | /* 1058 | * designr entry-point 1059 | */ 1060 | designr = new designr(); 1061 | 1062 | if ( designr.IsEnabled() ){ 1063 | designr.Disable(); 1064 | } 1065 | else{ 1066 | designr.Enable(); 1067 | } 1068 | 1069 | // Set event handler for the designr 1070 | document.onkeydown = designrKeyMap; 1071 | -------------------------------------------------------------------------------- /js/libs/autorefresh.js: -------------------------------------------------------------------------------- 1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 | // Distributed under an MIT license: https://codemirror.net/5/LICENSE 3 | 4 | (function(mod) { 5 | if (typeof exports == "object" && typeof module == "object") // CommonJS 6 | mod(require("../../lib/codemirror")) 7 | else if (typeof define == "function" && define.amd) // AMD 8 | define(["../../lib/codemirror"], mod) 9 | else // Plain browser env 10 | mod(CodeMirror) 11 | })(function(CodeMirror) { 12 | "use strict" 13 | 14 | CodeMirror.defineOption("autoRefresh", false, function(cm, val) { 15 | if (cm.state.autoRefresh) { 16 | stopListening(cm, cm.state.autoRefresh) 17 | cm.state.autoRefresh = null 18 | } 19 | if (val && cm.display.wrapper.offsetHeight == 0) 20 | startListening(cm, cm.state.autoRefresh = {delay: val.delay || 250}) 21 | }) 22 | 23 | function startListening(cm, state) { 24 | function check() { 25 | if (cm.display.wrapper.offsetHeight) { 26 | stopListening(cm, state) 27 | if (cm.display.lastWrapHeight != cm.display.wrapper.clientHeight) 28 | cm.refresh() 29 | } else { 30 | state.timeout = setTimeout(check, state.delay) 31 | } 32 | } 33 | state.timeout = setTimeout(check, state.delay) 34 | state.hurry = function() { 35 | clearTimeout(state.timeout) 36 | state.timeout = setTimeout(check, 50) 37 | } 38 | CodeMirror.on(window, "mouseup", state.hurry) 39 | CodeMirror.on(window, "keyup", state.hurry) 40 | } 41 | 42 | function stopListening(_cm, state) { 43 | clearTimeout(state.timeout) 44 | CodeMirror.off(window, "mouseup", state.hurry) 45 | CodeMirror.off(window, "keyup", state.hurry) 46 | } 47 | }); -------------------------------------------------------------------------------- /js/libs/codemirror.css: -------------------------------------------------------------------------------- 1 | /* BASICS */ 2 | 3 | .CodeMirror { 4 | /* Set height, width, borders, and global font properties here */ 5 | font-family: monospace; 6 | height: 100%; 7 | color: rgb(255, 254, 254); 8 | direction: ltr; 9 | text-align: left !important; 10 | } 11 | 12 | /* PADDING */ 13 | 14 | .CodeMirror-lines { 15 | /* padding: 4px 0; */ 16 | /* Vertical padding around content */ 17 | } 18 | 19 | .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { 20 | background-color: white; /* The little square between H and V scrollbars */ 21 | } 22 | 23 | /* GUTTER */ 24 | 25 | .CodeMirror-linenumber { 26 | padding: 0 3px 0 5px; 27 | min-width: 16px; 28 | text-align: right; 29 | color: #999; 30 | white-space: nowrap; 31 | } 32 | 33 | .CodeMirror-guttermarker { color: black; } 34 | .CodeMirror-guttermarker-subtle { color: #999; } 35 | 36 | /* CURSOR */ 37 | 38 | .CodeMirror-cursor { 39 | border-left: 1px solid rgb(236, 232, 232); 40 | border-right: none; 41 | width: 0; 42 | } 43 | /* Shown when moving in bi-directional text */ 44 | .CodeMirror div.CodeMirror-secondarycursor { 45 | border-left: 1px solid silver; 46 | } 47 | .cm-fat-cursor .CodeMirror-cursor { 48 | width: auto; 49 | border: 0 !important; 50 | background: #7e7; 51 | } 52 | .cm-fat-cursor div.CodeMirror-cursors { 53 | z-index: 1; 54 | } 55 | .cm-fat-cursor-mark { 56 | background-color: rgba(20, 255, 20, 0.5); 57 | -webkit-animation: blink 1.06s steps(1) infinite; 58 | -moz-animation: blink 1.06s steps(1) infinite; 59 | animation: blink 1.06s steps(1) infinite; 60 | } 61 | .cm-animate-fat-cursor { 62 | width: auto; 63 | border: 0; 64 | -webkit-animation: blink 1.06s steps(1) infinite; 65 | -moz-animation: blink 1.06s steps(1) infinite; 66 | animation: blink 1.06s steps(1) infinite; 67 | background-color: #7e7; 68 | } 69 | @-moz-keyframes blink { 70 | 0% {} 71 | 50% { background-color: transparent; } 72 | 100% {} 73 | } 74 | @-webkit-keyframes blink { 75 | 0% {} 76 | 50% { background-color: transparent; } 77 | 100% {} 78 | } 79 | @keyframes blink { 80 | 0% {} 81 | 50% { background-color: transparent; } 82 | 100% {} 83 | } 84 | 85 | /* Can style cursor different in overwrite (non-insert) mode */ 86 | 87 | .cm-tab { display: inline-block; text-decoration: inherit; } 88 | 89 | .CodeMirror-rulers { 90 | position: absolute; 91 | left: 0; right: 0; top: -50px; bottom: 0; 92 | overflow: hidden; 93 | } 94 | .CodeMirror-ruler { 95 | border-left: 1px solid #ccc; 96 | top: 0; bottom: 0; 97 | position: absolute; 98 | } 99 | 100 | /* DEFAULT THEME */ 101 | 102 | .cm-s-default .cm-header {color: blue;} 103 | .cm-s-default .cm-quote {color: #090;} 104 | .cm-negative {color: #d44;} 105 | .cm-positive {color: #292;} 106 | .cm-header, .cm-strong {font-weight: bold;} 107 | .cm-em {font-style: italic;} 108 | .cm-link {text-decoration: underline;} 109 | .cm-strikethrough {text-decoration: line-through;} 110 | 111 | .cm-s-default .cm-keyword {color: #e6db74;} 112 | .cm-s-default .cm-atom {color: #F78C6C;} 113 | .cm-s-default .cm-number {color: #C3E88D;} 114 | .cm-s-default .cm-def {color: #00f;} 115 | 116 | .cm-s-default .cm-variable-2 {color: #05a;} 117 | .cm-s-default .cm-variable-3, .cm-s-default .cm-type {color: #82AAFF;} 118 | .cm-s-default .cm-comment {color: #717790;} 119 | .cm-s-default .cm-string {color: #ff9ac1;} 120 | .cm-s-default .cm-string-2 {color: #f50;} 121 | .cm-s-default .cm-meta {color: #555;} 122 | .cm-s-default .cm-qualifier {color: #9effff;} 123 | .cm-property {color: #ae81ff;} 124 | .cm-s-default .cm-builtin {color: rgb(173, 138, 255);} 125 | .cm-s-default .cm-bracket {color: #997;} 126 | .cm-s-default .cm-tag {color: #9effff;} 127 | .cm-s-default .cm-attribute {color: #00c;} 128 | .cm-s-default .cm-hr {color: #999;} 129 | .cm-s-default .cm-link {color: #00c;} 130 | 131 | .cm-s-default .cm-error {color: #f00;} 132 | .cm-invalidchar {color: #f00;} 133 | 134 | .CodeMirror-composing { border-bottom: 2px solid; } 135 | 136 | /* Default styles for common addons */ 137 | 138 | div.CodeMirror span.CodeMirror-matchingbracket {color: #0b0;} 139 | div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;} 140 | .CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); } 141 | .CodeMirror-activeline-background {background: #e8f2ff;} 142 | 143 | /* STOP */ 144 | 145 | /* The rest of this file contains styles related to the mechanics of 146 | the editor. You probably shouldn't touch them. */ 147 | 148 | .CodeMirror { 149 | position: relative; 150 | overflow: hidden; 151 | background: white; 152 | } 153 | 154 | .CodeMirror-scroll { 155 | overflow: scroll !important; 156 | margin-bottom: -50px; 157 | /* margin-right: -50px; */ 158 | padding-bottom: 50px; 159 | height: 100%; 160 | outline: none; /* Prevent dragging from highlighting the element */ 161 | position: relative; 162 | } 163 | .CodeMirror-sizer { 164 | position: relative; 165 | margin-left: 1px !important; 166 | border-right: 50px solid transparent; 167 | } 168 | 169 | /* The fake, visible scrollbars. Used to force redraw during scrolling 170 | before actual scrolling happens, thus preventing shaking and 171 | flickering artifacts. */ 172 | .CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { 173 | position: absolute; 174 | z-index: 6; 175 | display: none; 176 | outline: none; 177 | } 178 | .CodeMirror-vscrollbar { 179 | right: 0; top: 0; 180 | overflow-x: hidden; 181 | overflow-y: scroll; 182 | } 183 | .CodeMirror-hscrollbar { 184 | bottom: 0; left: 0; 185 | overflow-y: hidden; 186 | overflow-x: scroll; 187 | } 188 | .CodeMirror-scrollbar-filler { 189 | right: 0; bottom: 0; 190 | } 191 | .CodeMirror-gutter-filler { 192 | left: 0; bottom: 0; 193 | } 194 | 195 | .CodeMirror-gutters { 196 | position: absolute; left: 0; top: 0; 197 | min-height: 100%; 198 | z-index: 3; 199 | } 200 | .CodeMirror-gutter { 201 | white-space: normal; 202 | height: 100%; 203 | display: inline-block; 204 | vertical-align: top; 205 | margin-bottom: -50px; 206 | } 207 | /* .CodeMirror-gutter-wrapper { 208 | position: absolute; 209 | z-index: 4; 210 | background: none !important; 211 | border: none !important; 212 | } */ 213 | .CodeMirror-gutter-background { 214 | position: absolute; 215 | top: 0; bottom: 0; 216 | z-index: 4; 217 | } 218 | .CodeMirror-gutter-elt { 219 | position: absolute; 220 | cursor: default; 221 | z-index: 4; 222 | } 223 | .CodeMirror-gutter-wrapper ::selection { background-color: transparent } 224 | .CodeMirror-gutter-wrapper ::-moz-selection { background-color: transparent } 225 | 226 | .CodeMirror-lines { 227 | cursor: text; 228 | min-height: 1px; /* prevents collapsing before first draw */ 229 | } 230 | .CodeMirror pre.CodeMirror-line, 231 | .CodeMirror pre.CodeMirror-line-like { 232 | /* Reset some styles that the rest of the page might have set */ 233 | -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0; 234 | border-width: 0; 235 | background: transparent; 236 | font-family: inherit; 237 | font-size: inherit; 238 | margin: 0; 239 | white-space: pre; 240 | word-wrap: normal; 241 | line-height: inherit; 242 | color: inherit; 243 | z-index: 2; 244 | position: relative; 245 | overflow: visible; 246 | -webkit-tap-highlight-color: transparent; 247 | -webkit-font-variant-ligatures: contextual; 248 | font-variant-ligatures: contextual; 249 | padding-left: 40px; 250 | } 251 | /* .CodeMirror-wrap pre.CodeMirror-line, 252 | .CodeMirror-wrap pre.CodeMirror-line-like { 253 | word-wrap: break-word; 254 | white-space: pre-wrap; 255 | word-break: normal; 256 | } 257 | */ 258 | .CodeMirror-linebackground { 259 | position: absolute; 260 | left: 0; right: 0; top: 0; bottom: 0; 261 | z-index: 0; 262 | } 263 | 264 | .CodeMirror-linewidget { 265 | position: relative; 266 | z-index: 2; 267 | padding: 0.1px; /* Force widget margins to stay inside of the container */ 268 | } 269 | 270 | .CodeMirror-rtl pre { direction: rtl; } 271 | 272 | .CodeMirror-code { 273 | outline: none; 274 | } 275 | 276 | /* Force content-box sizing for the elements where we expect it */ 277 | .CodeMirror-scroll, 278 | .CodeMirror-sizer, 279 | .CodeMirror-gutter, 280 | .CodeMirror-gutters, 281 | .CodeMirror-linenumber { 282 | background: rgb(36, 34, 34); 283 | -moz-box-sizing: content-box; 284 | box-sizing: content-box; 285 | } 286 | 287 | .CodeMirror-gutter, .CodeMirror-linenumbers { 288 | width: 0px !important; 289 | } 290 | 291 | .CodeMirror-measure { 292 | position: absolute; 293 | width: 100%; 294 | height: 0; 295 | overflow: hidden; 296 | visibility: hidden; 297 | } 298 | 299 | .CodeMirror-cursor { 300 | position: absolute; 301 | pointer-events: none; 302 | } 303 | .CodeMirror-measure pre { position: static; } 304 | 305 | div.CodeMirror-cursors { 306 | visibility: hidden; 307 | position: relative; 308 | z-index: 3; 309 | } 310 | div.CodeMirror-dragcursors { 311 | visibility: visible; 312 | } 313 | 314 | .CodeMirror-focused div.CodeMirror-cursors { 315 | visibility: visible; 316 | } 317 | 318 | .CodeMirror-selected { background: #d9d9d9; } 319 | .CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; } 320 | .CodeMirror-crosshair { cursor: crosshair; } 321 | .CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; } 322 | .CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; } 323 | 324 | .cm-searching { 325 | background-color: #ffa; 326 | background-color: rgba(255, 255, 0, .4); 327 | } 328 | 329 | /* Used to force a border model for a node */ 330 | .cm-force-border { padding-right: .1px; } 331 | 332 | @media print { 333 | /* Hide the cursor when printing */ 334 | .CodeMirror div.CodeMirror-cursors { 335 | visibility: hidden; 336 | } 337 | } 338 | 339 | /* See issue #2901 */ 340 | .cm-tab-wrap-hack:after { content: ''; } 341 | 342 | /* Help users use markselection to safely style text background */ 343 | span.CodeMirror-selectedtext { background: none; } 344 | -------------------------------------------------------------------------------- /js/libs/css.js: -------------------------------------------------------------------------------- 1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 | // Distributed under an MIT license: https://codemirror.net/LICENSE 3 | 4 | (function (mod) { 5 | if (typeof exports == "object" && typeof module == "object") // CommonJS 6 | mod(require("../../lib/codemirror")); 7 | else if (typeof define == "function" && define.amd) // AMD 8 | define(["../../lib/codemirror"], mod); 9 | else // Plain browser env 10 | mod(CodeMirror); 11 | })(function (CodeMirror) { 12 | "use strict"; 13 | 14 | CodeMirror.defineMode("css", function (config, parserConfig) { 15 | var inline = parserConfig.inline 16 | if (!parserConfig.propertyKeywords) parserConfig = CodeMirror.resolveMode("text/css"); 17 | 18 | var indentUnit = config.indentUnit, 19 | tokenHooks = parserConfig.tokenHooks, 20 | documentTypes = parserConfig.documentTypes || {}, 21 | mediaTypes = parserConfig.mediaTypes || {}, 22 | mediaFeatures = parserConfig.mediaFeatures || {}, 23 | mediaValueKeywords = parserConfig.mediaValueKeywords || {}, 24 | propertyKeywords = parserConfig.propertyKeywords || {}, 25 | nonStandardPropertyKeywords = parserConfig.nonStandardPropertyKeywords || {}, 26 | fontProperties = parserConfig.fontProperties || {}, 27 | counterDescriptors = parserConfig.counterDescriptors || {}, 28 | colorKeywords = parserConfig.colorKeywords || {}, 29 | valueKeywords = parserConfig.valueKeywords || {}, 30 | allowNested = parserConfig.allowNested, 31 | lineComment = parserConfig.lineComment, 32 | supportsAtComponent = parserConfig.supportsAtComponent === true, 33 | highlightNonStandardPropertyKeywords = config.highlightNonStandardPropertyKeywords !== false; 34 | 35 | var type, override; 36 | function ret(style, tp) { type = tp; return style; } 37 | 38 | // Tokenizers 39 | 40 | function tokenBase(stream, state) { 41 | var ch = stream.next(); 42 | if (tokenHooks[ch]) { 43 | var result = tokenHooks[ch](stream, state); 44 | if (result !== false) return result; 45 | } 46 | if (ch == "@") { 47 | stream.eatWhile(/[\w\\\-]/); 48 | return ret("def", stream.current()); 49 | } else if (ch == "=" || (ch == "~" || ch == "|") && stream.eat("=")) { 50 | return ret(null, "compare"); 51 | } else if (ch == "\"" || ch == "'") { 52 | state.tokenize = tokenString(ch); 53 | return state.tokenize(stream, state); 54 | } else if (ch == "#") { 55 | stream.eatWhile(/[\w\\\-]/); 56 | return ret("atom", "hash"); 57 | } else if (ch == "!") { 58 | stream.match(/^\s*\w*/); 59 | return ret("keyword", "important"); 60 | } else if (/\d/.test(ch) || ch == "." && stream.eat(/\d/)) { 61 | stream.eatWhile(/[\w.%]/); 62 | return ret("number", "unit"); 63 | } else if (ch === "-") { 64 | if (/[\d.]/.test(stream.peek())) { 65 | stream.eatWhile(/[\w.%]/); 66 | return ret("number", "unit"); 67 | } else if (stream.match(/^-[\w\\\-]*/)) { 68 | stream.eatWhile(/[\w\\\-]/); 69 | if (stream.match(/^\s*:/, false)) 70 | return ret("variable-2", "variable-definition"); 71 | return ret("variable-2", "variable"); 72 | } else if (stream.match(/^\w+-/)) { 73 | return ret("meta", "meta"); 74 | } 75 | } else if (/[,+>*\/]/.test(ch)) { 76 | return ret(null, "select-op"); 77 | } else if (ch == "." && stream.match(/^-?[_a-z][_a-z0-9-]*/i)) { 78 | return ret("qualifier", "qualifier"); 79 | } else if (/[:;{}\[\]\(\)]/.test(ch)) { 80 | return ret(null, ch); 81 | } else if (stream.match(/^[\w-.]+(?=\()/)) { 82 | if (/^(url(-prefix)?|domain|regexp)$/i.test(stream.current())) { 83 | state.tokenize = tokenParenthesized; 84 | } 85 | return ret("variable callee", "variable"); 86 | } else if (/[\w\\\-]/.test(ch)) { 87 | stream.eatWhile(/[\w\\\-]/); 88 | return ret("property", "word"); 89 | } else { 90 | return ret(null, null); 91 | } 92 | } 93 | 94 | function tokenString(quote) { 95 | return function (stream, state) { 96 | var escaped = false, ch; 97 | while ((ch = stream.next()) != null) { 98 | if (ch == quote && !escaped) { 99 | if (quote == ")") stream.backUp(1); 100 | break; 101 | } 102 | escaped = !escaped && ch == "\\"; 103 | } 104 | if (ch == quote || !escaped && quote != ")") state.tokenize = null; 105 | return ret("string", "string"); 106 | }; 107 | } 108 | 109 | function tokenParenthesized(stream, state) { 110 | stream.next(); // Must be '(' 111 | if (!stream.match(/^\s*[\"\')]/, false)) 112 | state.tokenize = tokenString(")"); 113 | else 114 | state.tokenize = null; 115 | return ret(null, "("); 116 | } 117 | 118 | // Context management 119 | 120 | function Context(type, indent, prev) { 121 | this.type = type; 122 | this.indent = indent; 123 | this.prev = prev; 124 | } 125 | 126 | function pushContext(state, stream, type, indent) { 127 | state.context = new Context(type, stream.indentation() + (indent === false ? 0 : indentUnit), state.context); 128 | return type; 129 | } 130 | 131 | function popContext(state) { 132 | if (state.context.prev) 133 | state.context = state.context.prev; 134 | return state.context.type; 135 | } 136 | 137 | function pass(type, stream, state) { 138 | return states[state.context.type](type, stream, state); 139 | } 140 | function popAndPass(type, stream, state, n) { 141 | for (var i = n || 1; i > 0; i--) 142 | state.context = state.context.prev; 143 | return pass(type, stream, state); 144 | } 145 | 146 | // Parser 147 | 148 | function wordAsValue(stream) { 149 | var word = stream.current().toLowerCase(); 150 | if (valueKeywords.hasOwnProperty(word)) 151 | override = "atom"; 152 | else if (colorKeywords.hasOwnProperty(word)) 153 | override = "keyword"; 154 | else 155 | override = "variable"; 156 | } 157 | 158 | var states = {}; 159 | 160 | states.top = function (type, stream, state) { 161 | if (type == "{") { 162 | return pushContext(state, stream, "block"); 163 | } else if (type == "}" && state.context.prev) { 164 | return popContext(state); 165 | } else if (supportsAtComponent && /@component/i.test(type)) { 166 | return pushContext(state, stream, "atComponentBlock"); 167 | } else if (/^@(-moz-)?document$/i.test(type)) { 168 | return pushContext(state, stream, "documentTypes"); 169 | } else if (/^@(media|supports|(-moz-)?document|import)$/i.test(type)) { 170 | return pushContext(state, stream, "atBlock"); 171 | } else if (/^@(font-face|counter-style)/i.test(type)) { 172 | state.stateArg = type; 173 | return "restricted_atBlock_before"; 174 | } else if (/^@(-(moz|ms|o|webkit)-)?keyframes$/i.test(type)) { 175 | return "keyframes"; 176 | } else if (type && type.charAt(0) == "@") { 177 | return pushContext(state, stream, "at"); 178 | } else if (type == "hash") { 179 | override = "builtin"; 180 | } else if (type == "word") { 181 | override = "tag"; 182 | } else if (type == "variable-definition") { 183 | return "maybeprop"; 184 | } else if (type == "interpolation") { 185 | return pushContext(state, stream, "interpolation"); 186 | } else if (type == ":") { 187 | return "pseudo"; 188 | } else if (allowNested && type == "(") { 189 | return pushContext(state, stream, "parens"); 190 | } 191 | return state.context.type; 192 | }; 193 | 194 | states.block = function (type, stream, state) { 195 | if (type == "word") { 196 | var word = stream.current().toLowerCase(); 197 | if (propertyKeywords.hasOwnProperty(word)) { 198 | override = "property"; 199 | return "maybeprop"; 200 | } else if (nonStandardPropertyKeywords.hasOwnProperty(word)) { 201 | override = highlightNonStandardPropertyKeywords ? "string-2" : "property"; 202 | return "maybeprop"; 203 | } else if (allowNested) { 204 | override = stream.match(/^\s*:(?:\s|$)/, false) ? "property" : "tag"; 205 | return "block"; 206 | } else { 207 | override += " error"; 208 | return "maybeprop"; 209 | } 210 | } else if (type == "meta") { 211 | return "block"; 212 | } else if (!allowNested && (type == "hash" || type == "qualifier")) { 213 | override = "error"; 214 | return "block"; 215 | } else { 216 | return states.top(type, stream, state); 217 | } 218 | }; 219 | 220 | states.maybeprop = function (type, stream, state) { 221 | if (type == ":") return pushContext(state, stream, "prop"); 222 | return pass(type, stream, state); 223 | }; 224 | 225 | states.prop = function (type, stream, state) { 226 | if (type == ";") return popContext(state); 227 | if (type == "{" && allowNested) return pushContext(state, stream, "propBlock"); 228 | if (type == "}" || type == "{") return popAndPass(type, stream, state); 229 | if (type == "(") return pushContext(state, stream, "parens"); 230 | 231 | if (type == "hash" && !/^#([0-9a-fA-f]{3,4}|[0-9a-fA-f]{6}|[0-9a-fA-f]{8})$/.test(stream.current())) { 232 | override += " error"; 233 | } else if (type == "word") { 234 | wordAsValue(stream); 235 | } else if (type == "interpolation") { 236 | return pushContext(state, stream, "interpolation"); 237 | } 238 | return "prop"; 239 | }; 240 | 241 | states.propBlock = function (type, _stream, state) { 242 | if (type == "}") return popContext(state); 243 | if (type == "word") { override = "property"; return "maybeprop"; } 244 | return state.context.type; 245 | }; 246 | 247 | states.parens = function (type, stream, state) { 248 | if (type == "{" || type == "}") return popAndPass(type, stream, state); 249 | if (type == ")") return popContext(state); 250 | if (type == "(") return pushContext(state, stream, "parens"); 251 | if (type == "interpolation") return pushContext(state, stream, "interpolation"); 252 | if (type == "word") wordAsValue(stream); 253 | return "parens"; 254 | }; 255 | 256 | states.pseudo = function (type, stream, state) { 257 | if (type == "meta") return "pseudo"; 258 | 259 | if (type == "word") { 260 | override = "variable-3"; 261 | return state.context.type; 262 | } 263 | return pass(type, stream, state); 264 | }; 265 | 266 | states.documentTypes = function (type, stream, state) { 267 | if (type == "word" && documentTypes.hasOwnProperty(stream.current())) { 268 | override = "tag"; 269 | return state.context.type; 270 | } else { 271 | return states.atBlock(type, stream, state); 272 | } 273 | }; 274 | 275 | states.atBlock = function (type, stream, state) { 276 | if (type == "(") return pushContext(state, stream, "atBlock_parens"); 277 | if (type == "}" || type == ";") return popAndPass(type, stream, state); 278 | if (type == "{") return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top"); 279 | 280 | if (type == "interpolation") return pushContext(state, stream, "interpolation"); 281 | 282 | if (type == "word") { 283 | var word = stream.current().toLowerCase(); 284 | if (word == "only" || word == "not" || word == "and" || word == "or") 285 | override = "keyword"; 286 | else if (mediaTypes.hasOwnProperty(word)) 287 | override = "attribute"; 288 | else if (mediaFeatures.hasOwnProperty(word)) 289 | override = "property"; 290 | else if (mediaValueKeywords.hasOwnProperty(word)) 291 | override = "keyword"; 292 | else if (propertyKeywords.hasOwnProperty(word)) 293 | override = "property"; 294 | else if (nonStandardPropertyKeywords.hasOwnProperty(word)) 295 | override = highlightNonStandardPropertyKeywords ? "string-2" : "property"; 296 | else if (valueKeywords.hasOwnProperty(word)) 297 | override = "atom"; 298 | else if (colorKeywords.hasOwnProperty(word)) 299 | override = "keyword"; 300 | else 301 | override = "error"; 302 | } 303 | return state.context.type; 304 | }; 305 | 306 | states.atComponentBlock = function (type, stream, state) { 307 | if (type == "}") 308 | return popAndPass(type, stream, state); 309 | if (type == "{") 310 | return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top", false); 311 | if (type == "word") 312 | override = "error"; 313 | return state.context.type; 314 | }; 315 | 316 | states.atBlock_parens = function (type, stream, state) { 317 | if (type == ")") return popContext(state); 318 | if (type == "{" || type == "}") return popAndPass(type, stream, state, 2); 319 | return states.atBlock(type, stream, state); 320 | }; 321 | 322 | states.restricted_atBlock_before = function (type, stream, state) { 323 | if (type == "{") 324 | return pushContext(state, stream, "restricted_atBlock"); 325 | if (type == "word" && state.stateArg == "@counter-style") { 326 | override = "variable"; 327 | return "restricted_atBlock_before"; 328 | } 329 | return pass(type, stream, state); 330 | }; 331 | 332 | states.restricted_atBlock = function (type, stream, state) { 333 | if (type == "}") { 334 | state.stateArg = null; 335 | return popContext(state); 336 | } 337 | if (type == "word") { 338 | if ((state.stateArg == "@font-face" && !fontProperties.hasOwnProperty(stream.current().toLowerCase())) || 339 | (state.stateArg == "@counter-style" && !counterDescriptors.hasOwnProperty(stream.current().toLowerCase()))) 340 | override = "error"; 341 | else 342 | override = "property"; 343 | return "maybeprop"; 344 | } 345 | return "restricted_atBlock"; 346 | }; 347 | 348 | states.keyframes = function (type, stream, state) { 349 | if (type == "word") { override = "variable"; return "keyframes"; } 350 | if (type == "{") return pushContext(state, stream, "top"); 351 | return pass(type, stream, state); 352 | }; 353 | 354 | states.at = function (type, stream, state) { 355 | if (type == ";") return popContext(state); 356 | if (type == "{" || type == "}") return popAndPass(type, stream, state); 357 | if (type == "word") override = "tag"; 358 | else if (type == "hash") override = "builtin"; 359 | return "at"; 360 | }; 361 | 362 | states.interpolation = function (type, stream, state) { 363 | if (type == "}") return popContext(state); 364 | if (type == "{" || type == ";") return popAndPass(type, stream, state); 365 | if (type == "word") override = "variable"; 366 | else if (type != "variable" && type != "(" && type != ")") override = "error"; 367 | return "interpolation"; 368 | }; 369 | 370 | return { 371 | startState: function (base) { 372 | return { 373 | tokenize: null, 374 | state: inline ? "block" : "top", 375 | stateArg: null, 376 | context: new Context(inline ? "block" : "top", base || 0, null) 377 | }; 378 | }, 379 | 380 | token: function (stream, state) { 381 | if (!state.tokenize && stream.eatSpace()) return null; 382 | var style = (state.tokenize || tokenBase)(stream, state); 383 | if (style && typeof style == "object") { 384 | type = style[1]; 385 | style = style[0]; 386 | } 387 | override = style; 388 | if (type != "comment") 389 | state.state = states[state.state](type, stream, state); 390 | return override; 391 | }, 392 | 393 | indent: function (state, textAfter) { 394 | var cx = state.context, ch = textAfter && textAfter.charAt(0); 395 | var indent = cx.indent; 396 | if (cx.type == "prop" && (ch == "}" || ch == ")")) cx = cx.prev; 397 | if (cx.prev) { 398 | if (ch == "}" && (cx.type == "block" || cx.type == "top" || 399 | cx.type == "interpolation" || cx.type == "restricted_atBlock")) { 400 | // Resume indentation from parent context. 401 | cx = cx.prev; 402 | indent = cx.indent; 403 | } else if (ch == ")" && (cx.type == "parens" || cx.type == "atBlock_parens") || 404 | ch == "{" && (cx.type == "at" || cx.type == "atBlock")) { 405 | // Dedent relative to current context. 406 | indent = Math.max(0, cx.indent - indentUnit); 407 | } 408 | } 409 | return indent; 410 | }, 411 | 412 | electricChars: "}", 413 | blockCommentStart: "/*", 414 | blockCommentEnd: "*/", 415 | blockCommentContinue: " * ", 416 | lineComment: lineComment, 417 | fold: "brace" 418 | }; 419 | }); 420 | 421 | function keySet(array) { 422 | var keys = {}; 423 | for (var i = 0; i < array.length; ++i) { 424 | keys[array[i].toLowerCase()] = true; 425 | } 426 | return keys; 427 | } 428 | 429 | var documentTypes_ = [ 430 | "domain", "regexp", "url", "url-prefix" 431 | ], documentTypes = keySet(documentTypes_); 432 | 433 | var mediaTypes_ = [ 434 | "all", "aural", "braille", "handheld", "print", "projection", "screen", 435 | "tty", "tv", "embossed" 436 | ], mediaTypes = keySet(mediaTypes_); 437 | 438 | var mediaFeatures_ = [ 439 | "width", "min-width", "max-width", "height", "min-height", "max-height", 440 | "device-width", "min-device-width", "max-device-width", "device-height", 441 | "min-device-height", "max-device-height", "aspect-ratio", 442 | "min-aspect-ratio", "max-aspect-ratio", "device-aspect-ratio", 443 | "min-device-aspect-ratio", "max-device-aspect-ratio", "color", "min-color", 444 | "max-color", "color-index", "min-color-index", "max-color-index", 445 | "monochrome", "min-monochrome", "max-monochrome", "resolution", 446 | "min-resolution", "max-resolution", "scan", "grid", "orientation", 447 | "device-pixel-ratio", "min-device-pixel-ratio", "max-device-pixel-ratio", 448 | "pointer", "any-pointer", "hover", "any-hover", "prefers-color-scheme" 449 | ], mediaFeatures = keySet(mediaFeatures_); 450 | 451 | var mediaValueKeywords_ = [ 452 | "landscape", "portrait", "none", "coarse", "fine", "on-demand", "hover", 453 | "interlace", "progressive", 454 | "dark", "light" 455 | ], mediaValueKeywords = keySet(mediaValueKeywords_); 456 | 457 | var propertyKeywords_ = [ 458 | "align-content", "align-items", "align-self", "alignment-adjust", 459 | "alignment-baseline", "all", "anchor-point", "animation", "animation-delay", 460 | "animation-direction", "animation-duration", "animation-fill-mode", 461 | "animation-iteration-count", "animation-name", "animation-play-state", 462 | "animation-timing-function", "appearance", "azimuth", "backdrop-filter", 463 | "backface-visibility", "background", "background-attachment", 464 | "background-blend-mode", "background-clip", "background-color", 465 | "background-image", "background-origin", "background-position", 466 | "background-position-x", "background-position-y", "background-repeat", 467 | "background-size", "baseline-shift", "binding", "bleed", "block-size", 468 | "bookmark-label", "bookmark-level", "bookmark-state", "bookmark-target", 469 | "border", "border-bottom", "border-bottom-color", "border-bottom-left-radius", 470 | "border-bottom-right-radius", "border-bottom-style", "border-bottom-width", 471 | "border-collapse", "border-color", "border-image", "border-image-outset", 472 | "border-image-repeat", "border-image-slice", "border-image-source", 473 | "border-image-width", "border-left", "border-left-color", "border-left-style", 474 | "border-left-width", "border-radius", "border-right", "border-right-color", 475 | "border-right-style", "border-right-width", "border-spacing", "border-style", 476 | "border-top", "border-top-color", "border-top-left-radius", 477 | "border-top-right-radius", "border-top-style", "border-top-width", 478 | "border-width", "bottom", "box-decoration-break", "box-shadow", "box-sizing", 479 | "break-after", "break-before", "break-inside", "caption-side", "caret-color", 480 | "clear", "clip", "color", "color-profile", "column-count", "column-fill", 481 | "column-gap", "column-rule", "column-rule-color", "column-rule-style", 482 | "column-rule-width", "column-span", "column-width", "columns", "contain", 483 | "content", "counter-increment", "counter-reset", "crop", "cue", "cue-after", 484 | "cue-before", "cursor", "direction", "display", "dominant-baseline", 485 | "drop-initial-after-adjust", "drop-initial-after-align", 486 | "drop-initial-before-adjust", "drop-initial-before-align", "drop-initial-size", 487 | "drop-initial-value", "elevation", "empty-cells", "fit", "fit-position", 488 | "flex", "flex-basis", "flex-direction", "flex-flow", "flex-grow", 489 | "flex-shrink", "flex-wrap", "float", "float-offset", "flow-from", "flow-into", 490 | "font", "font-family", "font-feature-settings", "font-kerning", 491 | "font-language-override", "font-optical-sizing", "font-size", 492 | "font-size-adjust", "font-stretch", "font-style", "font-synthesis", 493 | "font-variant", "font-variant-alternates", "font-variant-caps", 494 | "font-variant-east-asian", "font-variant-ligatures", "font-variant-numeric", 495 | "font-variant-position", "font-variation-settings", "font-weight", "gap", 496 | "grid", "grid-area", "grid-auto-columns", "grid-auto-flow", "grid-auto-rows", 497 | "grid-column", "grid-column-end", "grid-column-gap", "grid-column-start", 498 | "grid-gap", "grid-row", "grid-row-end", "grid-row-gap", "grid-row-start", 499 | "grid-template", "grid-template-areas", "grid-template-columns", 500 | "grid-template-rows", "hanging-punctuation", "height", "hyphens", "icon", 501 | "image-orientation", "image-rendering", "image-resolution", "inline-box-align", 502 | "inset", "inset-block", "inset-block-end", "inset-block-start", "inset-inline", 503 | "inset-inline-end", "inset-inline-start", "isolation", "justify-content", 504 | "justify-items", "justify-self", "left", "letter-spacing", "line-break", 505 | "line-height", "line-height-step", "line-stacking", "line-stacking-ruby", 506 | "line-stacking-shift", "line-stacking-strategy", "list-style", 507 | "list-style-image", "list-style-position", "list-style-type", "margin", 508 | "margin-bottom", "margin-left", "margin-right", "margin-top", "marks", 509 | "marquee-direction", "marquee-loop", "marquee-play-count", "marquee-speed", 510 | "marquee-style", "mask-clip", "mask-composite", "mask-image", "mask-mode", 511 | "mask-origin", "mask-position", "mask-repeat", "mask-size", "mask-type", 512 | "max-block-size", "max-height", "max-inline-size", 513 | "max-width", "min-block-size", "min-height", "min-inline-size", "min-width", 514 | "mix-blend-mode", "move-to", "nav-down", "nav-index", "nav-left", "nav-right", 515 | "nav-up", "object-fit", "object-position", "offset", "offset-anchor", 516 | "offset-distance", "offset-path", "offset-position", "offset-rotate", 517 | "opacity", "order", "orphans", "outline", "outline-color", "outline-offset", 518 | "outline-style", "outline-width", "overflow", "overflow-style", 519 | "overflow-wrap", "overflow-x", "overflow-y", "padding", "padding-bottom", 520 | "padding-left", "padding-right", "padding-top", "page", "page-break-after", 521 | "page-break-before", "page-break-inside", "page-policy", "pause", 522 | "pause-after", "pause-before", "perspective", "perspective-origin", "pitch", 523 | "pitch-range", "place-content", "place-items", "place-self", "play-during", 524 | "position", "presentation-level", "punctuation-trim", "quotes", 525 | "region-break-after", "region-break-before", "region-break-inside", 526 | "region-fragment", "rendering-intent", "resize", "rest", "rest-after", 527 | "rest-before", "richness", "right", "rotate", "rotation", "rotation-point", 528 | "row-gap", "ruby-align", "ruby-overhang", "ruby-position", "ruby-span", 529 | "scale", "scroll-behavior", "scroll-margin", "scroll-margin-block", 530 | "scroll-margin-block-end", "scroll-margin-block-start", "scroll-margin-bottom", 531 | "scroll-margin-inline", "scroll-margin-inline-end", 532 | "scroll-margin-inline-start", "scroll-margin-left", "scroll-margin-right", 533 | "scroll-margin-top", "scroll-padding", "scroll-padding-block", 534 | "scroll-padding-block-end", "scroll-padding-block-start", 535 | "scroll-padding-bottom", "scroll-padding-inline", "scroll-padding-inline-end", 536 | "scroll-padding-inline-start", "scroll-padding-left", "scroll-padding-right", 537 | "scroll-padding-top", "scroll-snap-align", "scroll-snap-type", 538 | "shape-image-threshold", "shape-inside", "shape-margin", "shape-outside", 539 | "size", "speak", "speak-as", "speak-header", "speak-numeral", 540 | "speak-punctuation", "speech-rate", "stress", "string-set", "tab-size", 541 | "table-layout", "target", "target-name", "target-new", "target-position", 542 | "text-align", "text-align-last", "text-combine-upright", "text-decoration", 543 | "text-decoration-color", "text-decoration-line", "text-decoration-skip", 544 | "text-decoration-skip-ink", "text-decoration-style", "text-emphasis", 545 | "text-emphasis-color", "text-emphasis-position", "text-emphasis-style", 546 | "text-height", "text-indent", "text-justify", "text-orientation", 547 | "text-outline", "text-overflow", "text-rendering", "text-shadow", 548 | "text-size-adjust", "text-space-collapse", "text-transform", 549 | "text-underline-position", "text-wrap", "top", "touch-action", "transform", "transform-origin", 550 | "transform-style", "transition", "transition-delay", "transition-duration", 551 | "transition-property", "transition-timing-function", "translate", 552 | "unicode-bidi", "user-select", "vertical-align", "visibility", "voice-balance", 553 | "voice-duration", "voice-family", "voice-pitch", "voice-range", "voice-rate", 554 | "voice-stress", "voice-volume", "volume", "white-space", "widows", "width", 555 | "will-change", "word-break", "word-spacing", "word-wrap", "writing-mode", "z-index", 556 | // SVG-specific 557 | "clip-path", "clip-rule", "mask", "enable-background", "filter", "flood-color", 558 | "flood-opacity", "lighting-color", "stop-color", "stop-opacity", "pointer-events", 559 | "color-interpolation", "color-interpolation-filters", 560 | "color-rendering", "fill", "fill-opacity", "fill-rule", "image-rendering", 561 | "marker", "marker-end", "marker-mid", "marker-start", "paint-order", "shape-rendering", "stroke", 562 | "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", 563 | "stroke-miterlimit", "stroke-opacity", "stroke-width", "text-rendering", 564 | "baseline-shift", "dominant-baseline", "glyph-orientation-horizontal", 565 | "glyph-orientation-vertical", "text-anchor", "writing-mode", 566 | ], propertyKeywords = keySet(propertyKeywords_); 567 | 568 | var nonStandardPropertyKeywords_ = [ 569 | "border-block", "border-block-color", "border-block-end", 570 | "border-block-end-color", "border-block-end-style", "border-block-end-width", 571 | "border-block-start", "border-block-start-color", "border-block-start-style", 572 | "border-block-start-width", "border-block-style", "border-block-width", 573 | "border-inline", "border-inline-color", "border-inline-end", 574 | "border-inline-end-color", "border-inline-end-style", 575 | "border-inline-end-width", "border-inline-start", "border-inline-start-color", 576 | "border-inline-start-style", "border-inline-start-width", 577 | "border-inline-style", "border-inline-width", "margin-block", 578 | "margin-block-end", "margin-block-start", "margin-inline", "margin-inline-end", 579 | "margin-inline-start", "padding-block", "padding-block-end", 580 | "padding-block-start", "padding-inline", "padding-inline-end", 581 | "padding-inline-start", "scroll-snap-stop", "scrollbar-3d-light-color", 582 | "scrollbar-arrow-color", "scrollbar-base-color", "scrollbar-dark-shadow-color", 583 | "scrollbar-face-color", "scrollbar-highlight-color", "scrollbar-shadow-color", 584 | "scrollbar-track-color", "searchfield-cancel-button", "searchfield-decoration", 585 | "searchfield-results-button", "searchfield-results-decoration", "shape-inside", "zoom" 586 | ], nonStandardPropertyKeywords = keySet(nonStandardPropertyKeywords_); 587 | 588 | var fontProperties_ = [ 589 | "font-display", "font-family", "src", "unicode-range", "font-variant", 590 | "font-feature-settings", "font-stretch", "font-weight", "font-style" 591 | ], fontProperties = keySet(fontProperties_); 592 | 593 | var counterDescriptors_ = [ 594 | "additive-symbols", "fallback", "negative", "pad", "prefix", "range", 595 | "speak-as", "suffix", "symbols", "system" 596 | ], counterDescriptors = keySet(counterDescriptors_); 597 | 598 | var colorKeywords_ = [ 599 | "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige", 600 | "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown", 601 | "burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue", 602 | "cornsilk", "crimson", "cyan", "darkblue", "darkcyan", "darkgoldenrod", 603 | "darkgray", "darkgreen", "darkkhaki", "darkmagenta", "darkolivegreen", 604 | "darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen", 605 | "darkslateblue", "darkslategray", "darkturquoise", "darkviolet", 606 | "deeppink", "deepskyblue", "dimgray", "dodgerblue", "firebrick", 607 | "floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite", 608 | "gold", "goldenrod", "gray", "grey", "green", "greenyellow", "honeydew", 609 | "hotpink", "indianred", "indigo", "ivory", "khaki", "lavender", 610 | "lavenderblush", "lawngreen", "lemonchiffon", "lightblue", "lightcoral", 611 | "lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", "lightpink", 612 | "lightsalmon", "lightseagreen", "lightskyblue", "lightslategray", 613 | "lightsteelblue", "lightyellow", "lime", "limegreen", "linen", "magenta", 614 | "maroon", "mediumaquamarine", "mediumblue", "mediumorchid", "mediumpurple", 615 | "mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise", 616 | "mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin", 617 | "navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange", "orangered", 618 | "orchid", "palegoldenrod", "palegreen", "paleturquoise", "palevioletred", 619 | "papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue", 620 | "purple", "rebeccapurple", "red", "rosybrown", "royalblue", "saddlebrown", 621 | "salmon", "sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue", 622 | "slateblue", "slategray", "snow", "springgreen", "steelblue", "tan", 623 | "teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white", 624 | "whitesmoke", "yellow", "yellowgreen" 625 | ], colorKeywords = keySet(colorKeywords_); 626 | 627 | var valueKeywords_ = [ 628 | "above", "absolute", "activeborder", "additive", "activecaption", "afar", 629 | "after-white-space", "ahead", "alias", "all", "all-scroll", "alphabetic", "alternate", 630 | "always", "amharic", "amharic-abegede", "antialiased", "appworkspace", 631 | "arabic-indic", "armenian", "asterisks", "attr", "auto", "auto-flow", "avoid", "avoid-column", "avoid-page", 632 | "avoid-region", "axis-pan", "background", "backwards", "baseline", "below", "bidi-override", "binary", 633 | "bengali", "blink", "block", "block-axis", "bold", "bolder", "border", "border-box", 634 | "both", "bottom", "break", "break-all", "break-word", "bullets", "button", "button-bevel", 635 | "buttonface", "buttonhighlight", "buttonshadow", "buttontext", "calc", "cambodian", 636 | "capitalize", "caps-lock-indicator", "caption", "captiontext", "caret", 637 | "cell", "center", "checkbox", "circle", "cjk-decimal", "cjk-earthly-branch", 638 | "cjk-heavenly-stem", "cjk-ideographic", "clear", "clip", "close-quote", 639 | "col-resize", "collapse", "color", "color-burn", "color-dodge", "column", "column-reverse", 640 | "compact", "condensed", "contain", "content", "contents", 641 | "content-box", "context-menu", "continuous", "copy", "counter", "counters", "cover", "crop", 642 | "cross", "crosshair", "currentcolor", "cursive", "cyclic", "darken", "dashed", "decimal", 643 | "decimal-leading-zero", "default", "default-button", "dense", "destination-atop", 644 | "destination-in", "destination-out", "destination-over", "devanagari", "difference", 645 | "disc", "discard", "disclosure-closed", "disclosure-open", "document", 646 | "dot-dash", "dot-dot-dash", 647 | "dotted", "double", "down", "e-resize", "ease", "ease-in", "ease-in-out", "ease-out", 648 | "element", "ellipse", "ellipsis", "embed", "end", "ethiopic", "ethiopic-abegede", 649 | "ethiopic-abegede-am-et", "ethiopic-abegede-gez", "ethiopic-abegede-ti-er", 650 | "ethiopic-abegede-ti-et", "ethiopic-halehame-aa-er", 651 | "ethiopic-halehame-aa-et", "ethiopic-halehame-am-et", 652 | "ethiopic-halehame-gez", "ethiopic-halehame-om-et", 653 | "ethiopic-halehame-sid-et", "ethiopic-halehame-so-et", 654 | "ethiopic-halehame-ti-er", "ethiopic-halehame-ti-et", "ethiopic-halehame-tig", 655 | "ethiopic-numeric", "ew-resize", "exclusion", "expanded", "extends", "extra-condensed", 656 | "extra-expanded", "fantasy", "fast", "fill", "fill-box", "fixed", "flat", "flex", "flex-end", "flex-start", "footnotes", 657 | "forwards", "from", "geometricPrecision", "georgian", "graytext", "grid", "groove", 658 | "gujarati", "gurmukhi", "hand", "hangul", "hangul-consonant", "hard-light", "hebrew", 659 | "help", "hidden", "hide", "higher", "highlight", "highlighttext", 660 | "hiragana", "hiragana-iroha", "horizontal", "hsl", "hsla", "hue", "icon", "ignore", 661 | "inactiveborder", "inactivecaption", "inactivecaptiontext", "infinite", 662 | "infobackground", "infotext", "inherit", "initial", "inline", "inline-axis", 663 | "inline-block", "inline-flex", "inline-grid", "inline-table", "inset", "inside", "intrinsic", "invert", 664 | "italic", "japanese-formal", "japanese-informal", "justify", "kannada", 665 | "katakana", "katakana-iroha", "keep-all", "khmer", 666 | "korean-hangul-formal", "korean-hanja-formal", "korean-hanja-informal", 667 | "landscape", "lao", "large", "larger", "left", "level", "lighter", "lighten", 668 | "line-through", "linear", "linear-gradient", "lines", "list-item", "listbox", "listitem", 669 | "local", "logical", "loud", "lower", "lower-alpha", "lower-armenian", 670 | "lower-greek", "lower-hexadecimal", "lower-latin", "lower-norwegian", 671 | "lower-roman", "lowercase", "ltr", "luminosity", "malayalam", "manipulation", "match", "matrix", "matrix3d", 672 | "media-controls-background", "media-current-time-display", 673 | "media-fullscreen-button", "media-mute-button", "media-play-button", 674 | "media-return-to-realtime-button", "media-rewind-button", 675 | "media-seek-back-button", "media-seek-forward-button", "media-slider", 676 | "media-sliderthumb", "media-time-remaining-display", "media-volume-slider", 677 | "media-volume-slider-container", "media-volume-sliderthumb", "medium", 678 | "menu", "menulist", "menulist-button", "menulist-text", 679 | "menulist-textfield", "menutext", "message-box", "middle", "min-intrinsic", 680 | "mix", "mongolian", "monospace", "move", "multiple", "multiple_mask_images", "multiply", "myanmar", "n-resize", 681 | "narrower", "ne-resize", "nesw-resize", "no-close-quote", "no-drop", 682 | "no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap", 683 | "ns-resize", "numbers", "numeric", "nw-resize", "nwse-resize", "oblique", "octal", "opacity", "open-quote", 684 | "optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset", 685 | "outside", "outside-shape", "overlay", "overline", "padding", "padding-box", 686 | "painted", "page", "paused", "persian", "perspective", "pinch-zoom", "plus-darker", "plus-lighter", 687 | "pointer", "polygon", "portrait", "pre", "pre-line", "pre-wrap", "preserve-3d", 688 | "progress", "push-button", "radial-gradient", "radio", "read-only", 689 | "read-write", "read-write-plaintext-only", "rectangle", "region", 690 | "relative", "repeat", "repeating-linear-gradient", 691 | "repeating-radial-gradient", "repeat-x", "repeat-y", "reset", "reverse", 692 | "rgb", "rgba", "ridge", "right", "rotate", "rotate3d", "rotateX", "rotateY", 693 | "rotateZ", "round", "row", "row-resize", "row-reverse", "rtl", "run-in", "running", 694 | "s-resize", "sans-serif", "saturation", "scale", "scale3d", "scaleX", "scaleY", "scaleZ", "screen", 695 | "scroll", "scrollbar", "scroll-position", "se-resize", "searchfield", 696 | "searchfield-cancel-button", "searchfield-decoration", 697 | "searchfield-results-button", "searchfield-results-decoration", "self-start", "self-end", 698 | "semi-condensed", "semi-expanded", "separate", "serif", "show", "sidama", 699 | "simp-chinese-formal", "simp-chinese-informal", "single", 700 | "skew", "skewX", "skewY", "skip-white-space", "slide", "slider-horizontal", 701 | "slider-vertical", "sliderthumb-horizontal", "sliderthumb-vertical", "slow", 702 | "small", "small-caps", "small-caption", "smaller", "soft-light", "solid", "somali", 703 | "source-atop", "source-in", "source-out", "source-over", "space", "space-around", "space-between", "space-evenly", "spell-out", "square", 704 | "square-button", "start", "static", "status-bar", "stretch", "stroke", "stroke-box", "sub", 705 | "subpixel-antialiased", "svg_masks", "super", "sw-resize", "symbolic", "symbols", "system-ui", "table", 706 | "table-caption", "table-cell", "table-column", "table-column-group", 707 | "table-footer-group", "table-header-group", "table-row", "table-row-group", 708 | "tamil", 709 | "telugu", "text", "text-bottom", "text-top", "textarea", "textfield", "thai", 710 | "thick", "thin", "threeddarkshadow", "threedface", "threedhighlight", 711 | "threedlightshadow", "threedshadow", "tibetan", "tigre", "tigrinya-er", 712 | "tigrinya-er-abegede", "tigrinya-et", "tigrinya-et-abegede", "to", "top", 713 | "trad-chinese-formal", "trad-chinese-informal", "transform", 714 | "translate", "translate3d", "translateX", "translateY", "translateZ", 715 | "transparent", "ultra-condensed", "ultra-expanded", "underline", "unidirectional-pan", "unset", "up", 716 | "upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal", 717 | "upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url", 718 | "var", "vertical", "vertical-text", "view-box", "visible", "visibleFill", "visiblePainted", 719 | "visibleStroke", "visual", "w-resize", "wait", "wave", "wider", 720 | "window", "windowframe", "windowtext", "words", "wrap", "wrap-reverse", "x-large", "x-small", "xor", 721 | "xx-large", "xx-small" 722 | ], valueKeywords = keySet(valueKeywords_); 723 | 724 | var allWords = documentTypes_.concat(mediaTypes_).concat(mediaFeatures_).concat(mediaValueKeywords_) 725 | .concat(propertyKeywords_).concat(nonStandardPropertyKeywords_).concat(colorKeywords_) 726 | .concat(valueKeywords_); 727 | CodeMirror.registerHelper("hintWords", "css", allWords); 728 | 729 | function tokenCComment(stream, state) { 730 | var maybeEnd = false, ch; 731 | while ((ch = stream.next()) != null) { 732 | if (maybeEnd && ch == "/") { 733 | state.tokenize = null; 734 | break; 735 | } 736 | maybeEnd = (ch == "*"); 737 | } 738 | return ["comment", "comment"]; 739 | } 740 | 741 | CodeMirror.defineMIME("text/css", { 742 | documentTypes: documentTypes, 743 | mediaTypes: mediaTypes, 744 | mediaFeatures: mediaFeatures, 745 | mediaValueKeywords: mediaValueKeywords, 746 | propertyKeywords: propertyKeywords, 747 | nonStandardPropertyKeywords: nonStandardPropertyKeywords, 748 | fontProperties: fontProperties, 749 | counterDescriptors: counterDescriptors, 750 | colorKeywords: colorKeywords, 751 | valueKeywords: valueKeywords, 752 | tokenHooks: { 753 | "/": function (stream, state) { 754 | if (!stream.eat("*")) return false; 755 | state.tokenize = tokenCComment; 756 | return tokenCComment(stream, state); 757 | } 758 | }, 759 | name: "css" 760 | }); 761 | 762 | CodeMirror.defineMIME("text/x-scss", { 763 | mediaTypes: mediaTypes, 764 | mediaFeatures: mediaFeatures, 765 | mediaValueKeywords: mediaValueKeywords, 766 | propertyKeywords: propertyKeywords, 767 | nonStandardPropertyKeywords: nonStandardPropertyKeywords, 768 | colorKeywords: colorKeywords, 769 | valueKeywords: valueKeywords, 770 | fontProperties: fontProperties, 771 | allowNested: true, 772 | lineComment: "//", 773 | tokenHooks: { 774 | "/": function (stream, state) { 775 | if (stream.eat("/")) { 776 | stream.skipToEnd(); 777 | return ["comment", "comment"]; 778 | } else if (stream.eat("*")) { 779 | state.tokenize = tokenCComment; 780 | return tokenCComment(stream, state); 781 | } else { 782 | return ["operator", "operator"]; 783 | } 784 | }, 785 | ":": function (stream) { 786 | if (stream.match(/^\s*\{/, false)) 787 | return [null, null] 788 | return false; 789 | }, 790 | "$": function (stream) { 791 | stream.match(/^[\w-]+/); 792 | if (stream.match(/^\s*:/, false)) 793 | return ["variable-2", "variable-definition"]; 794 | return ["variable-2", "variable"]; 795 | }, 796 | "#": function (stream) { 797 | if (!stream.eat("{")) return false; 798 | return [null, "interpolation"]; 799 | } 800 | }, 801 | name: "css", 802 | helperType: "scss" 803 | }); 804 | 805 | CodeMirror.defineMIME("text/x-less", { 806 | mediaTypes: mediaTypes, 807 | mediaFeatures: mediaFeatures, 808 | mediaValueKeywords: mediaValueKeywords, 809 | propertyKeywords: propertyKeywords, 810 | nonStandardPropertyKeywords: nonStandardPropertyKeywords, 811 | colorKeywords: colorKeywords, 812 | valueKeywords: valueKeywords, 813 | fontProperties: fontProperties, 814 | allowNested: true, 815 | lineComment: "//", 816 | tokenHooks: { 817 | "/": function (stream, state) { 818 | if (stream.eat("/")) { 819 | stream.skipToEnd(); 820 | return ["comment", "comment"]; 821 | } else if (stream.eat("*")) { 822 | state.tokenize = tokenCComment; 823 | return tokenCComment(stream, state); 824 | } else { 825 | return ["operator", "operator"]; 826 | } 827 | }, 828 | "@": function (stream) { 829 | if (stream.eat("{")) return [null, "interpolation"]; 830 | if (stream.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/i, false)) return false; 831 | stream.eatWhile(/[\w\\\-]/); 832 | if (stream.match(/^\s*:/, false)) 833 | return ["variable-2", "variable-definition"]; 834 | return ["variable-2", "variable"]; 835 | }, 836 | "&": function () { 837 | return ["atom", "atom"]; 838 | } 839 | }, 840 | name: "css", 841 | helperType: "less" 842 | }); 843 | 844 | CodeMirror.defineMIME("text/x-gss", { 845 | documentTypes: documentTypes, 846 | mediaTypes: mediaTypes, 847 | mediaFeatures: mediaFeatures, 848 | propertyKeywords: propertyKeywords, 849 | nonStandardPropertyKeywords: nonStandardPropertyKeywords, 850 | fontProperties: fontProperties, 851 | counterDescriptors: counterDescriptors, 852 | colorKeywords: colorKeywords, 853 | valueKeywords: valueKeywords, 854 | supportsAtComponent: true, 855 | tokenHooks: { 856 | "/": function (stream, state) { 857 | if (!stream.eat("*")) return false; 858 | state.tokenize = tokenCComment; 859 | return tokenCComment(stream, state); 860 | } 861 | }, 862 | name: "css", 863 | helperType: "gss" 864 | }); 865 | 866 | }); 867 | -------------------------------------------------------------------------------- /js/libs/formatting.js: -------------------------------------------------------------------------------- 1 | 2 | (function() { 3 | 4 | CodeMirror.extendMode("css", { 5 | commentStart: "/*", 6 | commentEnd: "*/", 7 | newlineAfterToken: function(_type, content) { 8 | return /^[;{}]$/.test(content); 9 | } 10 | }); 11 | 12 | CodeMirror.extendMode("javascript", { 13 | commentStart: "/*", 14 | commentEnd: "*/", 15 | // FIXME semicolons inside of for 16 | newlineAfterToken: function(_type, content, textAfter, state) { 17 | if (this.jsonMode) { 18 | return /^[\[,{]$/.test(content) || /^}/.test(textAfter); 19 | } else { 20 | if (content == ";" && state.lexical && state.lexical.type == ")") return false; 21 | return /^[;{}]$/.test(content) && !/^;/.test(textAfter); 22 | } 23 | } 24 | }); 25 | 26 | var inlineElements = /^(a|abbr|acronym|area|base|bdo|big|br|button|caption|cite|code|col|colgroup|dd|del|dfn|em|frame|hr|iframe|img|input|ins|kbd|label|legend|link|map|object|optgroup|option|param|q|samp|script|select|small|span|strong|sub|sup|textarea|tt|var)$/; 27 | 28 | CodeMirror.extendMode("xml", { 29 | commentStart: "", 31 | newlineAfterToken: function(type, content, textAfter, state) { 32 | var inline = false; 33 | if (this.configuration == "html") 34 | inline = state.context ? inlineElements.test(state.context.tagName) : false; 35 | return !inline && ((type == "tag" && />$/.test(content) && state.context) || 36 | /^ -1 && endIndex > -1 && endIndex > startIndex) { 54 | // Take string till comment start 55 | selText = selText.substr(0, startIndex) 56 | // From comment start till comment end 57 | + selText.substring(startIndex + curMode.commentStart.length, endIndex) 58 | // From comment end till string end 59 | + selText.substr(endIndex + curMode.commentEnd.length); 60 | } 61 | cm.replaceRange(selText, from, to); 62 | } 63 | }); 64 | }); 65 | 66 | // Applies automatic mode-aware indentation to the specified range 67 | CodeMirror.defineExtension("autoIndentRange", function (from, to) { 68 | var cmInstance = this; 69 | this.operation(function () { 70 | for (var i = from.line; i <= to.line; i++) { 71 | cmInstance.indentLine(i, "smart"); 72 | } 73 | }); 74 | }); 75 | 76 | // Applies automatic formatting to the specified range 77 | CodeMirror.defineExtension("autoFormatRange", function (from, to) { 78 | var cm = this; 79 | var outer = cm.getMode(), text = cm.getRange(from, to).split("\n"); 80 | var state = CodeMirror.copyState(outer, cm.getTokenAt(from).state); 81 | var tabSize = cm.getOption("tabSize"); 82 | 83 | var out = "", lines = 0, atSol = from.ch == 0; 84 | function newline() { 85 | out += "\n"; 86 | atSol = true; 87 | ++lines; 88 | } 89 | 90 | for (var i = 0; i < text.length; ++i) { 91 | var stream = new CodeMirror.StringStream(text[i], tabSize); 92 | while (!stream.eol()) { 93 | var inner = CodeMirror.innerMode(outer, state); 94 | var style = outer.token(stream, state), cur = stream.current(); 95 | stream.start = stream.pos; 96 | if (!atSol || /\S/.test(cur)) { 97 | out += cur; 98 | atSol = false; 99 | } 100 | if (!atSol && inner.mode.newlineAfterToken && 101 | inner.mode.newlineAfterToken(style, cur, stream.string.slice(stream.pos) || text[i+1] || "", inner.state)) 102 | newline(); 103 | } 104 | if (!stream.pos && outer.blankLine) outer.blankLine(state); 105 | if (!atSol && i < text.length - 1) newline(); 106 | } 107 | 108 | cm.operation(function () { 109 | cm.replaceRange(out, from, to); 110 | for (var cur = from.line + 1, end = from.line + lines; cur <= end; ++cur) 111 | cm.indentLine(cur, "smart"); 112 | cm.setSelection(from, cm.getCursor(false)); 113 | }); 114 | }); 115 | })(); -------------------------------------------------------------------------------- /js/libs/html-hint.js: -------------------------------------------------------------------------------- 1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 | // Distributed under an MIT license: https://codemirror.net/LICENSE 3 | 4 | (function(mod) { 5 | if (typeof exports == "object" && typeof module == "object") // CommonJS 6 | mod(require("../../lib/codemirror"), require("./xml-hint")); 7 | else if (typeof define == "function" && define.amd) // AMD 8 | define(["../../lib/codemirror", "./xml-hint"], mod); 9 | else // Plain browser env 10 | mod(CodeMirror); 11 | })(function(CodeMirror) { 12 | "use strict"; 13 | 14 | var langs = "ab aa af ak sq am ar an hy as av ae ay az bm ba eu be bn bh bi bs br bg my ca ch ce ny zh cv kw co cr hr cs da dv nl dz en eo et ee fo fj fi fr ff gl ka de el gn gu ht ha he hz hi ho hu ia id ie ga ig ik io is it iu ja jv kl kn kr ks kk km ki rw ky kv kg ko ku kj la lb lg li ln lo lt lu lv gv mk mg ms ml mt mi mr mh mn na nv nb nd ne ng nn no ii nr oc oj cu om or os pa pi fa pl ps pt qu rm rn ro ru sa sc sd se sm sg sr gd sn si sk sl so st es su sw ss sv ta te tg th ti bo tk tl tn to tr ts tt tw ty ug uk ur uz ve vi vo wa cy wo fy xh yi yo za zu".split(" "); 15 | var targets = ["_blank", "_self", "_top", "_parent"]; 16 | var charsets = ["ascii", "utf-8", "utf-16", "latin1", "latin1"]; 17 | var methods = ["get", "post", "put", "delete"]; 18 | var encs = ["application/x-www-form-urlencoded", "multipart/form-data", "text/plain"]; 19 | var media = ["all", "screen", "print", "embossed", "braille", "handheld", "print", "projection", "screen", "tty", "tv", "speech", 20 | "3d-glasses", "resolution [>][<][=] [X]", "device-aspect-ratio: X/Y", "orientation:portrait", 21 | "orientation:landscape", "device-height: [X]", "device-width: [X]"]; 22 | var s = { attrs: {} }; // Simple tag, reused for a whole lot of tags 23 | 24 | var data = { 25 | a: { 26 | attrs: { 27 | href: null, ping: null, type: null, 28 | media: media, 29 | target: targets, 30 | hreflang: langs 31 | } 32 | }, 33 | abbr: s, 34 | acronym: s, 35 | address: s, 36 | applet: s, 37 | area: { 38 | attrs: { 39 | alt: null, coords: null, href: null, target: null, ping: null, 40 | media: media, hreflang: langs, type: null, 41 | shape: ["default", "rect", "circle", "poly"] 42 | } 43 | }, 44 | article: s, 45 | aside: s, 46 | audio: { 47 | attrs: { 48 | src: null, mediagroup: null, 49 | crossorigin: ["anonymous", "use-credentials"], 50 | preload: ["none", "metadata", "auto"], 51 | autoplay: ["", "autoplay"], 52 | loop: ["", "loop"], 53 | controls: ["", "controls"] 54 | } 55 | }, 56 | b: s, 57 | base: { attrs: { href: null, target: targets } }, 58 | basefont: s, 59 | bdi: s, 60 | bdo: s, 61 | big: s, 62 | blockquote: { attrs: { cite: null } }, 63 | body: s, 64 | br: s, 65 | button: { 66 | attrs: { 67 | form: null, formaction: null, name: null, value: null, 68 | autofocus: ["", "autofocus"], 69 | disabled: ["", "autofocus"], 70 | formenctype: encs, 71 | formmethod: methods, 72 | formnovalidate: ["", "novalidate"], 73 | formtarget: targets, 74 | type: ["submit", "reset", "button"] 75 | } 76 | }, 77 | canvas: { attrs: { width: null, height: null } }, 78 | caption: s, 79 | center: s, 80 | cite: s, 81 | code: s, 82 | col: { attrs: { span: null } }, 83 | colgroup: { attrs: { span: null } }, 84 | command: { 85 | attrs: { 86 | type: ["command", "checkbox", "radio"], 87 | label: null, icon: null, radiogroup: null, command: null, title: null, 88 | disabled: ["", "disabled"], 89 | checked: ["", "checked"] 90 | } 91 | }, 92 | data: { attrs: { value: null } }, 93 | datagrid: { attrs: { disabled: ["", "disabled"], multiple: ["", "multiple"] } }, 94 | datalist: { attrs: { data: null } }, 95 | dd: s, 96 | del: { attrs: { cite: null, datetime: null } }, 97 | details: { attrs: { open: ["", "open"] } }, 98 | dfn: s, 99 | dir: s, 100 | div: s, 101 | dialog: { attrs: { open: null } }, 102 | dl: s, 103 | dt: s, 104 | em: s, 105 | embed: { attrs: { src: null, type: null, width: null, height: null } }, 106 | eventsource: { attrs: { src: null } }, 107 | fieldset: { attrs: { disabled: ["", "disabled"], form: null, name: null } }, 108 | figcaption: s, 109 | figure: s, 110 | font: s, 111 | footer: s, 112 | form: { 113 | attrs: { 114 | action: null, name: null, 115 | "accept-charset": charsets, 116 | autocomplete: ["on", "off"], 117 | enctype: encs, 118 | method: methods, 119 | novalidate: ["", "novalidate"], 120 | target: targets 121 | } 122 | }, 123 | frame: s, 124 | frameset: s, 125 | h1: s, h2: s, h3: s, h4: s, h5: s, h6: s, 126 | head: { 127 | attrs: {}, 128 | children: ["title", "base", "link", "style", "meta", "script", "noscript", "command"] 129 | }, 130 | header: s, 131 | hgroup: s, 132 | hr: s, 133 | html: { 134 | attrs: { manifest: null }, 135 | children: ["head", "body"] 136 | }, 137 | i: s, 138 | iframe: { 139 | attrs: { 140 | src: null, srcdoc: null, name: null, width: null, height: null, 141 | sandbox: ["allow-top-navigation", "allow-same-origin", "allow-forms", "allow-scripts"], 142 | seamless: ["", "seamless"] 143 | } 144 | }, 145 | img: { 146 | attrs: { 147 | alt: null, src: null, ismap: null, usemap: null, width: null, height: null, 148 | crossorigin: ["anonymous", "use-credentials"] 149 | } 150 | }, 151 | input: { 152 | attrs: { 153 | alt: null, dirname: null, form: null, formaction: null, 154 | height: null, list: null, max: null, maxlength: null, min: null, 155 | name: null, pattern: null, placeholder: null, size: null, src: null, 156 | step: null, value: null, width: null, 157 | accept: ["audio/*", "video/*", "image/*"], 158 | autocomplete: ["on", "off"], 159 | autofocus: ["", "autofocus"], 160 | checked: ["", "checked"], 161 | disabled: ["", "disabled"], 162 | formenctype: encs, 163 | formmethod: methods, 164 | formnovalidate: ["", "novalidate"], 165 | formtarget: targets, 166 | multiple: ["", "multiple"], 167 | readonly: ["", "readonly"], 168 | required: ["", "required"], 169 | type: ["hidden", "text", "search", "tel", "url", "email", "password", "datetime", "date", "month", 170 | "week", "time", "datetime-local", "number", "range", "color", "checkbox", "radio", 171 | "file", "submit", "image", "reset", "button"] 172 | } 173 | }, 174 | ins: { attrs: { cite: null, datetime: null } }, 175 | kbd: s, 176 | keygen: { 177 | attrs: { 178 | challenge: null, form: null, name: null, 179 | autofocus: ["", "autofocus"], 180 | disabled: ["", "disabled"], 181 | keytype: ["RSA"] 182 | } 183 | }, 184 | label: { attrs: { "for": null, form: null } }, 185 | legend: s, 186 | li: { attrs: { value: null } }, 187 | link: { 188 | attrs: { 189 | href: null, type: null, 190 | hreflang: langs, 191 | media: media, 192 | sizes: ["all", "16x16", "16x16 32x32", "16x16 32x32 64x64"] 193 | } 194 | }, 195 | map: { attrs: { name: null } }, 196 | mark: s, 197 | menu: { attrs: { label: null, type: ["list", "context", "toolbar"] } }, 198 | meta: { 199 | attrs: { 200 | content: null, 201 | charset: charsets, 202 | name: ["viewport", "application-name", "author", "description", "generator", "keywords"], 203 | "http-equiv": ["content-language", "content-type", "default-style", "refresh"] 204 | } 205 | }, 206 | meter: { attrs: { value: null, min: null, low: null, high: null, max: null, optimum: null } }, 207 | nav: s, 208 | noframes: s, 209 | noscript: s, 210 | object: { 211 | attrs: { 212 | data: null, type: null, name: null, usemap: null, form: null, width: null, height: null, 213 | typemustmatch: ["", "typemustmatch"] 214 | } 215 | }, 216 | ol: { attrs: { reversed: ["", "reversed"], start: null, type: ["1", "a", "A", "i", "I"] } }, 217 | optgroup: { attrs: { disabled: ["", "disabled"], label: null } }, 218 | option: { attrs: { disabled: ["", "disabled"], label: null, selected: ["", "selected"], value: null } }, 219 | output: { attrs: { "for": null, form: null, name: null } }, 220 | p: s, 221 | param: { attrs: { name: null, value: null } }, 222 | pre: s, 223 | progress: { attrs: { value: null, max: null } }, 224 | q: { attrs: { cite: null } }, 225 | rp: s, 226 | rt: s, 227 | ruby: s, 228 | s: s, 229 | samp: s, 230 | script: { 231 | attrs: { 232 | type: ["text/javascript"], 233 | src: null, 234 | async: ["", "async"], 235 | defer: ["", "defer"], 236 | charset: charsets 237 | } 238 | }, 239 | section: s, 240 | select: { 241 | attrs: { 242 | form: null, name: null, size: null, 243 | autofocus: ["", "autofocus"], 244 | disabled: ["", "disabled"], 245 | multiple: ["", "multiple"] 246 | } 247 | }, 248 | small: s, 249 | source: { attrs: { src: null, type: null, media: null } }, 250 | span: s, 251 | strike: s, 252 | strong: s, 253 | style: { 254 | attrs: { 255 | type: ["text/css"], 256 | media: media, 257 | scoped: null 258 | } 259 | }, 260 | sub: s, 261 | summary: s, 262 | sup: s, 263 | table: s, 264 | tbody: s, 265 | td: { attrs: { colspan: null, rowspan: null, headers: null } }, 266 | textarea: { 267 | attrs: { 268 | dirname: null, form: null, maxlength: null, name: null, placeholder: null, 269 | rows: null, cols: null, 270 | autofocus: ["", "autofocus"], 271 | disabled: ["", "disabled"], 272 | readonly: ["", "readonly"], 273 | required: ["", "required"], 274 | wrap: ["soft", "hard"] 275 | } 276 | }, 277 | tfoot: s, 278 | th: { attrs: { colspan: null, rowspan: null, headers: null, scope: ["row", "col", "rowgroup", "colgroup"] } }, 279 | thead: s, 280 | time: { attrs: { datetime: null } }, 281 | title: s, 282 | tr: s, 283 | track: { 284 | attrs: { 285 | src: null, label: null, "default": null, 286 | kind: ["subtitles", "captions", "descriptions", "chapters", "metadata"], 287 | srclang: langs 288 | } 289 | }, 290 | tt: s, 291 | u: s, 292 | ul: s, 293 | "var": s, 294 | video: { 295 | attrs: { 296 | src: null, poster: null, width: null, height: null, 297 | crossorigin: ["anonymous", "use-credentials"], 298 | preload: ["auto", "metadata", "none"], 299 | autoplay: ["", "autoplay"], 300 | mediagroup: ["movie"], 301 | muted: ["", "muted"], 302 | controls: ["", "controls"] 303 | } 304 | }, 305 | wbr: s 306 | }; 307 | 308 | var globalAttrs = { 309 | accesskey: ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"], 310 | "class": null, 311 | contenteditable: ["true", "false"], 312 | contextmenu: null, 313 | dir: ["ltr", "rtl", "auto"], 314 | draggable: ["true", "false", "auto"], 315 | dropzone: ["copy", "move", "link", "string:", "file:"], 316 | hidden: ["hidden"], 317 | id: null, 318 | inert: ["inert"], 319 | itemid: null, 320 | itemprop: null, 321 | itemref: null, 322 | itemscope: ["itemscope"], 323 | itemtype: null, 324 | lang: ["en", "es"], 325 | spellcheck: ["true", "false"], 326 | autocorrect: ["true", "false"], 327 | autocapitalize: ["true", "false"], 328 | style: null, 329 | tabindex: ["1", "2", "3", "4", "5", "6", "7", "8", "9"], 330 | title: null, 331 | translate: ["yes", "no"], 332 | onclick: null, 333 | rel: ["stylesheet", "alternate", "author", "bookmark", "help", "license", "next", "nofollow", "noreferrer", "prefetch", "prev", "search", "tag"] 334 | }; 335 | function populate(obj) { 336 | for (var attr in globalAttrs) if (globalAttrs.hasOwnProperty(attr)) 337 | obj.attrs[attr] = globalAttrs[attr]; 338 | } 339 | 340 | populate(s); 341 | for (var tag in data) if (data.hasOwnProperty(tag) && data[tag] != s) 342 | populate(data[tag]); 343 | 344 | CodeMirror.htmlSchema = data; 345 | function htmlHint(cm, options) { 346 | var local = {schemaInfo: data}; 347 | if (options) for (var opt in options) local[opt] = options[opt]; 348 | return CodeMirror.hint.xml(cm, local); 349 | } 350 | CodeMirror.registerHelper("hint", "html", htmlHint); 351 | }); 352 | -------------------------------------------------------------------------------- /js/libs/htmlmixed.js: -------------------------------------------------------------------------------- 1 | 2 | // CodeMirror, copyright (c) by Marijn Haverbeke and others 3 | // Distributed under an MIT license: https://codemirror.net/LICENSE 4 | 5 | (function(mod) { 6 | if (typeof exports == "object" && typeof module == "object") // CommonJS 7 | mod(require("../../lib/codemirror"), require("../xml/xml"), require("../javascript/javascript"), require("../css/css")); 8 | else if (typeof define == "function" && define.amd) // AMD 9 | define(["../../lib/codemirror", "../xml/xml", "../javascript/javascript", "../css/css"], mod); 10 | else // Plain browser env 11 | mod(CodeMirror); 12 | })(function(CodeMirror) { 13 | "use strict"; 14 | 15 | var defaultTags = { 16 | script: [ 17 | ["lang", /(javascript|babel)/i, "javascript"], 18 | ["type", /^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^module$|^$/i, "javascript"], 19 | ["type", /./, "text/plain"], 20 | [null, null, "javascript"] 21 | ], 22 | style: [ 23 | ["lang", /^css$/i, "css"], 24 | ["type", /^(text\/)?(x-)?(stylesheet|css)$/i, "css"], 25 | ["type", /./, "text/plain"], 26 | [null, null, "css"] 27 | ] 28 | }; 29 | 30 | function maybeBackup(stream, pat, style) { 31 | var cur = stream.current(), close = cur.search(pat); 32 | if (close > -1) { 33 | stream.backUp(cur.length - close); 34 | } else if (cur.match(/<\/?$/)) { 35 | stream.backUp(cur.length); 36 | if (!stream.match(pat, false)) stream.match(cur); 37 | } 38 | return style; 39 | } 40 | 41 | var attrRegexpCache = {}; 42 | function getAttrRegexp(attr) { 43 | var regexp = attrRegexpCache[attr]; 44 | if (regexp) return regexp; 45 | return attrRegexpCache[attr] = new RegExp("\\s+" + attr + "\\s*=\\s*('|\")?([^'\"]+)('|\")?\\s*"); 46 | } 47 | 48 | function getAttrValue(text, attr) { 49 | var match = text.match(getAttrRegexp(attr)) 50 | return match ? /^\s*(.*?)\s*$/.exec(match[2])[1] : "" 51 | } 52 | 53 | function getTagRegexp(tagName, anchored) { 54 | return new RegExp((anchored ? "^" : "") + "<\/\s*" + tagName + "\s*>", "i"); 55 | } 56 | 57 | function addTags(from, to) { 58 | for (var tag in from) { 59 | var dest = to[tag] || (to[tag] = []); 60 | var source = from[tag]; 61 | for (var i = source.length - 1; i >= 0; i--) 62 | dest.unshift(source[i]) 63 | } 64 | } 65 | 66 | function findMatchingMode(tagInfo, tagText) { 67 | for (var i = 0; i < tagInfo.length; i++) { 68 | var spec = tagInfo[i]; 69 | if (!spec[0] || spec[1].test(getAttrValue(tagText, spec[0]))) return spec[2]; 70 | } 71 | } 72 | 73 | CodeMirror.defineMode("htmlmixed", function (config, parserConfig) { 74 | var htmlMode = CodeMirror.getMode(config, { 75 | name: "xml", 76 | htmlMode: true, 77 | multilineTagIndentFactor: parserConfig.multilineTagIndentFactor, 78 | multilineTagIndentPastTag: parserConfig.multilineTagIndentPastTag, 79 | allowMissingTagName: parserConfig.allowMissingTagName, 80 | }); 81 | 82 | var tags = {}; 83 | var configTags = parserConfig && parserConfig.tags, configScript = parserConfig && parserConfig.scriptTypes; 84 | addTags(defaultTags, tags); 85 | if (configTags) addTags(configTags, tags); 86 | if (configScript) for (var i = configScript.length - 1; i >= 0; i--) 87 | tags.script.unshift(["type", configScript[i].matches, configScript[i].mode]) 88 | 89 | function html(stream, state) { 90 | var style = htmlMode.token(stream, state.htmlState), tag = /\btag\b/.test(style), tagName 91 | if (tag && !/[<>\s\/]/.test(stream.current()) && 92 | (tagName = state.htmlState.tagName && state.htmlState.tagName.toLowerCase()) && 93 | tags.hasOwnProperty(tagName)) { 94 | state.inTag = tagName + " " 95 | } else if (state.inTag && tag && />$/.test(stream.current())) { 96 | var inTag = /^([\S]+) (.*)/.exec(state.inTag) 97 | state.inTag = null 98 | var modeSpec = stream.current() == ">" && findMatchingMode(tags[inTag[1]], inTag[2]) 99 | var mode = CodeMirror.getMode(config, modeSpec) 100 | var endTagA = getTagRegexp(inTag[1], true), endTag = getTagRegexp(inTag[1], false); 101 | state.token = function (stream, state) { 102 | if (stream.match(endTagA, false)) { 103 | state.token = html; 104 | state.localState = state.localMode = null; 105 | return null; 106 | } 107 | return maybeBackup(stream, endTag, state.localMode.token(stream, state.localState)); 108 | }; 109 | state.localMode = mode; 110 | state.localState = CodeMirror.startState(mode, htmlMode.indent(state.htmlState, "", "")); 111 | } else if (state.inTag) { 112 | state.inTag += stream.current() 113 | if (stream.eol()) state.inTag += " " 114 | } 115 | return style; 116 | }; 117 | 118 | return { 119 | startState: function () { 120 | var state = CodeMirror.startState(htmlMode); 121 | return {token: html, inTag: null, localMode: null, localState: null, htmlState: state}; 122 | }, 123 | 124 | copyState: function (state) { 125 | var local; 126 | if (state.localState) { 127 | local = CodeMirror.copyState(state.localMode, state.localState); 128 | } 129 | return {token: state.token, inTag: state.inTag, 130 | localMode: state.localMode, localState: local, 131 | htmlState: CodeMirror.copyState(htmlMode, state.htmlState)}; 132 | }, 133 | 134 | token: function (stream, state) { 135 | return state.token(stream, state); 136 | }, 137 | 138 | indent: function (state, textAfter, line) { 139 | if (!state.localMode || /^\s*<\//.test(textAfter)) 140 | return htmlMode.indent(state.htmlState, textAfter, line); 141 | else if (state.localMode.indent) 142 | return state.localMode.indent(state.localState, textAfter, line); 143 | else 144 | return CodeMirror.Pass; 145 | }, 146 | 147 | innerMode: function (state) { 148 | return {state: state.localState || state.htmlState, mode: state.localMode || htmlMode}; 149 | } 150 | }; 151 | }, "xml", "javascript", "css"); 152 | 153 | CodeMirror.defineMIME("text/html", "htmlmixed"); 154 | }); -------------------------------------------------------------------------------- /js/libs/index.css: -------------------------------------------------------------------------------- 1 | body{ 2 | height: 100vh; 3 | } 4 | .gutter{ 5 | height: 100%; 6 | background: rgb(181, 187, 194); 7 | cursor: e-resize; 8 | } 9 | .navbar{ 10 | border-radius:0 !important 11 | } 12 | .navbar{ 13 | margin : 0 !important; 14 | } 15 | .navbar-inverse .navbar-nav>li>a{ 16 | color: white; 17 | } 18 | a:hover{ 19 | border-color: #337ab7; 20 | } 21 | .navbar-nav>li>.dropdown-menu{ 22 | background-color: black; 23 | } 24 | .dropdown-menu>li>a { 25 | color: white; 26 | } 27 | .editor{ 28 | width: 100%; 29 | height: 97%; 30 | display: flex; 31 | justify-items: center; 32 | align-items: center; 33 | background: rgb(41, 40, 40); 34 | } 35 | .code{ 36 | width: 100%; 37 | height: 100%; 38 | padding: 30px; 39 | border: 1px solid; 40 | } 41 | .editor .code iframe{ 42 | width: 100%; 43 | height: 100%; 44 | border: none; 45 | outline: none; 46 | background: white; 47 | 48 | } 49 | -------------------------------------------------------------------------------- /js/libs/monokai.min.css: -------------------------------------------------------------------------------- 1 | .cm-s-monokai.CodeMirror { 2 | background: #272822; 3 | color: #f8f8f2 4 | } 5 | 6 | .cm-s-monokai div.CodeMirror-selected { 7 | background: #49483e 8 | } 9 | 10 | .cm-s-monokai .CodeMirror-line::selection, .cm-s-monokai .CodeMirror-line>span::selection, .cm-s-monokai .CodeMirror-line>span>span::selection { 11 | background: rgba(73, 72, 62, .99) 12 | } 13 | 14 | .cm-s-monokai .CodeMirror-line::-moz-selection, .cm-s-monokai .CodeMirror-line>span::-moz-selection, .cm-s-monokai .CodeMirror-line>span>span::-moz-selection { 15 | background: rgba(73, 72, 62, .99) 16 | } 17 | 18 | .cm-s-monokai .CodeMirror-gutters { 19 | background: #272822; 20 | border-right: 0 21 | } 22 | 23 | .cm-s-monokai .CodeMirror-guttermarker { 24 | color: #fff 25 | } 26 | 27 | .cm-s-monokai .CodeMirror-guttermarker-subtle { 28 | color: #d0d0d0 29 | } 30 | 31 | .cm-s-monokai .CodeMirror-linenumber { 32 | color: #d0d0d0 33 | } 34 | 35 | .cm-s-monokai .CodeMirror-cursor { 36 | border-left: 1px solid #f8f8f0 37 | } 38 | 39 | .cm-s-monokai span.cm-comment { 40 | color: #75715e 41 | } 42 | 43 | .cm-s-monokai span.cm-atom { 44 | color: #ae81ff 45 | } 46 | 47 | .cm-s-monokai span.cm-number { 48 | color: #ae81ff 49 | } 50 | 51 | .cm-s-monokai span.cm-comment.cm-attribute { 52 | color: #97b757 53 | } 54 | 55 | .cm-s-monokai span.cm-comment.cm-def { 56 | color: #bc9262 57 | } 58 | 59 | .cm-s-monokai span.cm-comment.cm-tag { 60 | color: #bc6283 61 | } 62 | 63 | .cm-s-monokai span.cm-comment.cm-type { 64 | color: #5998a6 65 | } 66 | 67 | .cm-s-monokai span.cm-attribute, .cm-s-monokai span.cm-property { 68 | color: #a6e22e 69 | } 70 | 71 | .cm-s-monokai span.cm-keyword { 72 | color: #f92672 73 | } 74 | 75 | .cm-s-monokai span.cm-builtin { 76 | color: #66d9ef 77 | } 78 | 79 | .cm-s-monokai span.cm-string { 80 | color: #e6db74 81 | } 82 | 83 | .cm-s-monokai span.cm-variable { 84 | color: #f8f8f2 85 | } 86 | 87 | .cm-s-monokai span.cm-variable-2 { 88 | color: #9effff 89 | } 90 | 91 | .cm-s-monokai span.cm-type, .cm-s-monokai span.cm-variable-3 { 92 | color: #66d9ef 93 | } 94 | 95 | .cm-s-monokai span.cm-def { 96 | color: #fd971f 97 | } 98 | 99 | .cm-s-monokai span.cm-bracket { 100 | color: #f8f8f2 101 | } 102 | 103 | .cm-s-monokai span.cm-tag { 104 | color: #f92672 105 | } 106 | 107 | .cm-s-monokai span.cm-header { 108 | color: #ae81ff 109 | } 110 | 111 | .cm-s-monokai span.cm-link { 112 | color: #ae81ff 113 | } 114 | 115 | .cm-s-monokai span.cm-error { 116 | background: #f92672; 117 | color: #f8f8f0 118 | } 119 | 120 | .cm-s-monokai span { 121 | color: #9effff; 122 | } 123 | 124 | .cm-s-monokai .CodeMirror-activeline-background { 125 | background: #373831 126 | } 127 | 128 | .cm-s-monokai .CodeMirror-matchingbracket { 129 | text-decoration: underline; 130 | color: #fff !important 131 | } 132 | 133 | /*# sourceMappingURL=monokai.min.css.map */ -------------------------------------------------------------------------------- /js/libs/show-hint.css: -------------------------------------------------------------------------------- 1 | .CodeMirror-hints { 2 | position: absolute; 3 | z-index: 10; 4 | overflow: hidden; 5 | list-style: none; 6 | 7 | margin: 0; 8 | padding: 2px; 9 | 10 | -webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2); 11 | -moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2); 12 | box-shadow: 2px 3px 5px rgba(0,0,0,.2); 13 | border-radius: 3px; 14 | border: 1px solid silver; 15 | 16 | background: white; 17 | font-size: 90%; 18 | font-family: monospace; 19 | 20 | max-height: 20em; 21 | overflow-y: auto; 22 | } 23 | 24 | .CodeMirror-hint { 25 | margin: 0; 26 | padding: 0 4px; 27 | border-radius: 2px; 28 | white-space: pre; 29 | color: black; 30 | cursor: pointer; 31 | } 32 | 33 | li.CodeMirror-hint-active { 34 | background: #08f; 35 | color: white; 36 | } 37 | -------------------------------------------------------------------------------- /js/libs/show-hint.js: -------------------------------------------------------------------------------- 1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 | // Distributed under an MIT license: https://codemirror.net/LICENSE 3 | 4 | // declare global: DOMRect 5 | 6 | (function(mod) { 7 | if (typeof exports == "object" && typeof module == "object") // CommonJS 8 | mod(require("../../lib/codemirror")); 9 | else if (typeof define == "function" && define.amd) // AMD 10 | define(["../../lib/codemirror"], mod); 11 | else // Plain browser env 12 | mod(CodeMirror); 13 | })(function(CodeMirror) { 14 | "use strict"; 15 | 16 | var HINT_ELEMENT_CLASS = "CodeMirror-hint"; 17 | var ACTIVE_HINT_ELEMENT_CLASS = "CodeMirror-hint-active"; 18 | 19 | // This is the old interface, kept around for now to stay 20 | // backwards-compatible. 21 | CodeMirror.showHint = function(cm, getHints, options) { 22 | if (!getHints) return cm.showHint(options); 23 | if (options && options.async) getHints.async = true; 24 | var newOpts = {hint: getHints}; 25 | if (options) for (var prop in options) newOpts[prop] = options[prop]; 26 | return cm.showHint(newOpts); 27 | }; 28 | 29 | CodeMirror.defineExtension("showHint", function(options) { 30 | options = parseOptions(this, this.getCursor("start"), options); 31 | var selections = this.listSelections() 32 | if (selections.length > 1) return; 33 | // By default, don't allow completion when something is selected. 34 | // A hint function can have a `supportsSelection` property to 35 | // indicate that it can handle selections. 36 | if (this.somethingSelected()) { 37 | if (!options.hint.supportsSelection) return; 38 | // Don't try with cross-line selections 39 | for (var i = 0; i < selections.length; i++) 40 | if (selections[i].head.line != selections[i].anchor.line) return; 41 | } 42 | 43 | if (this.state.completionActive) this.state.completionActive.close(); 44 | var completion = this.state.completionActive = new Completion(this, options); 45 | if (!completion.options.hint) return; 46 | 47 | CodeMirror.signal(this, "startCompletion", this); 48 | completion.update(true); 49 | }); 50 | 51 | CodeMirror.defineExtension("closeHint", function() { 52 | if (this.state.completionActive) this.state.completionActive.close() 53 | }) 54 | 55 | function Completion(cm, options) { 56 | this.cm = cm; 57 | this.options = options; 58 | this.widget = null; 59 | this.debounce = 0; 60 | this.tick = 0; 61 | this.startPos = this.cm.getCursor("start"); 62 | this.startLen = this.cm.getLine(this.startPos.line).length - this.cm.getSelection().length; 63 | 64 | if (this.options.updateOnCursorActivity) { 65 | var self = this; 66 | cm.on("cursorActivity", this.activityFunc = function() { self.cursorActivity(); }); 67 | } 68 | } 69 | 70 | var requestAnimationFrame = window.requestAnimationFrame || function(fn) { 71 | return setTimeout(fn, 1000/60); 72 | }; 73 | var cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout; 74 | 75 | Completion.prototype = { 76 | close: function() { 77 | if (!this.active()) return; 78 | this.cm.state.completionActive = null; 79 | this.tick = null; 80 | if (this.options.updateOnCursorActivity) { 81 | this.cm.off("cursorActivity", this.activityFunc); 82 | } 83 | 84 | if (this.widget && this.data) CodeMirror.signal(this.data, "close"); 85 | if (this.widget) this.widget.close(); 86 | CodeMirror.signal(this.cm, "endCompletion", this.cm); 87 | }, 88 | 89 | active: function() { 90 | return this.cm.state.completionActive == this; 91 | }, 92 | 93 | pick: function(data, i) { 94 | var completion = data.list[i], self = this; 95 | this.cm.operation(function() { 96 | if (completion.hint) 97 | completion.hint(self.cm, data, completion); 98 | else 99 | self.cm.replaceRange(getText(completion), completion.from || data.from, 100 | completion.to || data.to, "complete"); 101 | CodeMirror.signal(data, "pick", completion); 102 | self.cm.scrollIntoView(); 103 | }); 104 | if (this.options.closeOnPick) { 105 | this.close(); 106 | } 107 | }, 108 | 109 | cursorActivity: function() { 110 | if (this.debounce) { 111 | cancelAnimationFrame(this.debounce); 112 | this.debounce = 0; 113 | } 114 | 115 | var identStart = this.startPos; 116 | if(this.data) { 117 | identStart = this.data.from; 118 | } 119 | 120 | var pos = this.cm.getCursor(), line = this.cm.getLine(pos.line); 121 | if (pos.line != this.startPos.line || line.length - pos.ch != this.startLen - this.startPos.ch || 122 | pos.ch < identStart.ch || this.cm.somethingSelected() || 123 | (!pos.ch || this.options.closeCharacters.test(line.charAt(pos.ch - 1)))) { 124 | this.close(); 125 | } else { 126 | var self = this; 127 | this.debounce = requestAnimationFrame(function() {self.update();}); 128 | if (this.widget) this.widget.disable(); 129 | } 130 | }, 131 | 132 | update: function(first) { 133 | if (this.tick == null) return 134 | var self = this, myTick = ++this.tick 135 | fetchHints(this.options.hint, this.cm, this.options, function(data) { 136 | if (self.tick == myTick) self.finishUpdate(data, first) 137 | }) 138 | }, 139 | 140 | finishUpdate: function(data, first) { 141 | if (this.data) CodeMirror.signal(this.data, "update"); 142 | 143 | var picked = (this.widget && this.widget.picked) || (first && this.options.completeSingle); 144 | if (this.widget) this.widget.close(); 145 | 146 | this.data = data; 147 | 148 | if (data && data.list.length) { 149 | if (picked && data.list.length == 1) { 150 | this.pick(data, 0); 151 | } else { 152 | this.widget = new Widget(this, data); 153 | CodeMirror.signal(data, "shown"); 154 | } 155 | } 156 | } 157 | }; 158 | 159 | function parseOptions(cm, pos, options) { 160 | var editor = cm.options.hintOptions; 161 | var out = {}; 162 | for (var prop in defaultOptions) out[prop] = defaultOptions[prop]; 163 | if (editor) for (var prop in editor) 164 | if (editor[prop] !== undefined) out[prop] = editor[prop]; 165 | if (options) for (var prop in options) 166 | if (options[prop] !== undefined) out[prop] = options[prop]; 167 | if (out.hint.resolve) out.hint = out.hint.resolve(cm, pos) 168 | return out; 169 | } 170 | 171 | function getText(completion) { 172 | if (typeof completion == "string") return completion; 173 | else return completion.text; 174 | } 175 | 176 | function buildKeyMap(completion, handle) { 177 | var baseMap = { 178 | Up: function() {handle.moveFocus(-1);}, 179 | Down: function() {handle.moveFocus(1);}, 180 | PageUp: function() {handle.moveFocus(-handle.menuSize() + 1, true);}, 181 | PageDown: function() {handle.moveFocus(handle.menuSize() - 1, true);}, 182 | Home: function() {handle.setFocus(0);}, 183 | End: function() {handle.setFocus(handle.length - 1);}, 184 | Enter: handle.pick, 185 | Tab: handle.pick, 186 | Esc: handle.close 187 | }; 188 | 189 | var mac = /Mac/.test(navigator.platform); 190 | 191 | if (mac) { 192 | baseMap["Ctrl-P"] = function() {handle.moveFocus(-1);}; 193 | baseMap["Ctrl-N"] = function() {handle.moveFocus(1);}; 194 | } 195 | 196 | var custom = completion.options.customKeys; 197 | var ourMap = custom ? {} : baseMap; 198 | function addBinding(key, val) { 199 | var bound; 200 | if (typeof val != "string") 201 | bound = function(cm) { return val(cm, handle); }; 202 | // This mechanism is deprecated 203 | else if (baseMap.hasOwnProperty(val)) 204 | bound = baseMap[val]; 205 | else 206 | bound = val; 207 | ourMap[key] = bound; 208 | } 209 | if (custom) 210 | for (var key in custom) if (custom.hasOwnProperty(key)) 211 | addBinding(key, custom[key]); 212 | var extra = completion.options.extraKeys; 213 | if (extra) 214 | for (var key in extra) if (extra.hasOwnProperty(key)) 215 | addBinding(key, extra[key]); 216 | return ourMap; 217 | } 218 | 219 | function getHintElement(hintsElement, el) { 220 | while (el && el != hintsElement) { 221 | if (el.nodeName.toUpperCase() === "LI" && el.parentNode == hintsElement) return el; 222 | el = el.parentNode; 223 | } 224 | } 225 | 226 | function Widget(completion, data) { 227 | this.id = "cm-complete-" + Math.floor(Math.random(1e6)) 228 | this.completion = completion; 229 | this.data = data; 230 | this.picked = false; 231 | var widget = this, cm = completion.cm; 232 | var ownerDocument = cm.getInputField().ownerDocument; 233 | var parentWindow = ownerDocument.defaultView || ownerDocument.parentWindow; 234 | 235 | var hints = this.hints = ownerDocument.createElement("ul"); 236 | hints.setAttribute("role", "listbox") 237 | hints.setAttribute("aria-expanded", "true") 238 | hints.id = this.id 239 | var theme = completion.cm.options.theme; 240 | hints.className = "CodeMirror-hints " + theme; 241 | this.selectedHint = data.selectedHint || 0; 242 | 243 | var completions = data.list; 244 | for (var i = 0; i < completions.length; ++i) { 245 | var elt = hints.appendChild(ownerDocument.createElement("li")), cur = completions[i]; 246 | var className = HINT_ELEMENT_CLASS + (i != this.selectedHint ? "" : " " + ACTIVE_HINT_ELEMENT_CLASS); 247 | if (cur.className != null) className = cur.className + " " + className; 248 | elt.className = className; 249 | if (i == this.selectedHint) elt.setAttribute("aria-selected", "true") 250 | elt.id = this.id + "-" + i 251 | elt.setAttribute("role", "option") 252 | if (cur.render) cur.render(elt, data, cur); 253 | else elt.appendChild(ownerDocument.createTextNode(cur.displayText || getText(cur))); 254 | elt.hintId = i; 255 | } 256 | 257 | var container = completion.options.container || ownerDocument.body; 258 | var pos = cm.cursorCoords(completion.options.alignWithWord ? data.from : null); 259 | var left = pos.left, top = pos.bottom, below = true; 260 | var offsetLeft = 0, offsetTop = 0; 261 | if (container !== ownerDocument.body) { 262 | // We offset the cursor position because left and top are relative to the offsetParent's top left corner. 263 | var isContainerPositioned = ['absolute', 'relative', 'fixed'].indexOf(parentWindow.getComputedStyle(container).position) !== -1; 264 | var offsetParent = isContainerPositioned ? container : container.offsetParent; 265 | var offsetParentPosition = offsetParent.getBoundingClientRect(); 266 | var bodyPosition = ownerDocument.body.getBoundingClientRect(); 267 | offsetLeft = (offsetParentPosition.left - bodyPosition.left - offsetParent.scrollLeft); 268 | offsetTop = (offsetParentPosition.top - bodyPosition.top - offsetParent.scrollTop); 269 | } 270 | hints.style.left = (left - offsetLeft) + "px"; 271 | hints.style.top = (top - offsetTop) + "px"; 272 | 273 | // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor. 274 | var winW = parentWindow.innerWidth || Math.max(ownerDocument.body.offsetWidth, ownerDocument.documentElement.offsetWidth); 275 | var winH = parentWindow.innerHeight || Math.max(ownerDocument.body.offsetHeight, ownerDocument.documentElement.offsetHeight); 276 | container.appendChild(hints); 277 | cm.getInputField().setAttribute("aria-autocomplete", "list") 278 | cm.getInputField().setAttribute("aria-owns", this.id) 279 | cm.getInputField().setAttribute("aria-activedescendant", this.id + "-" + this.selectedHint) 280 | 281 | var box = completion.options.moveOnOverlap ? hints.getBoundingClientRect() : new DOMRect(); 282 | var scrolls = completion.options.paddingForScrollbar ? hints.scrollHeight > hints.clientHeight + 1 : false; 283 | 284 | // Compute in the timeout to avoid reflow on init 285 | var startScroll; 286 | setTimeout(function() { startScroll = cm.getScrollInfo(); }); 287 | 288 | var overlapY = box.bottom - winH; 289 | if (overlapY > 0) { 290 | var height = box.bottom - box.top, curTop = pos.top - (pos.bottom - box.top); 291 | if (curTop - height > 0) { // Fits above cursor 292 | hints.style.top = (top = pos.top - height - offsetTop) + "px"; 293 | below = false; 294 | } else if (height > winH) { 295 | hints.style.height = (winH - 5) + "px"; 296 | hints.style.top = (top = pos.bottom - box.top - offsetTop) + "px"; 297 | var cursor = cm.getCursor(); 298 | if (data.from.ch != cursor.ch) { 299 | pos = cm.cursorCoords(cursor); 300 | hints.style.left = (left = pos.left - offsetLeft) + "px"; 301 | box = hints.getBoundingClientRect(); 302 | } 303 | } 304 | } 305 | var overlapX = box.right - winW; 306 | if (scrolls) overlapX += cm.display.nativeBarWidth; 307 | if (overlapX > 0) { 308 | if (box.right - box.left > winW) { 309 | hints.style.width = (winW - 5) + "px"; 310 | overlapX -= (box.right - box.left) - winW; 311 | } 312 | hints.style.left = (left = pos.left - overlapX - offsetLeft) + "px"; 313 | } 314 | if (scrolls) for (var node = hints.firstChild; node; node = node.nextSibling) 315 | node.style.paddingRight = cm.display.nativeBarWidth + "px" 316 | 317 | cm.addKeyMap(this.keyMap = buildKeyMap(completion, { 318 | moveFocus: function(n, avoidWrap) { widget.changeActive(widget.selectedHint + n, avoidWrap); }, 319 | setFocus: function(n) { widget.changeActive(n); }, 320 | menuSize: function() { return widget.screenAmount(); }, 321 | length: completions.length, 322 | close: function() { completion.close(); }, 323 | pick: function() { widget.pick(); }, 324 | data: data 325 | })); 326 | 327 | if (completion.options.closeOnUnfocus) { 328 | var closingOnBlur; 329 | cm.on("blur", this.onBlur = function() { closingOnBlur = setTimeout(function() { completion.close(); }, 100); }); 330 | cm.on("focus", this.onFocus = function() { clearTimeout(closingOnBlur); }); 331 | } 332 | 333 | cm.on("scroll", this.onScroll = function() { 334 | var curScroll = cm.getScrollInfo(), editor = cm.getWrapperElement().getBoundingClientRect(); 335 | if (!startScroll) startScroll = cm.getScrollInfo(); 336 | var newTop = top + startScroll.top - curScroll.top; 337 | var point = newTop - (parentWindow.pageYOffset || (ownerDocument.documentElement || ownerDocument.body).scrollTop); 338 | if (!below) point += hints.offsetHeight; 339 | if (point <= editor.top || point >= editor.bottom) return completion.close(); 340 | hints.style.top = newTop + "px"; 341 | hints.style.left = (left + startScroll.left - curScroll.left) + "px"; 342 | }); 343 | 344 | CodeMirror.on(hints, "dblclick", function(e) { 345 | var t = getHintElement(hints, e.target || e.srcElement); 346 | if (t && t.hintId != null) {widget.changeActive(t.hintId); widget.pick();} 347 | }); 348 | 349 | CodeMirror.on(hints, "click", function(e) { 350 | var t = getHintElement(hints, e.target || e.srcElement); 351 | if (t && t.hintId != null) { 352 | widget.changeActive(t.hintId); 353 | if (completion.options.completeOnSingleClick) widget.pick(); 354 | } 355 | }); 356 | 357 | CodeMirror.on(hints, "mousedown", function() { 358 | setTimeout(function(){cm.focus();}, 20); 359 | }); 360 | 361 | // The first hint doesn't need to be scrolled to on init 362 | var selectedHintRange = this.getSelectedHintRange(); 363 | if (selectedHintRange.from !== 0 || selectedHintRange.to !== 0) { 364 | this.scrollToActive(); 365 | } 366 | 367 | CodeMirror.signal(data, "select", completions[this.selectedHint], hints.childNodes[this.selectedHint]); 368 | return true; 369 | } 370 | 371 | Widget.prototype = { 372 | close: function() { 373 | if (this.completion.widget != this) return; 374 | this.completion.widget = null; 375 | if (this.hints.parentNode) this.hints.parentNode.removeChild(this.hints); 376 | this.completion.cm.removeKeyMap(this.keyMap); 377 | var input = this.completion.cm.getInputField() 378 | input.removeAttribute("aria-activedescendant") 379 | input.removeAttribute("aria-owns") 380 | 381 | var cm = this.completion.cm; 382 | if (this.completion.options.closeOnUnfocus) { 383 | cm.off("blur", this.onBlur); 384 | cm.off("focus", this.onFocus); 385 | } 386 | cm.off("scroll", this.onScroll); 387 | }, 388 | 389 | disable: function() { 390 | this.completion.cm.removeKeyMap(this.keyMap); 391 | var widget = this; 392 | this.keyMap = {Enter: function() { widget.picked = true; }}; 393 | this.completion.cm.addKeyMap(this.keyMap); 394 | }, 395 | 396 | pick: function() { 397 | this.completion.pick(this.data, this.selectedHint); 398 | }, 399 | 400 | changeActive: function(i, avoidWrap) { 401 | if (i >= this.data.list.length) 402 | i = avoidWrap ? this.data.list.length - 1 : 0; 403 | else if (i < 0) 404 | i = avoidWrap ? 0 : this.data.list.length - 1; 405 | if (this.selectedHint == i) return; 406 | var node = this.hints.childNodes[this.selectedHint]; 407 | if (node) { 408 | node.className = node.className.replace(" " + ACTIVE_HINT_ELEMENT_CLASS, ""); 409 | node.removeAttribute("aria-selected") 410 | } 411 | node = this.hints.childNodes[this.selectedHint = i]; 412 | node.className += " " + ACTIVE_HINT_ELEMENT_CLASS; 413 | node.setAttribute("aria-selected", "true") 414 | this.completion.cm.getInputField().setAttribute("aria-activedescendant", node.id) 415 | this.scrollToActive() 416 | CodeMirror.signal(this.data, "select", this.data.list[this.selectedHint], node); 417 | }, 418 | 419 | scrollToActive: function() { 420 | var selectedHintRange = this.getSelectedHintRange(); 421 | var node1 = this.hints.childNodes[selectedHintRange.from]; 422 | var node2 = this.hints.childNodes[selectedHintRange.to]; 423 | var firstNode = this.hints.firstChild; 424 | if (node1.offsetTop < this.hints.scrollTop) 425 | this.hints.scrollTop = node1.offsetTop - firstNode.offsetTop; 426 | else if (node2.offsetTop + node2.offsetHeight > this.hints.scrollTop + this.hints.clientHeight) 427 | this.hints.scrollTop = node2.offsetTop + node2.offsetHeight - this.hints.clientHeight + firstNode.offsetTop; 428 | }, 429 | 430 | screenAmount: function() { 431 | return Math.floor(this.hints.clientHeight / this.hints.firstChild.offsetHeight) || 1; 432 | }, 433 | 434 | getSelectedHintRange: function() { 435 | var margin = this.completion.options.scrollMargin || 0; 436 | return { 437 | from: Math.max(0, this.selectedHint - margin), 438 | to: Math.min(this.data.list.length - 1, this.selectedHint + margin), 439 | }; 440 | } 441 | }; 442 | 443 | function applicableHelpers(cm, helpers) { 444 | if (!cm.somethingSelected()) return helpers 445 | var result = [] 446 | for (var i = 0; i < helpers.length; i++) 447 | if (helpers[i].supportsSelection) result.push(helpers[i]) 448 | return result 449 | } 450 | 451 | function fetchHints(hint, cm, options, callback) { 452 | if (hint.async) { 453 | hint(cm, callback, options) 454 | } else { 455 | var result = hint(cm, options) 456 | if (result && result.then) result.then(callback) 457 | else callback(result) 458 | } 459 | } 460 | 461 | function resolveAutoHints(cm, pos) { 462 | var helpers = cm.getHelpers(pos, "hint"), words 463 | if (helpers.length) { 464 | var resolved = function(cm, callback, options) { 465 | var app = applicableHelpers(cm, helpers); 466 | function run(i) { 467 | if (i == app.length) return callback(null) 468 | fetchHints(app[i], cm, options, function(result) { 469 | if (result && result.list.length > 0) callback(result) 470 | else run(i + 1) 471 | }) 472 | } 473 | run(0) 474 | } 475 | resolved.async = true 476 | resolved.supportsSelection = true 477 | return resolved 478 | } else if (words = cm.getHelper(cm.getCursor(), "hintWords")) { 479 | return function(cm) { return CodeMirror.hint.fromList(cm, {words: words}) } 480 | } else if (CodeMirror.hint.anyword) { 481 | return function(cm, options) { return CodeMirror.hint.anyword(cm, options) } 482 | } else { 483 | return function() {} 484 | } 485 | } 486 | 487 | CodeMirror.registerHelper("hint", "auto", { 488 | resolve: resolveAutoHints 489 | }); 490 | 491 | CodeMirror.registerHelper("hint", "fromList", function(cm, options) { 492 | var cur = cm.getCursor(), token = cm.getTokenAt(cur) 493 | var term, from = CodeMirror.Pos(cur.line, token.start), to = cur 494 | if (token.start < cur.ch && /\w/.test(token.string.charAt(cur.ch - token.start - 1))) { 495 | term = token.string.substr(0, cur.ch - token.start) 496 | } else { 497 | term = "" 498 | from = cur 499 | } 500 | var found = []; 501 | for (var i = 0; i < options.words.length; i++) { 502 | var word = options.words[i]; 503 | if (word.slice(0, term.length) == term) 504 | found.push(word); 505 | } 506 | 507 | if (found.length) return {list: found, from: from, to: to}; 508 | }); 509 | 510 | CodeMirror.commands.autocomplete = CodeMirror.showHint; 511 | 512 | var defaultOptions = { 513 | hint: CodeMirror.hint.auto, 514 | completeSingle: true, 515 | alignWithWord: true, 516 | closeCharacters: /[\s()\[\]{};:>,]/, 517 | closeOnPick: true, 518 | closeOnUnfocus: true, 519 | updateOnCursorActivity: true, 520 | completeOnSingleClick: true, 521 | container: null, 522 | customKeys: null, 523 | extraKeys: null, 524 | paddingForScrollbar: true, 525 | moveOnOverlap: true, 526 | }; 527 | 528 | CodeMirror.defineOption("hintOptions", null); 529 | }); 530 | -------------------------------------------------------------------------------- /js/libs/xml-hint.js: -------------------------------------------------------------------------------- 1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 | // Distributed under an MIT license: https://codemirror.net/LICENSE 3 | 4 | (function(mod) { 5 | if (typeof exports == "object" && typeof module == "object") // CommonJS 6 | mod(require("../../lib/codemirror")); 7 | else if (typeof define == "function" && define.amd) // AMD 8 | define(["../../lib/codemirror"], mod); 9 | else // Plain browser env 10 | mod(CodeMirror); 11 | })(function(CodeMirror) { 12 | "use strict"; 13 | 14 | var Pos = CodeMirror.Pos; 15 | 16 | function matches(hint, typed, matchInMiddle) { 17 | if (matchInMiddle) return hint.indexOf(typed) >= 0; 18 | else return hint.lastIndexOf(typed, 0) == 0; 19 | } 20 | 21 | function getHints(cm, options) { 22 | var tags = options && options.schemaInfo; 23 | var quote = (options && options.quoteChar) || '"'; 24 | var matchInMiddle = options && options.matchInMiddle; 25 | if (!tags) return; 26 | var cur = cm.getCursor(), token = cm.getTokenAt(cur); 27 | if (token.end > cur.ch) { 28 | token.end = cur.ch; 29 | token.string = token.string.slice(0, cur.ch - token.start); 30 | } 31 | var inner = CodeMirror.innerMode(cm.getMode(), token.state); 32 | if (!inner.mode.xmlCurrentTag) return 33 | var result = [], replaceToken = false, prefix; 34 | var tag = /\btag\b/.test(token.type) && !/>$/.test(token.string); 35 | var tagName = tag && /^\w/.test(token.string), tagStart; 36 | 37 | if (tagName) { 38 | var before = cm.getLine(cur.line).slice(Math.max(0, token.start - 2), token.start); 39 | var tagType = /<\/$/.test(before) ? "close" : /<$/.test(before) ? "open" : null; 40 | if (tagType) tagStart = token.start - (tagType == "close" ? 2 : 1); 41 | } else if (tag && token.string == "<") { 42 | tagType = "open"; 43 | } else if (tag && token.string == ""); 66 | } else { 67 | // Attribute completion 68 | var curTag = tagInfo && tags[tagInfo.name], attrs = curTag && curTag.attrs; 69 | var globalAttrs = tags["!attrs"]; 70 | if (!attrs && !globalAttrs) return; 71 | if (!attrs) { 72 | attrs = globalAttrs; 73 | } else if (globalAttrs) { // Combine tag-local and global attributes 74 | var set = {}; 75 | for (var nm in globalAttrs) if (globalAttrs.hasOwnProperty(nm)) set[nm] = globalAttrs[nm]; 76 | for (var nm in attrs) if (attrs.hasOwnProperty(nm)) set[nm] = attrs[nm]; 77 | attrs = set; 78 | } 79 | if (token.type == "string" || token.string == "=") { // A value 80 | var before = cm.getRange(Pos(cur.line, Math.max(0, cur.ch - 60)), 81 | Pos(cur.line, token.type == "string" ? token.start : token.end)); 82 | var atName = before.match(/([^\s\u00a0=<>\"\']+)=$/), atValues; 83 | if (!atName || !attrs.hasOwnProperty(atName[1]) || !(atValues = attrs[atName[1]])) return; 84 | if (typeof atValues == 'function') atValues = atValues.call(this, cm); // Functions can be used to supply values for autocomplete widget 85 | if (token.type == "string") { 86 | prefix = token.string; 87 | var n = 0; 88 | if (/['"]/.test(token.string.charAt(0))) { 89 | quote = token.string.charAt(0); 90 | prefix = token.string.slice(1); 91 | n++; 92 | } 93 | var len = token.string.length; 94 | if (/['"]/.test(token.string.charAt(len - 1))) { 95 | quote = token.string.charAt(len - 1); 96 | prefix = token.string.substr(n, len - 2); 97 | } 98 | if (n) { // an opening quote 99 | var line = cm.getLine(cur.line); 100 | if (line.length > token.end && line.charAt(token.end) == quote) token.end++; // include a closing quote 101 | } 102 | replaceToken = true; 103 | } 104 | var returnHintsFromAtValues = function(atValues) { 105 | if (atValues) 106 | for (var i = 0; i < atValues.length; ++i) if (!prefix || matches(atValues[i], prefix, matchInMiddle)) 107 | result.push(quote + atValues[i] + quote); 108 | return returnHints(); 109 | }; 110 | if (atValues && atValues.then) return atValues.then(returnHintsFromAtValues); 111 | return returnHintsFromAtValues(atValues); 112 | } else { // An attribute name 113 | if (token.type == "attribute") { 114 | prefix = token.string; 115 | replaceToken = true; 116 | } 117 | for (var attr in attrs) if (attrs.hasOwnProperty(attr) && (!prefix || matches(attr, prefix, matchInMiddle))) 118 | result.push(attr); 119 | } 120 | } 121 | function returnHints() { 122 | return { 123 | list: result, 124 | from: replaceToken ? Pos(cur.line, tagStart == null ? token.start : tagStart) : cur, 125 | to: replaceToken ? Pos(cur.line, token.end) : cur 126 | }; 127 | } 128 | return returnHints(); 129 | } 130 | 131 | CodeMirror.registerHelper("hint", "xml", getHints); 132 | }); 133 | -------------------------------------------------------------------------------- /js/libs/xml.js: -------------------------------------------------------------------------------- 1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 | // Distributed under an MIT license: https://codemirror.net/LICENSE 3 | 4 | (function (mod) { 5 | if (typeof exports == "object" && typeof module == "object") // CommonJS 6 | mod(require("../../lib/codemirror")); 7 | else if (typeof define == "function" && define.amd) // AMD 8 | define(["../../lib/codemirror"], mod); 9 | else // Plain browser env 10 | mod(CodeMirror); 11 | })(function (CodeMirror) { 12 | "use strict"; 13 | 14 | var htmlConfig = { 15 | autoSelfClosers: { 16 | 'area': true, 'base': true, 'br': true, 'col': true, 'command': true, 17 | 'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true, 18 | 'keygen': true, 'link': true, 'meta': true, 'param': true, 'source': true, 19 | 'track': true, 'wbr': true, 'menuitem': true 20 | }, 21 | implicitlyClosed: { 22 | 'dd': true, 'li': true, 'optgroup': true, 'option': true, 'p': true, 23 | 'rp': true, 'rt': true, 'tbody': true, 'td': true, 'tfoot': true, 24 | 'th': true, 'tr': true 25 | }, 26 | contextGrabbers: { 27 | 'dd': { 'dd': true, 'dt': true }, 28 | 'dt': { 'dd': true, 'dt': true }, 29 | 'li': { 'li': true }, 30 | 'option': { 'option': true, 'optgroup': true }, 31 | 'optgroup': { 'optgroup': true }, 32 | 'p': { 33 | 'address': true, 'article': true, 'aside': true, 'blockquote': true, 'dir': true, 34 | 'div': true, 'dl': true, 'fieldset': true, 'footer': true, 'form': true, 35 | 'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true, 36 | 'header': true, 'hgroup': true, 'hr': true, 'menu': true, 'nav': true, 'ol': true, 37 | 'p': true, 'pre': true, 'section': true, 'table': true, 'ul': true 38 | }, 39 | 'rp': { 'rp': true, 'rt': true }, 40 | 'rt': { 'rp': true, 'rt': true }, 41 | 'tbody': { 'tbody': true, 'tfoot': true }, 42 | 'td': { 'td': true, 'th': true }, 43 | 'tfoot': { 'tbody': true }, 44 | 'th': { 'td': true, 'th': true }, 45 | 'thead': { 'tbody': true, 'tfoot': true }, 46 | 'tr': { 'tr': true } 47 | }, 48 | doNotIndent: { "pre": true }, 49 | allowUnquoted: true, 50 | allowMissing: true, 51 | caseFold: true 52 | } 53 | 54 | var xmlConfig = { 55 | autoSelfClosers: {}, 56 | implicitlyClosed: {}, 57 | contextGrabbers: {}, 58 | doNotIndent: {}, 59 | allowUnquoted: false, 60 | allowMissing: false, 61 | allowMissingTagName: false, 62 | caseFold: false 63 | } 64 | 65 | CodeMirror.defineMode("xml", function (editorConf, config_) { 66 | var indentUnit = editorConf.indentUnit 67 | var config = {} 68 | var defaults = config_.htmlMode ? htmlConfig : xmlConfig 69 | for (var prop in defaults) config[prop] = defaults[prop] 70 | for (var prop in config_) config[prop] = config_[prop] 71 | 72 | // Return variables for tokenizers 73 | var type, setStyle; 74 | 75 | function inText(stream, state) { 76 | function chain(parser) { 77 | state.tokenize = parser; 78 | return parser(stream, state); 79 | } 80 | 81 | var ch = stream.next(); 82 | if (ch == "<") { 83 | if (stream.eat("!")) { 84 | if (stream.eat("[")) { 85 | if (stream.match("CDATA[")) return chain(inBlock("atom", "]]>")); 86 | else return null; 87 | } else if (stream.match("--")) { 88 | return chain(inBlock("comment", "-->")); 89 | } else if (stream.match("DOCTYPE", true, true)) { 90 | stream.eatWhile(/[\w\._\-]/); 91 | return chain(doctype(1)); 92 | } else { 93 | return null; 94 | } 95 | } else if (stream.eat("?")) { 96 | stream.eatWhile(/[\w\._\-]/); 97 | state.tokenize = inBlock("meta", "?>"); 98 | return "meta"; 99 | } else { 100 | type = stream.eat("/") ? "closeTag" : "openTag"; 101 | state.tokenize = inTag; 102 | return "tag bracket"; 103 | } 104 | } else if (ch == "&") { 105 | var ok; 106 | if (stream.eat("#")) { 107 | if (stream.eat("x")) { 108 | ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";"); 109 | } else { 110 | ok = stream.eatWhile(/[\d]/) && stream.eat(";"); 111 | } 112 | } else { 113 | ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(";"); 114 | } 115 | return ok ? "atom" : "error"; 116 | } else { 117 | stream.eatWhile(/[^&<]/); 118 | return null; 119 | } 120 | } 121 | inText.isInText = true; 122 | 123 | function inTag(stream, state) { 124 | var ch = stream.next(); 125 | if (ch == ">" || (ch == "/" && stream.eat(">"))) { 126 | state.tokenize = inText; 127 | type = ch == ">" ? "endTag" : "selfcloseTag"; 128 | return "tag bracket"; 129 | } else if (ch == "=") { 130 | type = "equals"; 131 | return null; 132 | } else if (ch == "<") { 133 | state.tokenize = inText; 134 | state.state = baseState; 135 | state.tagName = state.tagStart = null; 136 | var next = state.tokenize(stream, state); 137 | return next ? next + " tag error" : "tag error"; 138 | } else if (/[\'\"]/.test(ch)) { 139 | state.tokenize = inAttribute(ch); 140 | state.stringStartCol = stream.column(); 141 | return state.tokenize(stream, state); 142 | } else { 143 | stream.match(/^[^\s\u00a0=<>\"\']*[^\s\u00a0=<>\"\'\/]/); 144 | return "word"; 145 | } 146 | } 147 | 148 | function inAttribute(quote) { 149 | var closure = function (stream, state) { 150 | while (!stream.eol()) { 151 | if (stream.next() == quote) { 152 | state.tokenize = inTag; 153 | break; 154 | } 155 | } 156 | return "string"; 157 | }; 158 | closure.isInAttribute = true; 159 | return closure; 160 | } 161 | 162 | function inBlock(style, terminator) { 163 | return function (stream, state) { 164 | while (!stream.eol()) { 165 | if (stream.match(terminator)) { 166 | state.tokenize = inText; 167 | break; 168 | } 169 | stream.next(); 170 | } 171 | return style; 172 | } 173 | } 174 | 175 | function doctype(depth) { 176 | return function (stream, state) { 177 | var ch; 178 | while ((ch = stream.next()) != null) { 179 | if (ch == "<") { 180 | state.tokenize = doctype(depth + 1); 181 | return state.tokenize(stream, state); 182 | } else if (ch == ">") { 183 | if (depth == 1) { 184 | state.tokenize = inText; 185 | break; 186 | } else { 187 | state.tokenize = doctype(depth - 1); 188 | return state.tokenize(stream, state); 189 | } 190 | } 191 | } 192 | return "meta"; 193 | }; 194 | } 195 | 196 | function Context(state, tagName, startOfLine) { 197 | this.prev = state.context; 198 | this.tagName = tagName || ""; 199 | this.indent = state.indented; 200 | this.startOfLine = startOfLine; 201 | if (config.doNotIndent.hasOwnProperty(tagName) || (state.context && state.context.noIndent)) 202 | this.noIndent = true; 203 | } 204 | function popContext(state) { 205 | if (state.context) state.context = state.context.prev; 206 | } 207 | function maybePopContext(state, nextTagName) { 208 | var parentTagName; 209 | while (true) { 210 | if (!state.context) { 211 | return; 212 | } 213 | parentTagName = state.context.tagName; 214 | if (!config.contextGrabbers.hasOwnProperty(parentTagName) || 215 | !config.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) { 216 | return; 217 | } 218 | popContext(state); 219 | } 220 | } 221 | 222 | function baseState(type, stream, state) { 223 | if (type == "openTag") { 224 | state.tagStart = stream.column(); 225 | return tagNameState; 226 | } else if (type == "closeTag") { 227 | return closeTagNameState; 228 | } else { 229 | return baseState; 230 | } 231 | } 232 | function tagNameState(type, stream, state) { 233 | if (type == "word") { 234 | state.tagName = stream.current(); 235 | setStyle = "tag"; 236 | return attrState; 237 | } else if (config.allowMissingTagName && type == "endTag") { 238 | setStyle = "tag bracket"; 239 | return attrState(type, stream, state); 240 | } else { 241 | setStyle = "error"; 242 | return tagNameState; 243 | } 244 | } 245 | function closeTagNameState(type, stream, state) { 246 | if (type == "word") { 247 | var tagName = stream.current(); 248 | if (state.context && state.context.tagName != tagName && 249 | config.implicitlyClosed.hasOwnProperty(state.context.tagName)) 250 | popContext(state); 251 | if ((state.context && state.context.tagName == tagName) || config.matchClosing === false) { 252 | setStyle = "tag"; 253 | return closeState; 254 | } else { 255 | setStyle = "tag error"; 256 | return closeStateErr; 257 | } 258 | } else if (config.allowMissingTagName && type == "endTag") { 259 | setStyle = "tag bracket"; 260 | return closeState(type, stream, state); 261 | } else { 262 | setStyle = "error"; 263 | return closeStateErr; 264 | } 265 | } 266 | 267 | function closeState(type, _stream, state) { 268 | if (type != "endTag") { 269 | setStyle = "error"; 270 | return closeState; 271 | } 272 | popContext(state); 273 | return baseState; 274 | } 275 | function closeStateErr(type, stream, state) { 276 | setStyle = "error"; 277 | return closeState(type, stream, state); 278 | } 279 | 280 | function attrState(type, _stream, state) { 281 | if (type == "word") { 282 | setStyle = "attribute"; 283 | return attrEqState; 284 | } else if (type == "endTag" || type == "selfcloseTag") { 285 | var tagName = state.tagName, tagStart = state.tagStart; 286 | state.tagName = state.tagStart = null; 287 | if (type == "selfcloseTag" || 288 | config.autoSelfClosers.hasOwnProperty(tagName)) { 289 | maybePopContext(state, tagName); 290 | } else { 291 | maybePopContext(state, tagName); 292 | state.context = new Context(state, tagName, tagStart == state.indented); 293 | } 294 | return baseState; 295 | } 296 | setStyle = "error"; 297 | return attrState; 298 | } 299 | function attrEqState(type, stream, state) { 300 | if (type == "equals") return attrValueState; 301 | if (!config.allowMissing) setStyle = "error"; 302 | return attrState(type, stream, state); 303 | } 304 | function attrValueState(type, stream, state) { 305 | if (type == "string") return attrContinuedState; 306 | if (type == "word" && config.allowUnquoted) { setStyle = "string"; return attrState; } 307 | setStyle = "error"; 308 | return attrState(type, stream, state); 309 | } 310 | function attrContinuedState(type, stream, state) { 311 | if (type == "string") return attrContinuedState; 312 | return attrState(type, stream, state); 313 | } 314 | 315 | return { 316 | startState: function (baseIndent) { 317 | var state = { 318 | tokenize: inText, 319 | state: baseState, 320 | indented: baseIndent || 0, 321 | tagName: null, tagStart: null, 322 | context: null 323 | } 324 | if (baseIndent != null) state.baseIndent = baseIndent 325 | return state 326 | }, 327 | 328 | token: function (stream, state) { 329 | if (!state.tagName && stream.sol()) 330 | state.indented = stream.indentation(); 331 | 332 | if (stream.eatSpace()) return null; 333 | type = null; 334 | var style = state.tokenize(stream, state); 335 | if ((style || type) && style != "comment") { 336 | setStyle = null; 337 | state.state = state.state(type || style, stream, state); 338 | if (setStyle) 339 | style = setStyle == "error" ? style + " error" : setStyle; 340 | } 341 | return style; 342 | }, 343 | 344 | indent: function (state, textAfter, fullLine) { 345 | var context = state.context; 346 | // Indent multi-line strings (e.g. css). 347 | if (state.tokenize.isInAttribute) { 348 | if (state.tagStart == state.indented) 349 | return state.stringStartCol + 1; 350 | else 351 | return state.indented + indentUnit; 352 | } 353 | if (context && context.noIndent) return CodeMirror.Pass; 354 | if (state.tokenize != inTag && state.tokenize != inText) 355 | return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0; 356 | // Indent the starts of attribute names. 357 | if (state.tagName) { 358 | if (config.multilineTagIndentPastTag !== false) 359 | return state.tagStart + state.tagName.length + 2; 360 | else 361 | return state.tagStart + indentUnit * (config.multilineTagIndentFactor || 1); 362 | } 363 | if (config.alignCDATA && /$/, 392 | blockCommentStart: "", 394 | 395 | configuration: config.htmlMode ? "html" : "xml", 396 | helperType: config.htmlMode ? "html" : "xml", 397 | 398 | skipAttribute: function (state) { 399 | if (state.state == attrValueState) 400 | state.state = attrState 401 | }, 402 | 403 | xmlCurrentTag: function (state) { 404 | return state.tagName ? { name: state.tagName, close: state.type == "closeTag" } : null 405 | }, 406 | 407 | xmlCurrentContext: function (state) { 408 | var context = [] 409 | for (var cx = state.context; cx; cx = cx.prev) 410 | context.push(cx.tagName) 411 | return context.reverse() 412 | } 413 | }; 414 | }); 415 | 416 | CodeMirror.defineMIME("text/xml", "xml"); 417 | CodeMirror.defineMIME("application/xml", "xml"); 418 | if (!CodeMirror.mimeModes.hasOwnProperty("text/html")) 419 | CodeMirror.defineMIME("text/html", { name: "xml", htmlMode: true }); 420 | 421 | }); 422 | -------------------------------------------------------------------------------- /js/script.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * designr, A Google Chrome Extension for inspect CSS styles and save snapshots of web components and designs. 3 | * https://github.com/ANG13T/designr 4 | */ 5 | 6 | let startButton = document.getElementById("startButton"); 7 | let homePage = document.getElementById("home"); 8 | let mainPage = document.getElementById("main"); 9 | let paletteBackButton = document.getElementById("back-palette-button"); 10 | let viewPalettePage = document.getElementById("view-palette"); 11 | let paletteTableNone = document.getElementById("none-palette"); 12 | let paletteTable = document.getElementById("paletteTable"); 13 | let paletteNameInput = document.getElementById("paletteNameInput"); 14 | let paletteTitle = document.getElementById("palette-title"); 15 | let viewSettingsButton = document.getElementById("view-settings"); 16 | let paletteTableContent = document.getElementById('paletteTable').getElementsByTagName('tbody')[0]; 17 | 18 | const modal = document.getElementById("modal"); 19 | const overlay = document.getElementById("overlay"); 20 | const createPaletteBtn = document.getElementById("create-palette"); 21 | const createPaletteBtnModal = document.getElementById("create-palette-modal"); 22 | const closeModalBtn = document.getElementById("btn-close"); 23 | 24 | const editModal = document.getElementById("edit-modal"); 25 | const editCloseModalButton = document.getElementById("btn-close-edit"); 26 | const editPaletteTextInput = document.getElementById("paletteNameEditInput"); 27 | let editPaletteButton = document.getElementById("edit-palette-button"); 28 | let confirmEditPaletteButton = document.getElementById("edit-palette-modal"); 29 | const editOverlay = document.getElementById("edit-overlay"); 30 | 31 | const deleteModal = document.getElementById("delete-modal"); 32 | const openDeleteModalButton = document.getElementById("delete-palette-button"); 33 | const deleteModalConfirmButton = document.getElementById("delete-palette-modal"); 34 | const deleteCloseModalButton = document.getElementById("btn-close-delete"); 35 | const deleteOverlay = document.getElementById("delete-overlay"); 36 | 37 | let viewElementPage = document.getElementById("view-element"); 38 | let paletteTableElementNone = document.getElementById("none-palette-element"); 39 | let selectElementButton = document.getElementById("select-element-button"); 40 | let backElementButton = document.getElementById("back-element-button"); 41 | let editElementButton = document.getElementById("edit-element-button"); 42 | let deleteElementButton = document.getElementById("delete-element-button"); 43 | let paletteElementsTable = document.getElementById("paletteElementsTable"); 44 | let paletteElementsTableContainer = document.getElementById("elmentTableContainer"); 45 | let elementTitle = document.getElementById("element-title"); 46 | let elementTableContent = document.getElementById('paletteElementsTable').getElementsByTagName('tbody')[0]; 47 | 48 | const editElementModal = document.getElementById("edit-element-modal"); 49 | const editElementCloseModalButton = document.getElementById("btn-close-edit-element"); 50 | const editElementTextInput = document.getElementById("elementNameEditInput"); 51 | let confirmEditElementButton = document.getElementById("edit-element-modal-confirm"); 52 | const editElementOverlay = document.getElementById("edit-element-overlay"); 53 | 54 | const deleteElementModal = document.getElementById("delete-element-modal"); 55 | const openDeleteElementModalButton = document.getElementById("delete-element-button"); 56 | const deleteElementModalConfirmButton = document.getElementById("delete-element-button-confirm"); 57 | const deleteElementCloseModalButton = document.getElementById("btn-close-delete-element"); 58 | const deleteElementOverlay = document.getElementById("delete-element-overlay"); 59 | const saveElementClipboard = document.getElementById("save-element-styles"); 60 | 61 | const saveClipboardButton = document.getElementById("save-clipboard-button"); 62 | const saveCssButton = document.getElementById("save-css-button"); 63 | const cancelCssButton = document.getElementById("cancel-css-button"); 64 | const clipBoardIcon = document.getElementById("clipboard-icon"); 65 | const clipBoardIconPal = document.getElementById("clipboard-icon-pal"); 66 | 67 | const codeTemplateContainer = document.getElementById("code-template-container"); 68 | 69 | var cssEditor; 70 | 71 | let palettes = []; 72 | let selectedPalette = null; 73 | let selectedPaletteIndex = 0; 74 | let viewPalette = null; 75 | let viewPaletteIndex = null; 76 | 77 | let viewElement = null; 78 | let viewElementIndex = null; 79 | 80 | function setViewHome() { 81 | chrome.storage.sync.set({ "viewHome": "true" }, () => console.log("done")); 82 | } 83 | 84 | async function getViewHome() { 85 | await chrome.storage.sync.get(["viewHome"], function (result) { 86 | if (result && result["viewHome"] == "true") { 87 | mainPage.hidden = false; 88 | homePage.hidden = true; 89 | viewPalettePage.hidden = true; 90 | } 91 | }); 92 | } 93 | 94 | async function retreivePalettes() { 95 | paletteTableNone.hidden = false; 96 | chrome.storage.local.get({ palettes: [] }, function (result) { 97 | let resultPal = result.palettes; 98 | palettes = resultPal; 99 | 100 | if (resultPal.length > 0) { 101 | renderPalettes(resultPal); 102 | paletteTableNone.hidden = true; 103 | } else { 104 | paletteTable.hidden = true; 105 | } 106 | }); 107 | } 108 | 109 | function renderPalettes(selectedPal) { 110 | removePaletteRows(); 111 | if (selectedPal.length > 0) { 112 | paletteTableNone.hidden = true; 113 | } 114 | selectedPal.forEach((pa, index) => { 115 | let newRow = paletteTableContent.insertRow(index); 116 | newRow.innerHTML = ` 117 | 118 | ${pa.name} 119 | ${pa.createdDate} 120 | ${pa.elementsData.length} 121 | 122 | `; 123 | }); 124 | 125 | document.querySelectorAll(".paletteTableRowBody").forEach((tabBody) => { 126 | tabBody.addEventListener("click", (el) => { 127 | let index = Number(el.srcElement.classList[1].split('-')[1]); 128 | viewPalette = palettes[index]; 129 | viewPaletteIndex = index; 130 | paletteTitle.innerText = viewPalette.name; 131 | renderViewPalettePage(); 132 | closeEditModal(); 133 | closeDeleteModal(); 134 | }) 135 | }) 136 | } 137 | 138 | function renderViewPalettePage() { 139 | mainPage.hidden = true; 140 | viewPalettePage.hidden = false; 141 | paletteElementsTableContainer.hidden = true; 142 | renderElementsPalette(); 143 | saveCssButton.hidden = true; 144 | cancelCssButton.hidden = true; 145 | if(viewPalette.elementsData.length == 0) { 146 | saveElementClipboard.hidden = true; 147 | } else { 148 | saveElementClipboard.hidden = false; 149 | } 150 | } 151 | 152 | function renderElementsPalette() { 153 | removeElementRows(); 154 | if (viewPalette.elementsData && viewPalette.elementsData.length > 0) { 155 | paletteElementsTableContainer.hidden = false; 156 | paletteTableElementNone.hidden = true; 157 | } else { 158 | paletteElementsTableContainer.hidden = true; 159 | paletteTableElementNone.hidden = false; 160 | } 161 | 162 | viewPalette.elementsData.forEach((pa, index) => { 163 | let newRow = elementTableContent.insertRow(index); 164 | let elementTitleText = pa.title; 165 | if (elementTitleText.length > 46) { 166 | elementTitleText = elementTitleText.substring(0, 46).concat('...') 167 | } 168 | newRow.innerHTML = ` 169 | 170 | ${elementTitleText} 171 | 172 | `; 173 | }); 174 | 175 | document.querySelectorAll(".elementTableRowBody").forEach((tabBody) => { 176 | tabBody.addEventListener("click", (el) => { 177 | let index = Number(el.srcElement.classList[1].split('-')[1]); 178 | viewElement = viewPalette.elementsData[index]; 179 | viewElementIndex = index; 180 | let displayText = viewElement.title; 181 | if (displayText.length > 23) { 182 | displayText = displayText.substring(0, 23).concat('...') 183 | } 184 | elementTitle.innerText = displayText; 185 | viewElementPage.hidden = false; 186 | renderViewElementsPage(); 187 | closeEditModal(); 188 | closeDeleteModal(); 189 | 190 | initCodeMirror(); 191 | cssEditor = CodeMirror(document.querySelector(".editor .code .html-code"), { 192 | mode: "css", 193 | tabSize: 2, 194 | lineNumbers: true, 195 | enableCodeFormatting: false, 196 | value: viewElement.css, 197 | autoClearEmptyLines: true, 198 | }); 199 | 200 | cssEditor.on("change", function() { 201 | if(cssEditor.getValue() != viewElement.css) { 202 | saveClipboardButton.hidden = true; 203 | saveCssButton.hidden = false; 204 | cancelCssButton.hidden = false; 205 | } else { 206 | saveClipboardButton.hidden = false; 207 | saveCssButton.hidden = true; 208 | cancelCssButton.hidden = true; 209 | } 210 | }) 211 | 212 | }) 213 | }) 214 | } 215 | 216 | function renderViewElementsPage() { 217 | viewPalettePage.hidden = true; 218 | viewElementPage.hidden = false; 219 | } 220 | 221 | function setPalettes(selectedPal) { 222 | chrome.storage.local.set({ palettes: selectedPal }, function () { 223 | 224 | }) 225 | } 226 | 227 | 228 | function removePaletteRows() { 229 | while (paletteTableContent.lastElementChild) { 230 | paletteTableContent.removeChild(paletteTableContent.lastElementChild); 231 | } 232 | } 233 | 234 | function removeElementRows() { 235 | while (elementTableContent.lastElementChild) { 236 | elementTableContent.removeChild(elementTableContent.lastElementChild); 237 | } 238 | } 239 | 240 | function openEditModal() { 241 | editPaletteTextInput.value = viewPalette.name; 242 | editModal.classList.remove('hidden'); 243 | editOverlay.classList.remove('hidden'); 244 | } 245 | 246 | function openEditElementModal() { 247 | editElementTextInput.value = viewElement.title; 248 | editElementModal.classList.remove('hidden'); 249 | editElementOverlay.classList.remove('hidden'); 250 | } 251 | 252 | function openDeleteElementModal() { 253 | deleteElementModal.classList.remove('hidden'); 254 | deleteElementOverlay.classList.remove('hidden'); 255 | } 256 | 257 | function closeEditElementModal() { 258 | editElementModal.classList.add('hidden'); 259 | editElementOverlay.classList.add('hidden'); 260 | } 261 | 262 | function closeDeleteElementModal() { 263 | deleteElementModal.classList.add('hidden'); 264 | deleteElementOverlay.classList.add('hidden'); 265 | } 266 | 267 | const closeEditModal = function () { 268 | editModal.classList.add('hidden'); 269 | editOverlay.classList.add('hidden'); 270 | } 271 | 272 | function openDeleteModal() { 273 | deleteModal.classList.remove('hidden'); 274 | deleteOverlay.classList.remove('hidden'); 275 | } 276 | 277 | const closeDeleteModal = function () { 278 | deleteModal.classList.add('hidden'); 279 | deleteOverlay.classList.add('hidden'); 280 | } 281 | 282 | function selectPalette(palSel) { 283 | selectPalette = palSel; 284 | } 285 | 286 | const closeModal = function () { 287 | console.log(modal) 288 | modal.classList.add('hidden'); 289 | overlay.classList.add('hidden'); 290 | }; 291 | 292 | 293 | 294 | function dateString() { 295 | var a = new Date(); 296 | var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; 297 | var year = a.getFullYear(); 298 | var month = months[a.getMonth()]; 299 | var date = a.getDate(); 300 | var hour = a.getHours(); 301 | var min = a.getMinutes(); 302 | if (min < 10) { 303 | min = "0" + a.getMinutes(); 304 | } 305 | var time = month + ' ' + date + ' ' + year + ' ' + hour + ':' + min; 306 | return time; 307 | } 308 | 309 | const createPalette = function (paletteName) { 310 | paletteNameInput.classList.remove("error"); 311 | if (paletteName.length > 0 && paletteName.length < 15) { 312 | let formattedDate = dateString(); 313 | let newPalette = { 314 | name: paletteName, 315 | createdDate: formattedDate, 316 | elementsData: [] 317 | } 318 | palettes.push(newPalette); 319 | setPalettes(palettes); 320 | paletteTable.hidden = false; 321 | renderPalettes(palettes); 322 | closeModal() 323 | } else { 324 | paletteNameInput.classList.add("error"); 325 | } 326 | } 327 | 328 | 329 | const editPalette = function (paletteName) { 330 | editPaletteTextInput.classList.remove("error"); 331 | if (paletteName.length > 0 && paletteName.length < 15) { 332 | viewPalette.name = paletteName; 333 | paletteTitle.innerText = paletteName; 334 | palettes[viewPaletteIndex] = viewPalette; 335 | setPalettes(palettes); 336 | closeEditModal() 337 | } else { 338 | editPaletteTextInput.classList.add("error"); 339 | } 340 | } 341 | 342 | const editElement = function (elementName) { 343 | editElementTextInput.classList.remove("error"); 344 | if (elementName.length > 0 && elementName.length < 61) { 345 | viewElement.title = elementName; 346 | elementTitle.innerText = elementName; 347 | viewPalette.elementsData[viewElementIndex] = viewElement; 348 | palettes[viewPaletteIndex] = viewPalette; 349 | setPalettes(palettes); 350 | closeEditElementModal() 351 | } else { 352 | editElementTextInput.classList.add("error"); 353 | } 354 | } 355 | 356 | 357 | const deletePalette = function () { 358 | palettes = palettes.filter(function (pal) { 359 | return pal.name !== viewPalette.name && pal.createdDate !== viewPalette.createdDate; 360 | }); 361 | closeDeleteModal(); 362 | viewPalettePage.hidden = true; 363 | mainPage.hidden = false; 364 | setPalettes(palettes); 365 | retreivePalettes(); 366 | } 367 | 368 | const deleteElement = function () { 369 | viewPalette.elementsData = viewPalette.elementsData.filter(function (elm) { 370 | return elm.css !== viewElement.css && elm.title !== viewElement.title; 371 | }); 372 | 373 | palettes[viewPaletteIndex] = viewPalette; 374 | closeDeleteElementModal(); 375 | viewElementPage.hidden = true; 376 | viewPalettePage.hidden = false; 377 | setPalettes(palettes); 378 | renderElementsPalette(); 379 | } 380 | 381 | 382 | getViewHome(); 383 | updatePaletteUI(); 384 | closeModal(); 385 | retreivePalettes(); 386 | mainPage.hidden = true; 387 | homePage.hidden = false; 388 | viewPalettePage.hidden = true; 389 | viewElementPage.hidden = true; 390 | closeEditModal() 391 | closeDeleteModal() 392 | closeEditElementModal() 393 | closeDeleteElementModal() 394 | 395 | 396 | async function updatePaletteUI() { 397 | await retreivePalettes(); 398 | } 399 | 400 | 401 | closeModal() 402 | closeModalBtn.addEventListener("click", closeModal); 403 | overlay.addEventListener("click", closeModal); 404 | 405 | 406 | document.addEventListener("keydown", function (e) { 407 | if (e.key === "Escape" && !modal.classList.contains("hidden")) { 408 | closeModal(); 409 | } 410 | }); 411 | 412 | 413 | const openModal = function () { 414 | modal.classList.remove('hidden'); 415 | overlay.classList.remove('hidden'); 416 | }; 417 | 418 | createPaletteBtnModal.addEventListener("click", () => { 419 | let palName = paletteNameInput.value; 420 | createPalette(palName); 421 | }); 422 | 423 | createPaletteBtn.addEventListener("click", () => { 424 | openModal(); 425 | }) 426 | 427 | 428 | startButton.addEventListener('click', function () { 429 | setViewHome(); 430 | mainPage.hidden = false; 431 | homePage.hidden = true; 432 | paletteElementsTableContainer.hidden = true; 433 | paletteTableNone.hidden = false; 434 | }); 435 | 436 | 437 | paletteBackButton.addEventListener("click", () => { 438 | mainPage.hidden = false; 439 | viewPalettePage.hidden = true; 440 | retreivePalettes() 441 | }) 442 | 443 | backElementButton.addEventListener("click", () => { 444 | viewPalettePage.hidden = false; 445 | viewElementPage.hidden = true; 446 | renderElementsPalette(); 447 | }) 448 | 449 | editPaletteButton.addEventListener("click", () => { 450 | openEditModal(); 451 | }) 452 | 453 | editElementButton.addEventListener("click", () => { 454 | openEditElementModal(); 455 | }) 456 | 457 | deleteElementButton.addEventListener("click", () => { 458 | openDeleteElementModal(); 459 | }) 460 | 461 | confirmEditElementButton.addEventListener("click", () => { 462 | editElement(editElementTextInput.value) 463 | }) 464 | 465 | editCloseModalButton.addEventListener("click", () => { 466 | closeEditModal(); 467 | }) 468 | 469 | deleteElementModalConfirmButton.addEventListener("click", () => { 470 | deleteElement(); 471 | }) 472 | 473 | deleteElementCloseModalButton.addEventListener("click", () => { 474 | closeDeleteElementModal(); 475 | }) 476 | 477 | confirmEditPaletteButton.addEventListener("click", () => { 478 | editPalette(editPaletteTextInput.value) 479 | }) 480 | 481 | editElementCloseModalButton.addEventListener("click", () => { 482 | closeEditElementModal(); 483 | }) 484 | 485 | openDeleteModalButton.addEventListener("click", () => { 486 | openDeleteModal(); 487 | }) 488 | 489 | deleteCloseModalButton.addEventListener("click", () => { 490 | closeDeleteModal(); 491 | }) 492 | 493 | deleteModalConfirmButton.addEventListener("click", () => { 494 | deletePalette(); 495 | }) 496 | 497 | selectElementButton.addEventListener("click", () => { 498 | chrome.tabs.query({ 499 | active: true, 500 | currentWindow: true 501 | }, function (tabs) { 502 | chrome.runtime.sendMessage({ action: "initiateElementSelect", data: { tab: tabs[0], palette: viewPalette.name } }).then(() => { 503 | window.close(); 504 | }) 505 | }); 506 | }) 507 | 508 | saveClipboardButton.addEventListener("click", () => { 509 | clipBoardIcon.classList.remove("fa-clipboard"); 510 | clipBoardIcon.classList.add("fa-thumbs-o-up"); 511 | navigator.clipboard.writeText(cssEditor.getValue()) 512 | setTimeout((function() { 513 | clipBoardIcon.classList.remove("fa-thumbs-o-up"); 514 | clipBoardIcon.classList.add("fa-clipboard"); 515 | }), 2000) 516 | }) 517 | 518 | saveCssButton.addEventListener("click", function() { 519 | viewElement.css = cssEditor.getValue(); 520 | viewPalette.elementsData[viewElementIndex] = viewElement; 521 | palettes[viewPaletteIndex] = viewPalette; 522 | setPalettes(palettes); 523 | cancelCssButton.hidden = true; 524 | saveCssButton.hidden = true; 525 | saveClipboardButton.hidden = false; 526 | }) 527 | 528 | cancelCssButton.addEventListener("click", function() { 529 | cssEditor.setValue(viewElement.css) 530 | cancelCssButton.hidden = true; 531 | saveCssButton.hidden = true; 532 | saveClipboardButton.hidden = false; 533 | }) 534 | 535 | viewSettingsButton.addEventListener("click", () => { 536 | window.open("https://github.com/ANG13T/designr", "_blank"); 537 | }) 538 | 539 | saveElementClipboard.addEventListener("click", function() { 540 | var result = ""; 541 | viewPalette.elementsData.forEach((eData) => { 542 | result += eData.css; 543 | result += "\n" 544 | result += "\n" 545 | }) 546 | console.log(result); 547 | 548 | clipBoardIconPal.classList.remove("fa-clipboard"); 549 | clipBoardIconPal.classList.add("fa-thumbs-o-up"); 550 | navigator.clipboard.writeText(result) 551 | setTimeout((function() { 552 | clipBoardIconPal.classList.remove("fa-thumbs-o-up"); 553 | clipBoardIconPal.classList.add("fa-clipboard"); 554 | }), 2000) 555 | }) 556 | 557 | function getUserCode() { 558 | return cssEditor.getValue() + "\n" + "" + "\n" + ""; 559 | } 560 | 561 | function update() { 562 | //this is the content of iframe 563 | var code = document.getElementById('iframe').contentWindow.document; 564 | code.open(); 565 | //getting value from editor and puts in the iframe 566 | code.write(getUserCode()); 567 | code.close(); 568 | } 569 | 570 | function initCodeMirror() { 571 | if(codeTemplateContainer.hasChildNodes()) { 572 | codeTemplateContainer.innerHTML = ""; 573 | } 574 | var codeMirror = document.createElement("div"); 575 | codeMirror.classList.add("html-code"); 576 | codeMirror.classList.add("code-display"); 577 | codeTemplateContainer.appendChild(codeMirror); 578 | } 579 | 580 | //Download Code File 581 | function downloadCode() { 582 | //1.Create a blob 583 | const userCode = getUserCode(); 584 | const blob = new Blob([userCode], { type: "text/html" }); 585 | downloadFile(blob, "index.html"); 586 | } 587 | //2.function that accepts blob and file name 588 | function downloadFile(blob, fileName) { 589 | //3.create url for blob 590 | const url = window.URL.createObjectURL(blob); 591 | //4.anchor tag to download 592 | const a = document.createElement('a'); 593 | //Before click we need to add some properties to our anchorTag 594 | a.href = url; 595 | a.download = fileName; 596 | //click event 597 | a.click(); 598 | //remove anchor tag 599 | a.remove(); 600 | 601 | document.addEventListener("focus", w => { window.URL.revokeObjectURL(url) }) 602 | } -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "designr", 3 | "version": "1.0.0", 4 | "description": "Inspect CSS styles and save snapshots of web components and designs", 5 | "author": "Angelina Tsuboi", 6 | "homepage_url": "https://github.com/ANG13T/designr", 7 | "icons": { 8 | "16": "assets/icons/icon16.png", 9 | "48": "assets/icons/icon48.png", 10 | "128": "assets/icons/icon128.png" 11 | }, 12 | "manifest_version": 3, 13 | "permissions": [ 14 | "storage", 15 | "tabs", 16 | "activeTab", 17 | "scripting" 18 | ], 19 | "host_permissions": [ 20 | "" 21 | ], 22 | "background": { 23 | "service_worker": "js/background.js" 24 | }, 25 | "action": { 26 | "default_title": "designr", 27 | "default_popup": "index.html" 28 | }, 29 | 30 | "content_scripts": [ 31 | { 32 | "matches": [ 33 | "" 34 | ], 35 | "js": [ 36 | "js/background.js" 37 | ] 38 | } 39 | ] 40 | } --------------------------------------------------------------------------------