├── FileSaver.js ├── go.js ├── img └── jsoneditor-icons.svg ├── index.html ├── jsoneditor.css ├── jsoneditor.js ├── notie.css ├── notie.js └── state-machine.ts /FileSaver.js: -------------------------------------------------------------------------------- 1 | /* FileSaver.js 2 | * A saveAs() FileSaver implementation. 3 | * 1.3.2 4 | * 2016-06-16 18:25:19 5 | * 6 | * By Eli Grey, http://eligrey.com 7 | * License: MIT 8 | * See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md 9 | */ 10 | 11 | /*global self */ 12 | /*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */ 13 | 14 | /*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */ 15 | 16 | var saveAs = saveAs || (function(view) { 17 | "use strict"; 18 | // IE <10 is explicitly unsupported 19 | if (typeof view === "undefined" || typeof navigator !== "undefined" && /MSIE [1-9]\./.test(navigator.userAgent)) { 20 | return; 21 | } 22 | var 23 | doc = view.document 24 | // only get URL when necessary in case Blob.js hasn't overridden it yet 25 | , get_URL = function() { 26 | return view.URL || view.webkitURL || view; 27 | } 28 | , save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a") 29 | , can_use_save_link = "download" in save_link 30 | , click = function(node) { 31 | var event = new MouseEvent("click"); 32 | node.dispatchEvent(event); 33 | } 34 | , is_safari = /constructor/i.test(view.HTMLElement) || view.safari 35 | , is_chrome_ios =/CriOS\/[\d]+/.test(navigator.userAgent) 36 | , throw_outside = function(ex) { 37 | (view.setImmediate || view.setTimeout)(function() { 38 | throw ex; 39 | }, 0); 40 | } 41 | , force_saveable_type = "application/octet-stream" 42 | // the Blob API is fundamentally broken as there is no "downloadfinished" event to subscribe to 43 | , arbitrary_revoke_timeout = 1000 * 40 // in ms 44 | , revoke = function(file) { 45 | var revoker = function() { 46 | if (typeof file === "string") { // file is an object URL 47 | get_URL().revokeObjectURL(file); 48 | } else { // file is a File 49 | file.remove(); 50 | } 51 | }; 52 | setTimeout(revoker, arbitrary_revoke_timeout); 53 | } 54 | , dispatch = function(filesaver, event_types, event) { 55 | event_types = [].concat(event_types); 56 | var i = event_types.length; 57 | while (i--) { 58 | var listener = filesaver["on" + event_types[i]]; 59 | if (typeof listener === "function") { 60 | try { 61 | listener.call(filesaver, event || filesaver); 62 | } catch (ex) { 63 | throw_outside(ex); 64 | } 65 | } 66 | } 67 | } 68 | , auto_bom = function(blob) { 69 | // prepend BOM for UTF-8 XML and text/* types (including HTML) 70 | // note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF 71 | if (/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) { 72 | return new Blob([String.fromCharCode(0xFEFF), blob], {type: blob.type}); 73 | } 74 | return blob; 75 | } 76 | , FileSaver = function(blob, name, no_auto_bom) { 77 | if (!no_auto_bom) { 78 | blob = auto_bom(blob); 79 | } 80 | // First try a.download, then web filesystem, then object URLs 81 | var 82 | filesaver = this 83 | , type = blob.type 84 | , force = type === force_saveable_type 85 | , object_url 86 | , dispatch_all = function() { 87 | dispatch(filesaver, "writestart progress write writeend".split(" ")); 88 | } 89 | // on any filesys errors revert to saving with object URLs 90 | , fs_error = function() { 91 | if ((is_chrome_ios || (force && is_safari)) && view.FileReader) { 92 | // Safari doesn't allow downloading of blob urls 93 | var reader = new FileReader(); 94 | reader.onloadend = function() { 95 | var url = is_chrome_ios ? reader.result : reader.result.replace(/^data:[^;]*;/, 'data:attachment/file;'); 96 | var popup = view.open(url, '_blank'); 97 | if(!popup) view.location.href = url; 98 | url=undefined; // release reference before dispatching 99 | filesaver.readyState = filesaver.DONE; 100 | dispatch_all(); 101 | }; 102 | reader.readAsDataURL(blob); 103 | filesaver.readyState = filesaver.INIT; 104 | return; 105 | } 106 | // don't create more object URLs than needed 107 | if (!object_url) { 108 | object_url = get_URL().createObjectURL(blob); 109 | } 110 | if (force) { 111 | view.location.href = object_url; 112 | } else { 113 | var opened = view.open(object_url, "_blank"); 114 | if (!opened) { 115 | // Apple does not allow window.open, see https://developer.apple.com/library/safari/documentation/Tools/Conceptual/SafariExtensionGuide/WorkingwithWindowsandTabs/WorkingwithWindowsandTabs.html 116 | view.location.href = object_url; 117 | } 118 | } 119 | filesaver.readyState = filesaver.DONE; 120 | dispatch_all(); 121 | revoke(object_url); 122 | } 123 | ; 124 | filesaver.readyState = filesaver.INIT; 125 | 126 | if (can_use_save_link) { 127 | object_url = get_URL().createObjectURL(blob); 128 | setTimeout(function() { 129 | save_link.href = object_url; 130 | save_link.download = name; 131 | click(save_link); 132 | dispatch_all(); 133 | revoke(object_url); 134 | filesaver.readyState = filesaver.DONE; 135 | }); 136 | return; 137 | } 138 | 139 | fs_error(); 140 | } 141 | , FS_proto = FileSaver.prototype 142 | , saveAs = function(blob, name, no_auto_bom) { 143 | return new FileSaver(blob, name || blob.name || "download", no_auto_bom); 144 | } 145 | ; 146 | // IE 10+ (native saveAs) 147 | if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob) { 148 | return function(blob, name, no_auto_bom) { 149 | name = name || blob.name || "download"; 150 | 151 | if (!no_auto_bom) { 152 | blob = auto_bom(blob); 153 | } 154 | return navigator.msSaveOrOpenBlob(blob, name); 155 | }; 156 | } 157 | 158 | FS_proto.abort = function(){}; 159 | FS_proto.readyState = FS_proto.INIT = 0; 160 | FS_proto.WRITING = 1; 161 | FS_proto.DONE = 2; 162 | 163 | FS_proto.error = 164 | FS_proto.onwritestart = 165 | FS_proto.onprogress = 166 | FS_proto.onwrite = 167 | FS_proto.onabort = 168 | FS_proto.onerror = 169 | FS_proto.onwriteend = 170 | null; 171 | 172 | return saveAs; 173 | }( 174 | typeof self !== "undefined" && self 175 | || typeof window !== "undefined" && window 176 | || this.content 177 | )); 178 | // `self` is undefined in Firefox for Android content script context 179 | // while `this` is nsIContentFrameMessageManager 180 | // with an attribute `content` that corresponds to the window 181 | 182 | if (typeof module !== "undefined" && module.exports) { 183 | module.exports.saveAs = saveAs; 184 | } else if ((typeof define !== "undefined" && define !== null) && (define.amd !== null)) { 185 | define("FileSaver.js", function() { 186 | return saveAs; 187 | }); 188 | } 189 | -------------------------------------------------------------------------------- /img/jsoneditor-icons.svg: -------------------------------------------------------------------------------- 1 | 2 | 16 | JSON Editor Icons 18 | 20 | 21 | 23 | image/svg+xml 24 | 26 | JSON Editor Icons 27 | 28 | 29 | 30 | 32 | 56 | 60 | 61 | 62 | 64 | 71 | 78 | 85 | 92 | 99 | 102 | 109 | 116 | 117 | 121 | 128 | 135 | 136 | 143 | 150 | 157 | 159 | 166 | 173 | 180 | 181 | 184 | 191 | 198 | 205 | 206 | 213 | 219 | 225 | 232 | 237 | 242 | 249 | 255 | 260 | 267 | 273 | 279 | 280 | 287 | 294 | 301 | 308 | 315 | 319 | 326 | 333 | 334 | 338 | 345 | 352 | 353 | 360 | 367 | 374 | 377 | 384 | 391 | 398 | 399 | 402 | 409 | 416 | 423 | 424 | 431 | 437 | 443 | 450 | 455 | 460 | 467 | 473 | 478 | 485 | 491 | 497 | 504 | 511 | 518 | 525 | 532 | 539 | 546 | 552 | 560 | 566 | 572 | 579 | 587 | 595 | 602 | 609 | 616 | 623 | 630 | 637 | 644 | 651 | 657 | 665 | 671 | 677 | 684 | 692 | 700 | 707 | 714 | 721 | 728 | 735 | 742 | 749 | 756 | 761 | 766 | 771 | 777 | 783 | 788 | 793 | 798 | 803 | 808 | 824 | 841 | 858 | 875 | 881 | 887 | 893 | 894 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 |  2 | 3 |

norm mode

4 |

help : alt+h

5 |
6 |
7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 919 | 920 | 921 | -------------------------------------------------------------------------------- /jsoneditor.css: -------------------------------------------------------------------------------- 1 | /* reset styling (prevent conflicts with bootstrap, materialize.css, etc.) */ 2 | 3 | div.jsoneditor .jsoneditor-search input { 4 | height: auto; 5 | border: inherit; 6 | } 7 | 8 | div.jsoneditor .jsoneditor-search input:focus { 9 | border: none !important; 10 | box-shadow: none !important; 11 | } 12 | 13 | div.jsoneditor table { 14 | border-collapse: collapse; 15 | width: auto; 16 | } 17 | 18 | div.jsoneditor td, 19 | div.jsoneditor th { 20 | padding: 0; 21 | display: table-cell; 22 | text-align: left; 23 | vertical-align: inherit; 24 | border-radius: inherit; 25 | } 26 | 27 | 28 | div.jsoneditor-field, 29 | div.jsoneditor-value, 30 | div.jsoneditor-readonly { 31 | border: 1px solid transparent; 32 | min-height: 16px; 33 | min-width: 32px; 34 | padding: 2px; 35 | margin: 1px; 36 | word-wrap: break-word; 37 | float: left; 38 | } 39 | 40 | /* adjust margin of p elements inside editable divs, needed for Opera, IE */ 41 | 42 | div.jsoneditor-field p, 43 | div.jsoneditor-value p { 44 | margin: 0; 45 | } 46 | 47 | div.jsoneditor-value { 48 | word-break: break-word; 49 | } 50 | 51 | div.jsoneditor-readonly { 52 | min-width: 16px; 53 | color: gray; 54 | } 55 | 56 | div.jsoneditor-empty { 57 | border-color: lightgray; 58 | border-style: dashed; 59 | border-radius: 2px; 60 | } 61 | 62 | div.jsoneditor-field.jsoneditor-empty::after, 63 | div.jsoneditor-value.jsoneditor-empty::after { 64 | pointer-events: none; 65 | color: lightgray; 66 | font-size: 8pt; 67 | } 68 | 69 | div.jsoneditor-field.jsoneditor-empty::after { 70 | content: "field"; 71 | } 72 | 73 | div.jsoneditor-value.jsoneditor-empty::after { 74 | content: "value"; 75 | } 76 | 77 | div.jsoneditor-value.jsoneditor-url, 78 | a.jsoneditor-value.jsoneditor-url { 79 | color: green; 80 | text-decoration: underline; 81 | } 82 | 83 | a.jsoneditor-value.jsoneditor-url { 84 | display: inline-block; 85 | padding: 2px; 86 | margin: 2px; 87 | } 88 | 89 | a.jsoneditor-value.jsoneditor-url:hover, 90 | a.jsoneditor-value.jsoneditor-url:focus { 91 | color: #ee422e; 92 | } 93 | 94 | div.jsoneditor td.jsoneditor-separator { 95 | padding: 3px 0; 96 | vertical-align: top; 97 | color: gray; 98 | } 99 | 100 | div.jsoneditor-field[contenteditable=true]:focus, 101 | div.jsoneditor-field[contenteditable=true]:hover, 102 | div.jsoneditor-value[contenteditable=true]:focus, 103 | div.jsoneditor-value[contenteditable=true]:hover, 104 | div.jsoneditor-field.jsoneditor-highlight, 105 | div.jsoneditor-value.jsoneditor-highlight { 106 | background-color: #FFFFAB; 107 | border: 1px solid yellow; 108 | border-radius: 2px; 109 | } 110 | 111 | div.jsoneditor-field.jsoneditor-highlight-active, 112 | div.jsoneditor-field.jsoneditor-highlight-active:focus, 113 | div.jsoneditor-field.jsoneditor-highlight-active:hover, 114 | div.jsoneditor-value.jsoneditor-highlight-active, 115 | div.jsoneditor-value.jsoneditor-highlight-active:focus, 116 | div.jsoneditor-value.jsoneditor-highlight-active:hover { 117 | background-color: #ffee00; 118 | border: 1px solid #ffc700; 119 | border-radius: 2px; 120 | } 121 | 122 | div.jsoneditor-value.jsoneditor-string { 123 | color: #008000; 124 | } 125 | 126 | div.jsoneditor-value.jsoneditor-object, 127 | div.jsoneditor-value.jsoneditor-array { 128 | min-width: 16px; 129 | color: #808080; 130 | } 131 | 132 | div.jsoneditor-value.jsoneditor-number { 133 | color: #ee422e; 134 | } 135 | 136 | div.jsoneditor-value.jsoneditor-boolean { 137 | color: #ff8c00; 138 | } 139 | 140 | div.jsoneditor-value.jsoneditor-null { 141 | color: #004ED0; 142 | } 143 | 144 | div.jsoneditor-value.jsoneditor-invalid { 145 | color: #000000; 146 | } 147 | 148 | div.jsoneditor-tree button { 149 | width: 24px; 150 | height: 24px; 151 | padding: 0; 152 | margin: 0; 153 | border: none; 154 | cursor: pointer; 155 | background: transparent url("img/jsoneditor-icons.svg"); 156 | } 157 | 158 | div.jsoneditor-mode-view tr.jsoneditor-expandable td.jsoneditor-tree, 159 | div.jsoneditor-mode-form tr.jsoneditor-expandable td.jsoneditor-tree { 160 | cursor: pointer; 161 | } 162 | 163 | div.jsoneditor-tree button.jsoneditor-collapsed { 164 | background-position: 0 -48px; 165 | } 166 | 167 | div.jsoneditor-tree button.jsoneditor-expanded { 168 | background-position: 0 -72px; 169 | } 170 | 171 | div.jsoneditor-tree button.jsoneditor-contextmenu { 172 | background-position: -48px -72px; 173 | } 174 | 175 | div.jsoneditor-tree button.jsoneditor-contextmenu:hover, 176 | div.jsoneditor-tree button.jsoneditor-contextmenu:focus, 177 | div.jsoneditor-tree button.jsoneditor-contextmenu.jsoneditor-selected, 178 | tr.jsoneditor-selected.jsoneditor-first button.jsoneditor-contextmenu { 179 | background-position: -48px -48px; 180 | } 181 | 182 | div.jsoneditor-tree *:focus { 183 | outline: none; 184 | } 185 | 186 | div.jsoneditor-tree button:focus { 187 | /* TODO: nice outline for buttons with focus 188 | outline: #97B0F8 solid 2px; 189 | box-shadow: 0 0 8px #97B0F8; 190 | */ 191 | background-color: #f5f5f5; 192 | outline: #e5e5e5 solid 1px; 193 | } 194 | 195 | div.jsoneditor-tree button.jsoneditor-invisible { 196 | visibility: hidden; 197 | background: none; 198 | } 199 | 200 | div.jsoneditor { 201 | color: #1A1A1A; 202 | border: 1px solid #3883fa; 203 | -moz-box-sizing: border-box; 204 | -webkit-box-sizing: border-box; 205 | box-sizing: border-box; 206 | width: 100%; 207 | height: 100%; 208 | overflow: hidden; 209 | position: relative; 210 | padding: 0; 211 | line-height: 100%; 212 | } 213 | 214 | div.jsoneditor-tree table.jsoneditor-tree { 215 | border-collapse: collapse; 216 | border-spacing: 0; 217 | width: 100%; 218 | margin: 0; 219 | } 220 | 221 | div.jsoneditor-outer { 222 | position: static; 223 | width: 100%; 224 | height: 100%; 225 | margin: -35px 0 0 0; 226 | padding: 35px 0 0 0; 227 | -moz-box-sizing: border-box; 228 | -webkit-box-sizing: border-box; 229 | box-sizing: border-box; 230 | } 231 | 232 | textarea.jsoneditor-text, 233 | .ace-jsoneditor { 234 | min-height: 150px; 235 | } 236 | 237 | div.jsoneditor-tree { 238 | width: 100%; 239 | height: 100%; 240 | position: relative; 241 | overflow: auto; 242 | } 243 | 244 | textarea.jsoneditor-text { 245 | width: 100%; 246 | height: 100%; 247 | margin: 0; 248 | -moz-box-sizing: border-box; 249 | -webkit-box-sizing: border-box; 250 | box-sizing: border-box; 251 | outline-width: 0; 252 | border: none; 253 | background-color: white; 254 | resize: none; 255 | } 256 | 257 | tr.jsoneditor-highlight, 258 | tr.jsoneditor-selected { 259 | background-color: #e6e6e6; 260 | } 261 | 262 | tr.jsoneditor-selected button.jsoneditor-dragarea, 263 | tr.jsoneditor-selected button.jsoneditor-contextmenu { 264 | visibility: hidden; 265 | } 266 | 267 | tr.jsoneditor-selected.jsoneditor-first button.jsoneditor-dragarea, 268 | tr.jsoneditor-selected.jsoneditor-first button.jsoneditor-contextmenu { 269 | visibility: visible; 270 | } 271 | 272 | div.jsoneditor-tree button.jsoneditor-dragarea { 273 | background: url("img/jsoneditor-icons.svg") -72px -72px; 274 | cursor: move; 275 | } 276 | 277 | div.jsoneditor-tree button.jsoneditor-dragarea:hover, 278 | div.jsoneditor-tree button.jsoneditor-dragarea:focus, 279 | tr.jsoneditor-selected.jsoneditor-first button.jsoneditor-dragarea { 280 | background-position: -72px -48px; 281 | } 282 | 283 | div.jsoneditor tr, 284 | div.jsoneditor th, 285 | div.jsoneditor td { 286 | padding: 0; 287 | margin: 0; 288 | } 289 | 290 | div.jsoneditor td { 291 | vertical-align: top; 292 | } 293 | 294 | div.jsoneditor td.jsoneditor-tree { 295 | vertical-align: top; 296 | } 297 | 298 | div.jsoneditor-field, 299 | div.jsoneditor-value, 300 | div.jsoneditor td, 301 | div.jsoneditor th, 302 | div.jsoneditor textarea, 303 | .jsoneditor-schema-error { 304 | font-family: droid sans mono, consolas, monospace, courier new, courier, sans-serif; 305 | font-size: 10pt; 306 | color: #1A1A1A; 307 | } 308 | 309 | /* popover */ 310 | 311 | .jsoneditor-schema-error { 312 | cursor: default; 313 | display: inline-block; 314 | /*font-family: arial, sans-serif;*/ 315 | height: 24px; 316 | line-height: 24px; 317 | position: relative; 318 | text-align: center; 319 | width: 24px; 320 | } 321 | 322 | div.jsoneditor-tree .jsoneditor-schema-error { 323 | width: 24px; 324 | height: 24px; 325 | padding: 0; 326 | margin: 0 4px 0 0; 327 | background: url("img/jsoneditor-icons.svg") -168px -48px; 328 | } 329 | 330 | .jsoneditor-schema-error .jsoneditor-popover { 331 | background-color: #4c4c4c; 332 | border-radius: 3px; 333 | box-shadow: 0 0 5px rgba(0,0,0,0.4); 334 | color: #fff; 335 | display: none; 336 | padding: 7px 10px; 337 | position: absolute; 338 | width: 200px; 339 | z-index: 4; 340 | } 341 | 342 | .jsoneditor-schema-error .jsoneditor-popover.jsoneditor-above { 343 | bottom: 32px; 344 | left: -98px; 345 | } 346 | 347 | .jsoneditor-schema-error .jsoneditor-popover.jsoneditor-below { 348 | top: 32px; 349 | left: -98px; 350 | } 351 | 352 | .jsoneditor-schema-error .jsoneditor-popover.jsoneditor-left { 353 | top: -7px; 354 | right: 32px; 355 | } 356 | 357 | .jsoneditor-schema-error .jsoneditor-popover.jsoneditor-right { 358 | top: -7px; 359 | left: 32px; 360 | } 361 | 362 | .jsoneditor-schema-error .jsoneditor-popover:before { 363 | border-right: 7px solid transparent; 364 | border-left: 7px solid transparent; 365 | content: ''; 366 | display: block; 367 | left: 50%; 368 | margin-left: -7px; 369 | position: absolute; 370 | } 371 | 372 | .jsoneditor-schema-error .jsoneditor-popover.jsoneditor-above:before { 373 | border-top: 7px solid #4c4c4c; 374 | bottom: -7px; 375 | } 376 | 377 | .jsoneditor-schema-error .jsoneditor-popover.jsoneditor-below:before { 378 | border-bottom: 7px solid #4c4c4c; 379 | top: -7px; 380 | } 381 | 382 | .jsoneditor-schema-error .jsoneditor-popover.jsoneditor-left:before { 383 | border-left: 7px solid #4c4c4c; 384 | border-top: 7px solid transparent; 385 | border-bottom: 7px solid transparent; 386 | content: ''; 387 | top: 19px; 388 | right: -14px; 389 | left: inherit; 390 | margin-left: inherit; 391 | margin-top: -7px; 392 | position: absolute; 393 | } 394 | 395 | .jsoneditor-schema-error .jsoneditor-popover.jsoneditor-right:before { 396 | border-right: 7px solid #4c4c4c; 397 | border-top: 7px solid transparent; 398 | border-bottom: 7px solid transparent; 399 | content: ''; 400 | top: 19px; 401 | left: -14px; 402 | margin-left: inherit; 403 | margin-top: -7px; 404 | position: absolute; 405 | } 406 | 407 | .jsoneditor-schema-error:hover .jsoneditor-popover, 408 | .jsoneditor-schema-error:focus .jsoneditor-popover { 409 | display: block; 410 | -webkit-animation: fade-in .3s linear 1, move-up .3s linear 1; 411 | -moz-animation: fade-in .3s linear 1, move-up .3s linear 1; 412 | -ms-animation: fade-in .3s linear 1, move-up .3s linear 1; 413 | } 414 | 415 | @-webkit-keyframes fade-in { 416 | from { 417 | opacity: 0; 418 | } 419 | 420 | to { 421 | opacity: 1; 422 | } 423 | } 424 | 425 | @-moz-keyframes fade-in { 426 | from { 427 | opacity: 0; 428 | } 429 | 430 | to { 431 | opacity: 1; 432 | } 433 | } 434 | 435 | @-ms-keyframes fade-in { 436 | from { 437 | opacity: 0; 438 | } 439 | 440 | to { 441 | opacity: 1; 442 | } 443 | } 444 | 445 | /*@-webkit-keyframes move-up {*/ 446 | 447 | /*from { bottom: 24px; }*/ 448 | 449 | /*to { bottom: 32px; }*/ 450 | 451 | /*}*/ 452 | 453 | /*@-moz-keyframes move-up {*/ 454 | 455 | /*from { bottom: 24px; }*/ 456 | 457 | /*to { bottom: 32px; }*/ 458 | 459 | /*}*/ 460 | 461 | /*@-ms-keyframes move-up {*/ 462 | 463 | /*from { bottom: 24px; }*/ 464 | 465 | /*to { bottom: 32px; }*/ 466 | 467 | /*}*/ 468 | 469 | /* JSON schema errors displayed at the bottom of the editor in mode text and code */ 470 | 471 | .jsoneditor .jsoneditor-text-errors { 472 | width: 100%; 473 | border-collapse: collapse; 474 | background-color: #ffef8b; 475 | border-top: 1px solid #ffd700; 476 | } 477 | 478 | .jsoneditor .jsoneditor-text-errors td { 479 | padding: 3px 6px; 480 | vertical-align: middle; 481 | } 482 | 483 | .jsoneditor-text-errors .jsoneditor-schema-error { 484 | border: none; 485 | width: 24px; 486 | height: 24px; 487 | padding: 0; 488 | margin: 0 4px 0 0; 489 | background: url("img/jsoneditor-icons.svg") -168px -48px; 490 | } 491 | /* ContextMenu - main menu */ 492 | 493 | div.jsoneditor-contextmenu-root { 494 | position: relative; 495 | width: 0; 496 | height: 0; 497 | } 498 | 499 | div.jsoneditor-contextmenu { 500 | position: absolute; 501 | box-sizing: content-box; 502 | z-index: 99999; 503 | } 504 | 505 | div.jsoneditor-contextmenu ul, 506 | div.jsoneditor-contextmenu li { 507 | box-sizing: content-box; 508 | } 509 | 510 | div.jsoneditor-contextmenu ul { 511 | position: relative; 512 | left: 0; 513 | top: 0; 514 | width: 124px; 515 | background: white; 516 | border: 1px solid #d3d3d3; 517 | box-shadow: 2px 2px 12px rgba(128, 128, 128, 0.3); 518 | list-style: none; 519 | margin: 0; 520 | padding: 0; 521 | } 522 | 523 | div.jsoneditor-contextmenu ul li button { 524 | padding: 0; 525 | margin: 0; 526 | width: 124px; 527 | height: 24px; 528 | border: none; 529 | cursor: pointer; 530 | color: #4d4d4d; 531 | background: transparent; 532 | font-size: 10pt; 533 | font-family: arial, sans-serif; 534 | box-sizing: border-box; 535 | line-height: 26px; 536 | text-align: left; 537 | } 538 | 539 | /* Fix button padding in firefox */ 540 | 541 | div.jsoneditor-contextmenu ul li button::-moz-focus-inner { 542 | padding: 0; 543 | border: 0; 544 | } 545 | 546 | div.jsoneditor-contextmenu ul li button:hover, 547 | div.jsoneditor-contextmenu ul li button:focus { 548 | color: #1a1a1a; 549 | background-color: #f5f5f5; 550 | outline: none; 551 | } 552 | 553 | div.jsoneditor-contextmenu ul li button.jsoneditor-default { 554 | width: 92px; 555 | } 556 | 557 | div.jsoneditor-contextmenu ul li button.jsoneditor-expand { 558 | float: right; 559 | width: 32px; 560 | height: 24px; 561 | border-left: 1px solid #e5e5e5; 562 | } 563 | 564 | div.jsoneditor-contextmenu div.jsoneditor-icon { 565 | float: left; 566 | width: 24px; 567 | height: 24px; 568 | border: none; 569 | padding: 0; 570 | margin: 0; 571 | background-image: url("img/jsoneditor-icons.svg"); 572 | } 573 | 574 | div.jsoneditor-contextmenu ul li button div.jsoneditor-expand { 575 | float: right; 576 | width: 24px; 577 | height: 24px; 578 | padding: 0; 579 | margin: 0 4px 0 0; 580 | background: url("img/jsoneditor-icons.svg") 0 -72px; 581 | opacity: 0.4; 582 | } 583 | 584 | div.jsoneditor-contextmenu ul li button:hover div.jsoneditor-expand, 585 | div.jsoneditor-contextmenu ul li button:focus div.jsoneditor-expand, 586 | div.jsoneditor-contextmenu ul li.jsoneditor-selected div.jsoneditor-expand, 587 | div.jsoneditor-contextmenu ul li button.jsoneditor-expand:hover div.jsoneditor-expand, 588 | div.jsoneditor-contextmenu ul li button.jsoneditor-expand:focus div.jsoneditor-expand { 589 | opacity: 1; 590 | } 591 | 592 | div.jsoneditor-contextmenu div.jsoneditor-separator { 593 | height: 0; 594 | border-top: 1px solid #e5e5e5; 595 | padding-top: 5px; 596 | margin-top: 5px; 597 | } 598 | 599 | div.jsoneditor-contextmenu button.jsoneditor-remove > div.jsoneditor-icon { 600 | background-position: -24px -24px; 601 | } 602 | 603 | div.jsoneditor-contextmenu button.jsoneditor-remove:hover > div.jsoneditor-icon, 604 | div.jsoneditor-contextmenu button.jsoneditor-remove:focus > div.jsoneditor-icon { 605 | background-position: -24px 0; 606 | } 607 | 608 | div.jsoneditor-contextmenu button.jsoneditor-append > div.jsoneditor-icon { 609 | background-position: 0 -24px; 610 | } 611 | 612 | div.jsoneditor-contextmenu button.jsoneditor-append:hover > div.jsoneditor-icon, 613 | div.jsoneditor-contextmenu button.jsoneditor-append:focus > div.jsoneditor-icon { 614 | background-position: 0 0; 615 | } 616 | 617 | div.jsoneditor-contextmenu button.jsoneditor-insert > div.jsoneditor-icon { 618 | background-position: 0 -24px; 619 | } 620 | 621 | div.jsoneditor-contextmenu button.jsoneditor-insert:hover > div.jsoneditor-icon, 622 | div.jsoneditor-contextmenu button.jsoneditor-insert:focus > div.jsoneditor-icon { 623 | background-position: 0 0; 624 | } 625 | 626 | div.jsoneditor-contextmenu button.jsoneditor-duplicate > div.jsoneditor-icon { 627 | background-position: -48px -24px; 628 | } 629 | 630 | div.jsoneditor-contextmenu button.jsoneditor-duplicate:hover > div.jsoneditor-icon, 631 | div.jsoneditor-contextmenu button.jsoneditor-duplicate:focus > div.jsoneditor-icon { 632 | background-position: -48px 0; 633 | } 634 | 635 | div.jsoneditor-contextmenu button.jsoneditor-sort-asc > div.jsoneditor-icon { 636 | background-position: -168px -24px; 637 | } 638 | 639 | div.jsoneditor-contextmenu button.jsoneditor-sort-asc:hover > div.jsoneditor-icon, 640 | div.jsoneditor-contextmenu button.jsoneditor-sort-asc:focus > div.jsoneditor-icon { 641 | background-position: -168px 0; 642 | } 643 | 644 | div.jsoneditor-contextmenu button.jsoneditor-sort-desc > div.jsoneditor-icon { 645 | background-position: -192px -24px; 646 | } 647 | 648 | div.jsoneditor-contextmenu button.jsoneditor-sort-desc:hover > div.jsoneditor-icon, 649 | div.jsoneditor-contextmenu button.jsoneditor-sort-desc:focus > div.jsoneditor-icon { 650 | background-position: -192px 0; 651 | } 652 | 653 | /* ContextMenu - sub menu */ 654 | 655 | div.jsoneditor-contextmenu ul li button.jsoneditor-selected, 656 | div.jsoneditor-contextmenu ul li button.jsoneditor-selected:hover, 657 | div.jsoneditor-contextmenu ul li button.jsoneditor-selected:focus { 658 | color: white; 659 | background-color: #ee422e; 660 | } 661 | 662 | div.jsoneditor-contextmenu ul li { 663 | overflow: hidden; 664 | } 665 | 666 | div.jsoneditor-contextmenu ul li ul { 667 | display: none; 668 | position: relative; 669 | left: -10px; 670 | top: 0; 671 | border: none; 672 | box-shadow: inset 0 0 10px rgba(128, 128, 128, 0.5); 673 | padding: 0 10px; 674 | /* TODO: transition is not supported on IE8-9 */ 675 | -webkit-transition: all 0.3s ease-out; 676 | -moz-transition: all 0.3s ease-out; 677 | -o-transition: all 0.3s ease-out; 678 | transition: all 0.3s ease-out; 679 | } 680 | 681 | 682 | 683 | div.jsoneditor-contextmenu ul li ul li button { 684 | padding-left: 24px; 685 | animation: all ease-in-out 1s; 686 | } 687 | 688 | div.jsoneditor-contextmenu ul li ul li button:hover, 689 | div.jsoneditor-contextmenu ul li ul li button:focus { 690 | background-color: #f5f5f5; 691 | } 692 | 693 | div.jsoneditor-contextmenu button.jsoneditor-type-string > div.jsoneditor-icon { 694 | background-position: -144px -24px; 695 | } 696 | 697 | div.jsoneditor-contextmenu button.jsoneditor-type-string:hover > div.jsoneditor-icon, 698 | div.jsoneditor-contextmenu button.jsoneditor-type-string:focus > div.jsoneditor-icon, 699 | div.jsoneditor-contextmenu button.jsoneditor-type-string.jsoneditor-selected > div.jsoneditor-icon { 700 | background-position: -144px 0; 701 | } 702 | 703 | div.jsoneditor-contextmenu button.jsoneditor-type-auto > div.jsoneditor-icon { 704 | background-position: -120px -24px; 705 | } 706 | 707 | div.jsoneditor-contextmenu button.jsoneditor-type-auto:hover > div.jsoneditor-icon, 708 | div.jsoneditor-contextmenu button.jsoneditor-type-auto:focus > div.jsoneditor-icon, 709 | div.jsoneditor-contextmenu button.jsoneditor-type-auto.jsoneditor-selected > div.jsoneditor-icon { 710 | background-position: -120px 0; 711 | } 712 | 713 | div.jsoneditor-contextmenu button.jsoneditor-type-object > div.jsoneditor-icon { 714 | background-position: -72px -24px; 715 | } 716 | 717 | div.jsoneditor-contextmenu button.jsoneditor-type-object:hover > div.jsoneditor-icon, 718 | div.jsoneditor-contextmenu button.jsoneditor-type-object:focus > div.jsoneditor-icon, 719 | div.jsoneditor-contextmenu button.jsoneditor-type-object.jsoneditor-selected > div.jsoneditor-icon { 720 | background-position: -72px 0; 721 | } 722 | 723 | div.jsoneditor-contextmenu button.jsoneditor-type-array > div.jsoneditor-icon { 724 | background-position: -96px -24px; 725 | } 726 | 727 | div.jsoneditor-contextmenu button.jsoneditor-type-array:hover > div.jsoneditor-icon, 728 | div.jsoneditor-contextmenu button.jsoneditor-type-array:focus > div.jsoneditor-icon, 729 | div.jsoneditor-contextmenu button.jsoneditor-type-array.jsoneditor-selected > div.jsoneditor-icon { 730 | background-position: -96px 0; 731 | } 732 | 733 | div.jsoneditor-contextmenu button.jsoneditor-type-modes > div.jsoneditor-icon { 734 | background-image: none; 735 | width: 6px; 736 | } 737 | div.jsoneditor-menu { 738 | width: 100%; 739 | height: 35px; 740 | padding: 2px; 741 | margin: 0; 742 | -moz-box-sizing: border-box; 743 | -webkit-box-sizing: border-box; 744 | box-sizing: border-box; 745 | color: white; 746 | background-color: #CCCCCC; 747 | border-bottom: 1px solid #CCCCCC; 748 | } 749 | 750 | div.jsoneditor-menu > button, 751 | div.jsoneditor-menu > div.jsoneditor-modes > button { 752 | width: 26px; 753 | height: 26px; 754 | margin: 2px; 755 | padding: 0; 756 | border-radius: 2px; 757 | border: 1px solid transparent; 758 | background: transparent url("img/jsoneditor-icons.svg"); 759 | color: white; 760 | opacity: 0.8; 761 | font-family: arial, sans-serif; 762 | font-size: 10pt; 763 | float: left; 764 | } 765 | 766 | div.jsoneditor-menu > button:hover, 767 | div.jsoneditor-menu > div.jsoneditor-modes > button:hover { 768 | background-color: rgba(255,255,255,0.2); 769 | border: 1px solid rgba(255,255,255,0.4); 770 | } 771 | 772 | div.jsoneditor-menu > button:focus, 773 | div.jsoneditor-menu > button:active, 774 | div.jsoneditor-menu > div.jsoneditor-modes > button:focus, 775 | div.jsoneditor-menu > div.jsoneditor-modes > button:active { 776 | background-color: rgba(255,255,255,0.3); 777 | } 778 | 779 | div.jsoneditor-menu > button:disabled, 780 | div.jsoneditor-menu > div.jsoneditor-modes > button:disabled { 781 | opacity: 0.5; 782 | } 783 | 784 | div.jsoneditor-menu > button.jsoneditor-collapse-all { 785 | background-position: 0 -96px; 786 | } 787 | 788 | div.jsoneditor-menu > button.jsoneditor-expand-all { 789 | background-position: 0 -120px; 790 | } 791 | 792 | div.jsoneditor-menu > button.jsoneditor-undo { 793 | background-position: -24px -96px; 794 | } 795 | 796 | div.jsoneditor-menu > button.jsoneditor-undo:disabled { 797 | background-position: -24px -120px; 798 | } 799 | 800 | div.jsoneditor-menu > button.jsoneditor-redo { 801 | background-position: -48px -96px; 802 | } 803 | 804 | div.jsoneditor-menu > button.jsoneditor-redo:disabled { 805 | background-position: -48px -120px; 806 | } 807 | 808 | div.jsoneditor-menu > button.jsoneditor-compact { 809 | background-position: -72px -96px; 810 | } 811 | 812 | div.jsoneditor-menu > button.jsoneditor-format { 813 | background-position: -72px -120px; 814 | } 815 | 816 | div.jsoneditor-menu > div.jsoneditor-modes { 817 | display: inline-block; 818 | float: left; 819 | } 820 | 821 | div.jsoneditor-menu > div.jsoneditor-modes > button { 822 | background-image: none; 823 | width: auto; 824 | padding-left: 6px; 825 | padding-right: 6px; 826 | } 827 | 828 | div.jsoneditor-menu > button.jsoneditor-separator, 829 | div.jsoneditor-menu > div.jsoneditor-modes > button.jsoneditor-separator { 830 | margin-left: 10px; 831 | } 832 | 833 | div.jsoneditor-menu a { 834 | font-family: arial, sans-serif; 835 | font-size: 10pt; 836 | color: white; 837 | opacity: 0.8; 838 | vertical-align: middle; 839 | } 840 | 841 | div.jsoneditor-menu a:hover { 842 | opacity: 1; 843 | } 844 | 845 | div.jsoneditor-menu a.jsoneditor-poweredBy { 846 | font-size: 8pt; 847 | position: absolute; 848 | right: 0; 849 | top: 0; 850 | padding: 10px; 851 | } 852 | table.jsoneditor-search input, 853 | table.jsoneditor-search div.jsoneditor-results { 854 | font-family: arial, sans-serif; 855 | font-size: 10pt; 856 | color: #1A1A1A; 857 | background: transparent; 858 | /* For Firefox */ 859 | } 860 | 861 | table.jsoneditor-search div.jsoneditor-results { 862 | color: white; 863 | padding-right: 5px; 864 | line-height: 24px; 865 | } 866 | 867 | table.jsoneditor-search { 868 | position: absolute; 869 | right: 4px; 870 | top: 4px; 871 | border-collapse: collapse; 872 | border-spacing: 0; 873 | } 874 | 875 | table.jsoneditor-search div.jsoneditor-frame { 876 | border: 1px solid transparent; 877 | background-color: white; 878 | padding: 0 2px; 879 | margin: 0; 880 | } 881 | 882 | table.jsoneditor-search div.jsoneditor-frame table { 883 | border-collapse: collapse; 884 | } 885 | 886 | table.jsoneditor-search input { 887 | width: 120px; 888 | border: none; 889 | outline: none; 890 | margin: 1px; 891 | line-height: 20px; 892 | } 893 | 894 | table.jsoneditor-search button { 895 | width: 16px; 896 | height: 24px; 897 | padding: 0; 898 | margin: 0; 899 | border: none; 900 | background: url("img/jsoneditor-icons.svg"); 901 | vertical-align: top; 902 | } 903 | 904 | table.jsoneditor-search button:hover { 905 | background-color: transparent; 906 | } 907 | 908 | table.jsoneditor-search button.jsoneditor-refresh { 909 | width: 18px; 910 | background-position: -99px -73px; 911 | } 912 | 913 | table.jsoneditor-search button.jsoneditor-next { 914 | cursor: pointer; 915 | background-position: -124px -73px; 916 | } 917 | 918 | table.jsoneditor-search button.jsoneditor-next:hover { 919 | background-position: -124px -49px; 920 | } 921 | 922 | table.jsoneditor-search button.jsoneditor-previous { 923 | cursor: pointer; 924 | background-position: -148px -73px; 925 | margin-right: 2px; 926 | } 927 | 928 | table.jsoneditor-search button.jsoneditor-previous:hover { 929 | background-position: -148px -49px; 930 | } -------------------------------------------------------------------------------- /notie.css: -------------------------------------------------------------------------------- 1 | .notie-container { 2 | font-size: 1.6rem; 3 | height: auto; 4 | left: 0; 5 | position: fixed; 6 | text-align: center; 7 | width: 100%; 8 | z-index: 2147483647; 9 | box-sizing: border-box; 10 | -o-box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.5); 11 | -ms-box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.5); 12 | -moz-box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.5); 13 | -webkit-box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.5); 14 | box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.5); } 15 | @media screen and (max-width: 900px) { 16 | .notie-container { 17 | font-size: 1.4rem; } } 18 | @media screen and (max-width: 750px) { 19 | .notie-container { 20 | font-size: 1.2rem; } } 21 | @media screen and (max-width: 400px) { 22 | .notie-container { 23 | font-size: 1rem; } } 24 | 25 | .notie-background-success { 26 | background-color: #57BF57; } 27 | 28 | .notie-background-warning { 29 | background-color: #D6A14D; } 30 | 31 | .notie-background-error { 32 | background-color: #E1715B; } 33 | 34 | .notie-background-info { 35 | background-color: #4D82D6; } 36 | 37 | .notie-background-neutral { 38 | background-color: #A0A0A0; } 39 | 40 | .notie-background-overlay { 41 | background-color: #FFFFFF; } 42 | 43 | .notie-textbox { 44 | color: #FFFFFF; 45 | padding: 20px; } 46 | 47 | .notie-textbox-inner { 48 | margin: 0 auto; 49 | max-width: 900px; } 50 | 51 | .notie-overlay { 52 | height: 100%; 53 | left: 0; 54 | opacity: 0; 55 | position: fixed; 56 | top: 0; 57 | width: 100%; 58 | z-index: 2147483646; } 59 | 60 | .notie-button { 61 | color: #FFFFFF; 62 | padding: 10px; 63 | cursor: pointer; } 64 | 65 | .notie-element { 66 | color: #FFFFFF; 67 | padding: 10px; } 68 | 69 | .notie-element-half { 70 | display: inline-block; 71 | width: 50%; 72 | box-sizing: border-box; } 73 | 74 | .notie-element-third { 75 | display: inline-block; 76 | width: 33.3333%; 77 | box-sizing: border-box; } 78 | 79 | .notie-alert { 80 | cursor: pointer; } 81 | 82 | .notie-input-field { 83 | background-color: #FFFFFF; 84 | border: 0; 85 | font-family: inherit; 86 | font-size: inherit; 87 | outline: 0; 88 | padding: 10px; 89 | text-align: center; 90 | width: 100%; 91 | box-sizing: border-box; } 92 | 93 | .notie-select-choice-repeated { 94 | border-bottom: 1px solid rgba(255, 255, 255, 0.2); 95 | box-sizing: border-box; } 96 | 97 | .notie-date-selector-inner { 98 | margin: 0 auto; 99 | max-width: 900px; 100 | -webkit-user-select: none; 101 | -moz-user-select: none; 102 | -ms-user-select: none; 103 | -o-user-select: none; 104 | user-select: none; } 105 | .notie-date-selector-inner [contenteditable], .notie-date-selector-inner [contenteditable]:focus { 106 | outline: 0px solid transparent; } 107 | 108 | .notie-date-selector-up { 109 | transform: rotate(180deg); } 110 | -------------------------------------------------------------------------------- /notie.js: -------------------------------------------------------------------------------- 1 | (function webpackUniversalModuleDefinition(root, factory) { 2 | if(typeof exports === 'object' && typeof module === 'object') 3 | module.exports = factory(); 4 | else if(typeof define === 'function' && define.amd) 5 | define([], factory); 6 | else if(typeof exports === 'object') 7 | exports["notie"] = factory(); 8 | else 9 | root["notie"] = factory(); 10 | })(this, function() { 11 | return /******/ (function(modules) { // webpackBootstrap 12 | /******/ // The module cache 13 | /******/ var installedModules = {}; 14 | 15 | /******/ // The require function 16 | /******/ function __webpack_require__(moduleId) { 17 | 18 | /******/ // Check if module is in cache 19 | /******/ if(installedModules[moduleId]) 20 | /******/ return installedModules[moduleId].exports; 21 | 22 | /******/ // Create a new module (and put it into the cache) 23 | /******/ var module = installedModules[moduleId] = { 24 | /******/ i: moduleId, 25 | /******/ l: false, 26 | /******/ exports: {} 27 | /******/ }; 28 | 29 | /******/ // Execute the module function 30 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 31 | 32 | /******/ // Flag the module as loaded 33 | /******/ module.l = true; 34 | 35 | /******/ // Return the exports of the module 36 | /******/ return module.exports; 37 | /******/ } 38 | 39 | 40 | /******/ // expose the modules object (__webpack_modules__) 41 | /******/ __webpack_require__.m = modules; 42 | 43 | /******/ // expose the module cache 44 | /******/ __webpack_require__.c = installedModules; 45 | 46 | /******/ // identity function for calling harmony imports with the correct context 47 | /******/ __webpack_require__.i = function(value) { return value; }; 48 | 49 | /******/ // define getter function for harmony exports 50 | /******/ __webpack_require__.d = function(exports, name, getter) { 51 | /******/ if(!__webpack_require__.o(exports, name)) { 52 | /******/ Object.defineProperty(exports, name, { 53 | /******/ configurable: false, 54 | /******/ enumerable: true, 55 | /******/ get: getter 56 | /******/ }); 57 | /******/ } 58 | /******/ }; 59 | 60 | /******/ // getDefaultExport function for compatibility with non-harmony modules 61 | /******/ __webpack_require__.n = function(module) { 62 | /******/ var getter = module && module.__esModule ? 63 | /******/ function getDefault() { return module['default']; } : 64 | /******/ function getModuleExports() { return module; }; 65 | /******/ __webpack_require__.d(getter, 'a', getter); 66 | /******/ return getter; 67 | /******/ }; 68 | 69 | /******/ // Object.prototype.hasOwnProperty.call 70 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 71 | 72 | /******/ // __webpack_public_path__ 73 | /******/ __webpack_require__.p = ""; 74 | 75 | /******/ // Load entry module and return exports 76 | /******/ return __webpack_require__(__webpack_require__.s = 0); 77 | /******/ }) 78 | /************************************************************************/ 79 | /******/ ([ 80 | /* 0 */ 81 | /***/ (function(module, exports, __webpack_require__) { 82 | 83 | "use strict"; 84 | 85 | 86 | Object.defineProperty(exports, "__esModule", { 87 | value: true 88 | }); 89 | 90 | var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; 91 | 92 | var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; 93 | 94 | function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } 95 | 96 | // ==================== 97 | // options 98 | // ==================== 99 | 100 | let currentId = null; 101 | let currentPosition = null; 102 | 103 | var positions = { 104 | top: 'top', 105 | bottom: 'bottom' 106 | }; 107 | 108 | var options = { 109 | alertTime: 3, 110 | dateMonths: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], 111 | overlayClickDismiss: true, 112 | overlayOpacity: 0.75, 113 | transitionCurve: 'ease', 114 | transitionDuration: 0.3, 115 | transitionSelector: 'all', 116 | classes: { 117 | container: 'notie-container', 118 | textbox: 'notie-textbox', 119 | textboxInner: 'notie-textbox-inner', 120 | button: 'notie-button', 121 | element: 'notie-element', 122 | elementHalf: 'notie-element-half', 123 | elementThird: 'notie-element-third', 124 | overlay: 'notie-overlay', 125 | backgroundSuccess: 'notie-background-success', 126 | backgroundWarning: 'notie-background-warning', 127 | backgroundError: 'notie-background-error', 128 | backgroundInfo: 'notie-background-info', 129 | backgroundNeutral: 'notie-background-neutral', 130 | backgroundOverlay: 'notie-background-overlay', 131 | alert: 'notie-alert', 132 | inputField: 'notie-input-field', 133 | selectChoiceRepeated: 'notie-select-choice-repeated', 134 | dateSelectorInner: 'notie-date-selector-inner', 135 | dateSelectorUp: 'notie-date-selector-up' 136 | }, 137 | ids: { 138 | overlay: 'notie-overlay' 139 | }, 140 | positions: { 141 | alert: positions.top, 142 | force: positions.top, 143 | confirm: positions.top, 144 | input: positions.top, 145 | select: positions.bottom, 146 | date: positions.top 147 | } 148 | }; 149 | 150 | var setOptions = exports.setOptions = function setOptions(newOptions) { 151 | options = _extends({}, options, newOptions, { 152 | classes: _extends({}, options.classes, newOptions.classes), 153 | ids: _extends({}, options.ids, newOptions.ids), 154 | positions: _extends({}, options.positions, newOptions.positions) 155 | }); 156 | }; 157 | 158 | // ==================== 159 | // helpers 160 | // ==================== 161 | 162 | var tick = function tick() { 163 | return new Promise(function (resolve) { 164 | return setTimeout(resolve, 0); 165 | }); 166 | }; 167 | var wait = function wait(time) { 168 | return new Promise(function (resolve) { 169 | return setTimeout(resolve, time * 1000); 170 | }); 171 | }; 172 | 173 | var blur = function blur() { 174 | document.activeElement && document.activeElement.blur(); 175 | }; 176 | 177 | var generateRandomId = function generateRandomId() { 178 | // RFC4122 version 4 compliant UUID 179 | var id = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { 180 | var r = Math.random() * 16 | 0; 181 | var v = c === 'x' ? r : r & 0x3 | 0x8; 182 | return v.toString(16); 183 | }); 184 | return 'notie-' + id; 185 | }; 186 | 187 | var typeToClassLookup = { 188 | 1: options.classes.backgroundSuccess, 189 | success: options.classes.backgroundSuccess, 190 | 2: options.classes.backgroundWarning, 191 | warning: options.classes.backgroundWarning, 192 | 3: options.classes.backgroundError, 193 | error: options.classes.backgroundError, 194 | 4: options.classes.backgroundInfo, 195 | info: options.classes.backgroundInfo, 196 | 5: options.classes.backgroundNeutral, 197 | neutral: options.classes.backgroundNeutral 198 | }; 199 | 200 | var getTransition = function getTransition() { 201 | return options.transitionSelector + ' ' + options.transitionDuration + 's ' + options.transitionCurve; 202 | }; 203 | 204 | var enterClicked = function enterClicked(event) { 205 | return event.keyCode === 13; 206 | }; 207 | var escapeClicked = function escapeClicked(event) { 208 | return event.keyCode === 27; 209 | }; 210 | 211 | var addToDocument = function addToDocument(element, position) { 212 | element.classList.add(options.classes.container); 213 | element.style[position] = '-10000px'; 214 | document.body.appendChild(element); 215 | element.style[position] = '-' + element.offsetHeight + 'px'; 216 | 217 | if (element.listener) window.addEventListener('keydown', element.listener); 218 | 219 | tick().then(function () { 220 | element.style.transition = getTransition(); 221 | element.style[position] = 0; 222 | }); 223 | }; 224 | 225 | var removeFromDocument = function removeFromDocument(id, position) { 226 | var element = document.getElementById(id); 227 | if (!element) return; 228 | element.style[position] = '-' + element.offsetHeight + 'px'; 229 | 230 | if (element.listener) window.removeEventListener('keydown', element.listener); 231 | 232 | wait(options.transitionDuration).then(function () { 233 | if (element.parentNode) element.parentNode.removeChild(element); 234 | }); 235 | }; 236 | 237 | var addOverlayToDocument = function addOverlayToDocument(owner, position) { 238 | var element = document.createElement('div'); 239 | element.id = options.ids.overlay; 240 | element.classList.add(options.classes.overlay); 241 | element.classList.add(options.classes.backgroundOverlay); 242 | element.style.opacity = 0; 243 | if (owner && options.overlayClickDismiss) { 244 | element.onclick = function () { 245 | removeFromDocument(owner.id, position); 246 | removeOverlayFromDocument(); 247 | }; 248 | } 249 | 250 | document.body.appendChild(element); 251 | 252 | tick().then(function () { 253 | element.style.transition = getTransition(); 254 | element.style.opacity = options.overlayOpacity; 255 | }); 256 | }; 257 | 258 | var removeOverlayFromDocument = function removeOverlayFromDocument() { 259 | var element = document.getElementById(options.ids.overlay); 260 | if(!element){return;} 261 | element.style.opacity = 0; 262 | wait(options.transitionDuration).then(function () { 263 | if (element.parentNode) element.parentNode.removeChild(element); 264 | }); 265 | }; 266 | 267 | var hideAlerts = exports.hideAlerts = function hideAlerts(callback) { 268 | var alertsShowing = document.getElementsByClassName(options.classes.alert); 269 | if (alertsShowing.length) { 270 | for (var i = 0; i < alertsShowing.length; i++) { 271 | var _alert = alertsShowing[i]; 272 | removeFromDocument(_alert.id, _alert.position); 273 | } 274 | if (callback) wait(options.transitionDuration).then(function () { 275 | return callback(); 276 | }); 277 | } 278 | }; 279 | 280 | var removeAll = exports.removeAll = function removeAll(){ 281 | if(currentId && currentPosition){ 282 | removeFromDocument(currentId,currentPosition); 283 | removeOverlayFromDocument(); 284 | currentId = null; 285 | currentPosition = null; 286 | } 287 | } 288 | 289 | // ==================== 290 | // exports 291 | // ==================== 292 | 293 | var alert = exports.alert = function alert(_ref) { 294 | var _ref$type = _ref.type, 295 | type = _ref$type === undefined ? 4 : _ref$type, 296 | text = _ref.text, 297 | _ref$time = _ref.time, 298 | time = _ref$time === undefined ? options.alertTime : _ref$time, 299 | _ref$stay = _ref.stay, 300 | stay = _ref$stay === undefined ? false : _ref$stay, 301 | _ref$position = _ref.position, 302 | position = _ref$position === undefined ? options.positions.alert || position.top : _ref$position; 303 | 304 | blur(); 305 | hideAlerts(); 306 | 307 | var element = document.createElement('div'); 308 | var id = generateRandomId(); 309 | element.id = id; 310 | element.position = position; 311 | 312 | currentId = id; 313 | currentPosition = position; 314 | 315 | element.classList.add(options.classes.textbox); 316 | element.classList.add(typeToClassLookup[type]); 317 | element.classList.add(options.classes.alert); 318 | element.innerHTML = '
' + text + '
'; 319 | element.onclick = function () { 320 | return removeFromDocument(id, position); 321 | }; 322 | 323 | element.listener = function (event) { 324 | if (enterClicked(event) || escapeClicked(event)) hideAlerts(); 325 | }; 326 | 327 | addToDocument(element, position); 328 | 329 | if (time && time < 1) time = 1; 330 | if (!stay && time) wait(time).then(function () { 331 | return removeFromDocument(id, position); 332 | }); 333 | }; 334 | 335 | var force = exports.force = function force(_ref2, callbackArg) { 336 | var _ref2$type = _ref2.type, 337 | type = _ref2$type === undefined ? 5 : _ref2$type, 338 | text = _ref2.text, 339 | _ref2$buttonText = _ref2.buttonText, 340 | buttonText = _ref2$buttonText === undefined ? 'OK' : _ref2$buttonText, 341 | callback = _ref2.callback, 342 | _ref2$position = _ref2.position, 343 | position = _ref2$position === undefined ? options.positions.force || position.top : _ref2$position; 344 | 345 | blur(); 346 | hideAlerts(); 347 | 348 | var element = document.createElement('div'); 349 | var id = generateRandomId(); 350 | element.id = id; 351 | 352 | var elementText = document.createElement('div'); 353 | elementText.classList.add(options.classes.textbox); 354 | elementText.classList.add(options.classes.backgroundInfo); 355 | elementText.innerHTML = '
' + text + '
'; 356 | 357 | var elementButton = document.createElement('div'); 358 | elementButton.classList.add(options.classes.button); 359 | elementButton.classList.add(typeToClassLookup[type]); 360 | elementButton.innerHTML = buttonText; 361 | elementButton.onclick = function () { 362 | removeFromDocument(id, position); 363 | removeOverlayFromDocument(); 364 | if (callback) callback();else if (callbackArg) callbackArg(); 365 | }; 366 | 367 | element.appendChild(elementText); 368 | element.appendChild(elementButton); 369 | 370 | element.listener = function (event) { 371 | if (enterClicked(event)) elementButton.click(); 372 | }; 373 | 374 | addToDocument(element, position); 375 | 376 | addOverlayToDocument(); 377 | }; 378 | 379 | //var oldConfirmId = null; 380 | //var oldConfirmPosition = null; 381 | 382 | var confirm = exports.confirm = function confirm(_ref3, submitCallbackArg, cancelCallbackArg) { 383 | // if(oldConfirmId && oldConfirmPosition){ 384 | // removeFromDocument(oldConfirmId, oldConfirmPosition); 385 | // removeOverlayFromDocument(); 386 | // oldConfirmId = null; 387 | // oldConfirmPosition = null; 388 | // } 389 | var text = _ref3.text, 390 | _ref3$submitText = _ref3.submitText, 391 | submitText = _ref3$submitText === undefined ? 'Yes' : _ref3$submitText, 392 | _ref3$cancelText = _ref3.cancelText, 393 | cancelText = _ref3$cancelText === undefined ? 'Cancel' : _ref3$cancelText, 394 | submitCallback = _ref3.submitCallback, 395 | cancelCallback = _ref3.cancelCallback, 396 | _ref3$position = _ref3.position, 397 | position = _ref3$position === undefined ? options.positions.confirm || position.top : _ref3$position; 398 | 399 | blur(); 400 | hideAlerts(); 401 | 402 | var element = document.createElement('div'); 403 | var id = generateRandomId(); 404 | element.id = id; 405 | 406 | currentId = id; 407 | currentPosition = position; 408 | 409 | var elementText = document.createElement('div'); 410 | elementText.classList.add(options.classes.textbox); 411 | elementText.classList.add(options.classes.backgroundInfo); 412 | elementText.innerHTML = '
' + text + '
'; 413 | 414 | var elementButtonLeft = document.createElement('div'); 415 | elementButtonLeft.classList.add(options.classes.button); 416 | elementButtonLeft.classList.add(options.classes.elementHalf); 417 | elementButtonLeft.classList.add(options.classes.backgroundSuccess); 418 | elementButtonLeft.innerHTML = submitText; 419 | 420 | //oldConfirmId = id; 421 | //oldConfirmPosition = position; 422 | 423 | elementButtonLeft.onclick = function () { 424 | removeFromDocument(id, position); 425 | removeOverlayFromDocument(); 426 | //oldConfirmId = null; 427 | //oldConfirmPosition = null; 428 | if (submitCallback) submitCallback();else if (submitCallbackArg) submitCallbackArg(); 429 | }; 430 | 431 | var elementButtonRight = document.createElement('div'); 432 | elementButtonRight.classList.add(options.classes.button); 433 | elementButtonRight.classList.add(options.classes.elementHalf); 434 | elementButtonRight.classList.add(options.classes.backgroundError); 435 | elementButtonRight.innerHTML = cancelText; 436 | elementButtonRight.onclick = function () { 437 | removeFromDocument(id, position); 438 | removeOverlayFromDocument(); 439 | //oldConfirmId = null; 440 | //oldConfirmPosition = null; 441 | if (cancelCallback) cancelCallback();else if (cancelCallbackArg) cancelCallbackArg(); 442 | }; 443 | 444 | element.appendChild(elementText); 445 | element.appendChild(elementButtonLeft); 446 | element.appendChild(elementButtonRight); 447 | 448 | element.listener = function (event) { 449 | if (enterClicked(event)) elementButtonLeft.click();else if (escapeClicked(event)) elementButtonRight.click(); 450 | }; 451 | 452 | addToDocument(element, position); 453 | 454 | addOverlayToDocument(element, position); 455 | }; 456 | 457 | //let oldInputId = null; 458 | //let oldInputPosition = null; 459 | 460 | var input = function input(_ref4, submitCallbackArg, cancelCallbackArg) { 461 | // if(oldInputId && oldInputPosition){ 462 | // removeFromDocument(oldInputId, oldInputPosition); 463 | // removeOverlayFromDocument(); 464 | // //oldInputId = null; 465 | // //oldInputPosition = null; 466 | // } 467 | var text = _ref4.text, 468 | _ref4$submitText = _ref4.submitText, 469 | submitText = _ref4$submitText === undefined ? 'Submit' : _ref4$submitText, 470 | _ref4$cancelText = _ref4.cancelText, 471 | cancelText = _ref4$cancelText === undefined ? 'Cancel' : _ref4$cancelText, 472 | submitCallback = _ref4.submitCallback, 473 | cancelCallback = _ref4.cancelCallback, 474 | _ref4$position = _ref4.position, 475 | position = _ref4$position === undefined ? options.positions.input || position.top : _ref4$position, 476 | settings = _objectWithoutProperties(_ref4, ['text', 'submitText', 'cancelText', 'submitCallback', 'cancelCallback', 'position']); 477 | 478 | blur(); 479 | hideAlerts(); 480 | 481 | var element = document.createElement('div'); 482 | var id = generateRandomId(); 483 | element.id = id; 484 | 485 | //oldInputId = id; 486 | //oldInputPosition = position; 487 | 488 | currentId = id; 489 | currentPosition = position; 490 | 491 | var elementText = document.createElement('div'); 492 | elementText.classList.add(options.classes.textbox); 493 | elementText.classList.add(options.classes.backgroundInfo); 494 | elementText.innerHTML = '
' + text + '
'; 495 | 496 | var elementInput = document.createElement('input'); 497 | elementInput.classList.add(options.classes.inputField); 498 | 499 | elementInput.setAttribute('autocapitalize', settings.autocapitalize || 'none'); 500 | elementInput.setAttribute('autocomplete', settings.autocomplete || 'off'); 501 | elementInput.setAttribute('autocorrect', settings.autocorrect || 'off'); 502 | elementInput.setAttribute('autofocus', settings.autofocus || 'true'); 503 | elementInput.setAttribute('inputmode', settings.inputmode || 'verbatim'); 504 | elementInput.setAttribute('max', settings.max || ''); 505 | elementInput.setAttribute('maxlength', settings.maxlength || ''); 506 | elementInput.setAttribute('min', settings.min || ''); 507 | elementInput.setAttribute('minlength', settings.minlength || ''); 508 | elementInput.setAttribute('placeholder', settings.placeholder || ''); 509 | elementInput.setAttribute('spellcheck', settings.spellcheck || 'default'); 510 | elementInput.setAttribute('step', settings.step || 'any'); 511 | elementInput.setAttribute('type', settings.type || 'text'); 512 | 513 | elementInput.value = settings.value || ''; 514 | 515 | // As-you-type input restrictions 516 | if (settings.allowed) { 517 | elementInput.oninput = function () { 518 | var regex = void 0; 519 | if (Array.isArray(settings.allowed)) { 520 | var regexString = ''; 521 | var allowed = settings.allowed; 522 | for (var i = 0; i < allowed.length; i++) { 523 | if (allowed[i] === 'an') regexString += '0-9a-zA-Z';else if (allowed[i] === 'a') regexString += 'a-zA-Z';else if (allowed[i] === 'n') regexString += '0-9'; 524 | if (allowed[i] === 's') regexString += ' '; 525 | } 526 | regex = new RegExp('[^' + regexString + ']', 'g'); 527 | } else if (_typeof(settings.allowed) === 'object') { 528 | regex = settings.allowed; 529 | } 530 | elementInput.value = elementInput.value.replace(regex, ''); 531 | }; 532 | } 533 | 534 | var elementButtonLeft = document.createElement('div'); 535 | elementButtonLeft.classList.add(options.classes.button); 536 | elementButtonLeft.classList.add(options.classes.elementHalf); 537 | elementButtonLeft.classList.add(options.classes.backgroundSuccess); 538 | elementButtonLeft.innerHTML = submitText; 539 | elementButtonLeft.onclick = function () { 540 | removeFromDocument(id, position); 541 | removeOverlayFromDocument(); 542 | //oldInputId = null; 543 | //oldInputPosition = null; 544 | if (submitCallback) submitCallback(elementInput.value);else if (submitCallbackArg) submitCallbackArg(elementInput.value); 545 | }; 546 | 547 | var elementButtonRight = document.createElement('div'); 548 | elementButtonRight.classList.add(options.classes.button); 549 | elementButtonRight.classList.add(options.classes.elementHalf); 550 | elementButtonRight.classList.add(options.classes.backgroundError); 551 | elementButtonRight.innerHTML = cancelText; 552 | elementButtonRight.onclick = function () { 553 | removeFromDocument(id, position); 554 | removeOverlayFromDocument(); 555 | //oldInputId = null; 556 | //oldInputPosition = null; 557 | if (cancelCallback) cancelCallback(elementInput.value);else if (cancelCallbackArg) cancelCallbackArg(elementInput.value); 558 | }; 559 | 560 | element.appendChild(elementText); 561 | element.appendChild(elementInput); 562 | element.appendChild(elementButtonLeft); 563 | element.appendChild(elementButtonRight); 564 | 565 | element.listener = function (event) { 566 | if (enterClicked(event)) elementButtonLeft.click();else if (escapeClicked(event)) elementButtonRight.click(); 567 | }; 568 | 569 | addToDocument(element, position); 570 | 571 | elementInput.focus(); 572 | 573 | addOverlayToDocument(element, position); 574 | }; 575 | 576 | exports.input = input; 577 | 578 | 579 | //var oldSelectId = null; 580 | //var oldSelectPosition = null; 581 | var select = exports.select = function select(_ref5, cancelCallbackArg) { 582 | // if(oldSelectId && oldSelectPosition){ 583 | // removeFromDocument(oldSelectId, oldSelectPosition); 584 | // removeOverlayFromDocument(); 585 | // oldSelectId = null; 586 | // oldSelectPosition = null; 587 | // } 588 | var text = _ref5.text, 589 | _ref5$cancelText = _ref5.cancelText, 590 | cancelText = _ref5$cancelText === undefined ? 'Cancel' : _ref5$cancelText, 591 | cancelCallback = _ref5.cancelCallback, 592 | choices = _ref5.choices, 593 | _ref5$position = _ref5.position, 594 | position = _ref5$position === undefined ? options.positions.select || position.top : _ref5$position; 595 | 596 | blur(); 597 | hideAlerts(); 598 | 599 | var element = document.createElement('div'); 600 | var id = generateRandomId(); 601 | element.id = id; 602 | 603 | // oldSelectId = id; 604 | // oldSelectPosition = position; 605 | 606 | currentId = id; 607 | currentPosition = position; 608 | 609 | var elementText = document.createElement('div'); 610 | elementText.classList.add(options.classes.textbox); 611 | elementText.classList.add(options.classes.backgroundInfo); 612 | elementText.innerHTML = '
' + text + '
'; 613 | 614 | element.appendChild(elementText); 615 | 616 | choices.forEach(function (_ref6, index) { 617 | var _ref6$type = _ref6.type, 618 | type = _ref6$type === undefined ? 1 : _ref6$type, 619 | text = _ref6.text, 620 | handler = _ref6.handler; 621 | 622 | var elementChoice = document.createElement('div'); 623 | elementChoice.classList.add(typeToClassLookup[type]); 624 | elementChoice.classList.add(options.classes.button); 625 | elementChoice.classList.add(options.classes.selectChoice); 626 | 627 | var nextChoice = choices[index + 1]; 628 | if (nextChoice && !nextChoice.type) nextChoice.type = 1; 629 | if (nextChoice && nextChoice.type === type) { 630 | elementChoice.classList.add(options.classes.selectChoiceRepeated); 631 | } 632 | 633 | elementChoice.innerHTML = text; 634 | elementChoice.onclick = function () { 635 | removeFromDocument(id, position); 636 | removeOverlayFromDocument(); 637 | // oldSelectId = null; 638 | // oldSelectPosition = null; 639 | handler(); 640 | }; 641 | 642 | element.appendChild(elementChoice); 643 | }); 644 | 645 | var elementCancel = document.createElement('div'); 646 | elementCancel.classList.add(options.classes.backgroundNeutral); 647 | elementCancel.classList.add(options.classes.button); 648 | elementCancel.innerHTML = cancelText; 649 | elementCancel.onclick = function () { 650 | removeFromDocument(id, position); 651 | removeOverlayFromDocument(); 652 | if (cancelCallback) cancelCallback();else if (cancelCallbackArg) cancelCallbackArg(); 653 | }; 654 | 655 | element.appendChild(elementCancel); 656 | 657 | element.listener = function (event) { 658 | if (escapeClicked(event)) elementCancel.click(); 659 | }; 660 | 661 | addToDocument(element, position); 662 | 663 | addOverlayToDocument(element, position); 664 | }; 665 | 666 | var date = exports.date = function date(_ref7, submitCallbackArg, cancelCallbackArg) { 667 | var _ref7$value = _ref7.value, 668 | value = _ref7$value === undefined ? new Date() : _ref7$value, 669 | _ref7$submitText = _ref7.submitText, 670 | submitText = _ref7$submitText === undefined ? 'OK' : _ref7$submitText, 671 | _ref7$cancelText = _ref7.cancelText, 672 | cancelText = _ref7$cancelText === undefined ? 'Cancel' : _ref7$cancelText, 673 | submitCallback = _ref7.submitCallback, 674 | cancelCallback = _ref7.cancelCallback, 675 | _ref7$position = _ref7.position, 676 | position = _ref7$position === undefined ? options.positions.date || position.top : _ref7$position; 677 | 678 | blur(); 679 | hideAlerts(); 680 | 681 | var arrow = '▾'; 682 | 683 | var elementDateMonth = document.createElement('div'); 684 | var elementDateDay = document.createElement('div'); 685 | var elementDateYear = document.createElement('div'); 686 | 687 | var setValueHTML = function setValueHTML(date) { 688 | elementDateMonth.innerHTML = options.dateMonths[date.getMonth()]; 689 | elementDateDay.innerHTML = date.getDate(); 690 | elementDateYear.innerHTML = date.getFullYear(); 691 | }; 692 | 693 | var handleDayInput = function handleDayInput(event) { 694 | var daysInMonth = new Date(value.getFullYear(), value.getMonth() + 1, 0).getDate(); 695 | var day = event.target.textContent.replace(/^0+/, '').replace(/[^\d]/g, '').slice(0, 2); 696 | if (Number(day) > daysInMonth) day = daysInMonth.toString(); 697 | event.target.textContent = day; 698 | if (Number(day) < 1) day = '1'; 699 | value.setDate(Number(day)); 700 | }; 701 | 702 | var handleYearInput = function handleYearInput(event) { 703 | var year = event.target.textContent.replace(/^0+/, '').replace(/[^\d]/g, '').slice(0, 4); 704 | event.target.textContent = year; 705 | value.setFullYear(Number(year)); 706 | }; 707 | 708 | var handleBlur = function handleBlur(event) { 709 | setValueHTML(value); 710 | }; 711 | 712 | var updateMonth = function updateMonth(amount) { 713 | var daysInNextMonth = new Date(value.getFullYear(), value.getMonth() + amount + 1, 0).getDate(); 714 | if (value.getDate() > daysInNextMonth) value.setDate(daysInNextMonth); 715 | value.setMonth(value.getMonth() + amount); 716 | setValueHTML(value); 717 | }; 718 | 719 | var updateDay = function updateDay(amount) { 720 | value.setDate(value.getDate() + amount); 721 | setValueHTML(value); 722 | }; 723 | 724 | var updateYear = function updateYear(amount) { 725 | var nextYear = value.getFullYear() + amount; 726 | if (nextYear < 0) value.setFullYear(0);else value.setFullYear(value.getFullYear() + amount); 727 | setValueHTML(value); 728 | }; 729 | 730 | var element = document.createElement('div'); 731 | var id = generateRandomId(); 732 | element.id = id; 733 | 734 | var elementDateSelector = document.createElement('div'); 735 | elementDateSelector.classList.add(options.classes.backgroundInfo); 736 | 737 | var elementDateSelectorInner = document.createElement('div'); 738 | elementDateSelectorInner.classList.add(options.classes.dateSelectorInner); 739 | 740 | var elementDateUpMonth = document.createElement('div'); 741 | elementDateUpMonth.classList.add(options.classes.button); 742 | elementDateUpMonth.classList.add(options.classes.elementThird); 743 | elementDateUpMonth.classList.add(options.classes.dateSelectorUp); 744 | elementDateUpMonth.innerHTML = arrow; 745 | 746 | var elementDateUpDay = document.createElement('div'); 747 | elementDateUpDay.classList.add(options.classes.button); 748 | elementDateUpDay.classList.add(options.classes.elementThird); 749 | elementDateUpDay.classList.add(options.classes.dateSelectorUp); 750 | elementDateUpDay.innerHTML = arrow; 751 | 752 | var elementDateUpYear = document.createElement('div'); 753 | elementDateUpYear.classList.add(options.classes.button); 754 | elementDateUpYear.classList.add(options.classes.elementThird); 755 | elementDateUpYear.classList.add(options.classes.dateSelectorUp); 756 | elementDateUpYear.innerHTML = arrow; 757 | 758 | elementDateMonth.classList.add(options.classes.element); 759 | elementDateMonth.classList.add(options.classes.elementThird); 760 | elementDateMonth.innerHTML = options.dateMonths[value.getMonth()]; 761 | 762 | elementDateDay.classList.add(options.classes.element); 763 | elementDateDay.classList.add(options.classes.elementThird); 764 | elementDateDay.setAttribute('contentEditable', true); 765 | elementDateDay.addEventListener('input', handleDayInput); 766 | elementDateDay.addEventListener('blur', handleBlur); 767 | elementDateDay.innerHTML = value.getDate(); 768 | 769 | elementDateYear.classList.add(options.classes.element); 770 | elementDateYear.classList.add(options.classes.elementThird); 771 | elementDateYear.setAttribute('contentEditable', true); 772 | elementDateYear.addEventListener('input', handleYearInput); 773 | elementDateYear.addEventListener('blur', handleBlur); 774 | elementDateYear.innerHTML = value.getFullYear(); 775 | 776 | var elementDateDownMonth = document.createElement('div'); 777 | elementDateDownMonth.classList.add(options.classes.button); 778 | elementDateDownMonth.classList.add(options.classes.elementThird); 779 | elementDateDownMonth.innerHTML = arrow; 780 | 781 | var elementDateDownDay = document.createElement('div'); 782 | elementDateDownDay.classList.add(options.classes.button); 783 | elementDateDownDay.classList.add(options.classes.elementThird); 784 | elementDateDownDay.innerHTML = arrow; 785 | 786 | var elementDateDownYear = document.createElement('div'); 787 | elementDateDownYear.classList.add(options.classes.button); 788 | elementDateDownYear.classList.add(options.classes.elementThird); 789 | elementDateDownYear.innerHTML = arrow; 790 | 791 | elementDateUpMonth.onclick = function () { 792 | return updateMonth(1); 793 | }; 794 | elementDateUpDay.onclick = function () { 795 | return updateDay(1); 796 | }; 797 | elementDateUpYear.onclick = function () { 798 | return updateYear(1); 799 | }; 800 | elementDateDownMonth.onclick = function () { 801 | return updateMonth(-1); 802 | }; 803 | elementDateDownDay.onclick = function () { 804 | return updateDay(-1); 805 | }; 806 | elementDateDownYear.onclick = function () { 807 | return updateYear(-1); 808 | }; 809 | 810 | var elementButtonLeft = document.createElement('div'); 811 | elementButtonLeft.classList.add(options.classes.button); 812 | elementButtonLeft.classList.add(options.classes.elementHalf); 813 | elementButtonLeft.classList.add(options.classes.backgroundSuccess); 814 | elementButtonLeft.innerHTML = submitText; 815 | elementButtonLeft.onclick = function () { 816 | removeFromDocument(id, position); 817 | removeOverlayFromDocument(); 818 | if (submitCallback) submitCallback(value);else if (submitCallbackArg) submitCallbackArg(value); 819 | }; 820 | 821 | var elementButtonRight = document.createElement('div'); 822 | elementButtonRight.classList.add(options.classes.button); 823 | elementButtonRight.classList.add(options.classes.elementHalf); 824 | elementButtonRight.classList.add(options.classes.backgroundError); 825 | elementButtonRight.innerHTML = cancelText; 826 | elementButtonRight.onclick = function () { 827 | removeFromDocument(id, position); 828 | removeOverlayFromDocument(); 829 | if (cancelCallback) cancelCallback(value);else if (cancelCallbackArg) cancelCallbackArg(value); 830 | }; 831 | 832 | elementDateSelectorInner.appendChild(elementDateUpMonth); 833 | elementDateSelectorInner.appendChild(elementDateUpDay); 834 | elementDateSelectorInner.appendChild(elementDateUpYear); 835 | elementDateSelectorInner.appendChild(elementDateMonth); 836 | elementDateSelectorInner.appendChild(elementDateDay); 837 | elementDateSelectorInner.appendChild(elementDateYear); 838 | elementDateSelectorInner.appendChild(elementDateDownMonth); 839 | elementDateSelectorInner.appendChild(elementDateDownDay); 840 | elementDateSelectorInner.appendChild(elementDateDownYear); 841 | elementDateSelector.appendChild(elementDateSelectorInner); 842 | element.appendChild(elementDateSelector); 843 | element.appendChild(elementButtonLeft); 844 | element.appendChild(elementButtonRight); 845 | 846 | element.listener = function (event) { 847 | if (enterClicked(event)) elementButtonLeft.click();else if (escapeClicked(event)) elementButtonRight.click(); 848 | }; 849 | 850 | addToDocument(element, position); 851 | 852 | addOverlayToDocument(element, position); 853 | }; 854 | 855 | exports.default = { 856 | alert: alert, 857 | force: force, 858 | confirm: confirm, 859 | input: input, 860 | select: select, 861 | date: date, 862 | setOptions: setOptions, 863 | hideAlerts: hideAlerts, 864 | removeAll: removeAll, 865 | }; 866 | 867 | /***/ }) 868 | /******/ ]); 869 | }); -------------------------------------------------------------------------------- /state-machine.ts: -------------------------------------------------------------------------------- 1 | interface ResultInterface { 2 | SUCCEEDED: number; 3 | NOTRANSITION: number; 4 | CANCELLED: number; 5 | PENDING: number; 6 | } 7 | 8 | interface ErrorInterface { 9 | INVALID_TRANSITION: number; 10 | PENDING_TRANSITION: number; 11 | INVALID_CALLBACK: number; 12 | } 13 | 14 | 15 | export default class StateMachine { 16 | 17 | //--------------------------------------------------------------------------- 18 | 19 | private static VERSION: string = "2.4.0"; 20 | 21 | //--------------------------------------------------------------------------- 22 | 23 | private static readonly Result: ResultInterface = { 24 | SUCCEEDED: 1, // the event transitioned successfully from one state to another 25 | NOTRANSITION: 2, // the event was successfull but no state transition was necessary 26 | CANCELLED: 3, // the event was cancelled by the caller in a beforeEvent callback 27 | PENDING: 4 // the event is asynchronous and the caller is in control of when the transition occurs 28 | }; 29 | 30 | private static readonly Error: ErrorInterface = { 31 | INVALID_TRANSITION: 100, // caller tried to fire an event that was innapropriate in the current state 32 | PENDING_TRANSITION: 200, // caller tried to fire an event while an async transition was still pending 33 | INVALID_CALLBACK: 300 // caller provided callback function threw an exception 34 | }; 35 | 36 | private static readonly WILDCARD: string = '*'; 37 | private static readonly ASYNC: string = 'async'; 38 | 39 | //--------------------------------------------------------------------------- 40 | 41 | public static create(cfg:any, target: any){ 42 | 43 | let initial = (typeof cfg.initial == 'string') ? { state: cfg.initial } : cfg.initial; // allow for a simple string, or an object with { state: 'foo', event: 'setup', defer: true|false } 44 | let terminal = cfg.terminal || cfg['final']; 45 | let fsm = target; 46 | let events = cfg.events || []; 47 | let callbacks = cfg.callbacks || {}; 48 | let map = {}; // track state transitions allowed for an event { event: { from: [ to ] } } 49 | let transitions = {}; // track events allowed from a state { state: [ event ] } 50 | 51 | let add = function (e) { 52 | let from = Array.isArray(e.from) ? e.from : (e.from ? [e.from] : [StateMachine.WILDCARD]); // allow 'wildcard' transition if 'from' is not specified 53 | map[e.name] = map[e.name] || {}; 54 | for (let n = 0; n < from.length; n++) { 55 | transitions[from[n]] = transitions[from[n]] || []; 56 | transitions[from[n]].push(e.name); 57 | 58 | map[e.name][from[n]] = e.to || from[n]; // allow no-op transition if 'to' is not specified 59 | } 60 | if (e.to) 61 | transitions[e.to] = transitions[e.to] || []; 62 | }; 63 | 64 | if (initial) { 65 | initial.event = initial.event || 'startup'; 66 | add({ name: initial.event, from: 'none', to: initial.state }); 67 | } 68 | 69 | for (let n = 0; n < events.length; n++) 70 | add(events[n]); 71 | 72 | for (let name in map) { 73 | if (map.hasOwnProperty(name)) 74 | fsm[name] = StateMachine.buildEvent(name, map[name]); 75 | } 76 | 77 | for (let name in callbacks) { 78 | if (callbacks.hasOwnProperty(name)) 79 | fsm[name] = callbacks[name] 80 | } 81 | 82 | fsm.current = 'none'; 83 | fsm.is = function (state) { return Array.isArray(state) ? (state.indexOf(this.current) >= 0) : (this.current === state); }; 84 | fsm.can = function (event) { return !this.transition && (map[event] !== undefined) && (map[event].hasOwnProperty(this.current) || map[event].hasOwnProperty(StateMachine.WILDCARD)); } 85 | fsm.cannot = function (event) { return !this.can(event); }; 86 | fsm.transitions = function () { return (transitions[this.current] || []).concat(transitions[StateMachine.WILDCARD] || []); }; 87 | fsm.isFinished = function () { return this.is(terminal); }; 88 | fsm.error = cfg.error || function (name, from, to, args, error, msg, e) { throw e || msg; }; // default behavior when something unexpected happens is to throw an exception, but caller can override this behavior if desired (see github issue #3 and #17) 89 | fsm.states = function () { return Object.keys(transitions).sort() }; 90 | 91 | if (initial && !initial.defer) 92 | fsm[initial.event](); 93 | 94 | return fsm; 95 | 96 | }; 97 | 98 | //=========================================================================== 99 | 100 | private static doCallback(fsm, func, name, from, to, args) { 101 | if (func) { 102 | try { 103 | if (Array.isArray(func)) { 104 | for (let i = 0, l = func.length; i < l; i++) { 105 | func[i].apply(fsm, [name, from,to].concat(args)); 106 | //func[i](name, from, to, args); 107 | } 108 | return true; 109 | } else { 110 | func.apply(fsm, [name, from, to].concat(args)); 111 | return true; 112 | } 113 | } 114 | catch (e) { 115 | fsm.error(name, from, to, args, StateMachine.Error.INVALID_CALLBACK, "an exception occurred in a caller-provided callback function", e); 116 | return true; 117 | } 118 | } 119 | }; 120 | 121 | private static beforeAnyEvent(fsm, name, from, to, args) { return StateMachine.doCallback(fsm, fsm['onbeforeevent'], name, from, to, args); }; 122 | private static afterAnyEvent(fsm, name, from, to, args) { return StateMachine.doCallback(fsm, fsm['onafterevent'] || fsm['onevent'], name, from, to, args); }; 123 | private static leaveAnyState(fsm, name, from, to, args) { return StateMachine.doCallback(fsm, fsm['onleavestate'], name, from, to, args); }; 124 | private static enterAnyState(fsm, name, from, to, args) { return StateMachine.doCallback(fsm, fsm['onenterstate'] || fsm['onstate'], name, from, to, args); }; 125 | private static changeState(fsm, name, from, to, args) { return StateMachine.doCallback(fsm, fsm['onchangestate'], name, from, to, args); }; 126 | 127 | private static beforeThisEvent(fsm, name, from, to, args) { return StateMachine.doCallback(fsm, fsm['onbefore' + name], name, from, to, args); }; 128 | private static afterThisEvent(fsm, name, from, to, args) { return StateMachine.doCallback(fsm, fsm['onafter' + name] || fsm['on' + name], name, from, to, args); }; 129 | private static leaveThisState(fsm, name, from, to, args) { return StateMachine.doCallback(fsm, fsm['onleave' + from], name, from, to, args); }; 130 | private static enterThisState(fsm, name, from, to, args) { return StateMachine.doCallback(fsm, fsm['onenter' + to] || fsm['on' + to], name, from, to, args); }; 131 | 132 | private static beforeEvent(fsm, name, from, to, args) { 133 | if ((false === StateMachine.beforeThisEvent(fsm, name, from, to, args)) || 134 | (false === StateMachine.beforeAnyEvent(fsm, name, from, to, args))) 135 | return false; 136 | }; 137 | 138 | private static afterEvent(fsm, name, from, to, args) { 139 | StateMachine.afterThisEvent(fsm, name, from, to, args); 140 | StateMachine.afterAnyEvent(fsm, name, from, to, args); 141 | }; 142 | 143 | private static leaveState(fsm, name, from, to, args) { 144 | let specific = StateMachine.leaveThisState(fsm, name, from, to, args), 145 | general = StateMachine.leaveAnyState(fsm, name, from, to, args); 146 | if ((false === specific) || (false === general)) 147 | return false; 148 | else if ((typeof StateMachine.ASYNC === typeof specific) || (typeof StateMachine.ASYNC === typeof general)) 149 | return StateMachine.ASYNC; 150 | }; 151 | 152 | private static enterState(fsm, name, from, to, args) { 153 | StateMachine.enterThisState(fsm, name, from, to, args); 154 | StateMachine.enterAnyState(fsm, name, from, to, args); 155 | }; 156 | 157 | //=========================================================================== 158 | 159 | private static buildEvent(name, map) { 160 | return function () { 161 | 162 | let from = this.current; 163 | let to = map[from] || (map[StateMachine.WILDCARD] != StateMachine.WILDCARD ? map[StateMachine.WILDCARD] : from) || from; 164 | let args = Array.prototype.slice.call(arguments); // turn arguments into pure array 165 | 166 | if (this.transition) 167 | return this.error(name, from, to, args, StateMachine.Error.PENDING_TRANSITION, "event " + name + " inappropriate because previous transition did not complete"); 168 | 169 | if (this.cannot(name)) 170 | return this.error(name, from, to, args, StateMachine.Error.INVALID_TRANSITION, "event " + name + " inappropriate in current state " + this.current); 171 | 172 | if (false === StateMachine.beforeEvent(this, name, from, to, args)) 173 | return StateMachine.Result.CANCELLED; 174 | 175 | if (from === to) { 176 | StateMachine.afterEvent(this, name, from, to, args); 177 | return StateMachine.Result.NOTRANSITION; 178 | } 179 | 180 | // prepare a transition method for use EITHER lower down, or by caller if they want an async transition (indicated by an ASYNC return value from leaveState) 181 | let fsm = this; 182 | this.transition = function () { 183 | fsm.transition = null; // this method should only ever be called once 184 | fsm.current = to; 185 | StateMachine.enterState(fsm, name, from, to, args); 186 | StateMachine.changeState(fsm, name, from, to, args); 187 | StateMachine.afterEvent(fsm, name, from, to, args); 188 | return StateMachine.Result.SUCCEEDED; 189 | }; 190 | this.transition.cancel = function () { // provide a way for caller to cancel async transition if desired (issue #22) 191 | fsm.transition = null; 192 | StateMachine.afterEvent(fsm, name, from, to, args); 193 | } 194 | 195 | let leave = StateMachine.leaveState(this, name, from, to, args); 196 | if (false === leave) { 197 | this.transition = null; 198 | return StateMachine.Result.CANCELLED; 199 | } 200 | else if (StateMachine.ASYNC === leave) { 201 | return StateMachine.Result.PENDING; 202 | } 203 | else { 204 | if (this.transition) // need to check in case user manually called transition() but forgot to return StateMachine.ASYNC 205 | return this.transition(); 206 | } 207 | 208 | }; 209 | } 210 | 211 | }; --------------------------------------------------------------------------------