From 004258a1761cd35cfad469afb2665cf66f4787ff Mon Sep 17 00:00:00 2001 From: hunterlong Date: Mon, 3 Feb 2020 22:37:32 -0800 Subject: [PATCH] turtles --- .gitignore | 1 - frontend/{src/assets => public}/css/base.css | 2 +- frontend/public/css/bootstrap.min.css | 7 + .../public/css/codemirror-colorpicker.css | 679 ++ frontend/public/css/codemirror.css | 346 + frontend/public/img/banner.png | Bin 0 -> 98711 bytes .../public/js/codemirror-colorpicker.min.js | 1 + frontend/public/js/codemirror.js | 9683 +++++++++++++++++ frontend/public/js/css.js | 832 ++ frontend/public/js/inputTags.min.js | 1 + frontend/public/js/rangePlugin.js | 147 + frontend/src/App.vue | 8 +- frontend/src/assets/css/flatpickr.min.css | 13 - frontend/src/assets/font/all.css | 3950 ------- frontend/src/assets/font/all.min.css | 5 - .../assets/font/webfonts/fa-brands-400.eot | Bin 123540 -> 0 bytes .../assets/font/webfonts/fa-brands-400.svg | 1175 -- .../assets/font/webfonts/fa-brands-400.ttf | Bin 123304 -> 0 bytes .../assets/font/webfonts/fa-brands-400.woff | Bin 79752 -> 0 bytes .../assets/font/webfonts/fa-brands-400.woff2 | Bin 68240 -> 0 bytes .../assets/font/webfonts/fa-regular-400.eot | Bin 40576 -> 0 bytes .../assets/font/webfonts/fa-regular-400.svg | 467 - .../assets/font/webfonts/fa-regular-400.ttf | Bin 40348 -> 0 bytes .../assets/font/webfonts/fa-regular-400.woff | Bin 18168 -> 0 bytes .../assets/font/webfonts/fa-regular-400.woff2 | Bin 14880 -> 0 bytes .../src/assets/font/webfonts/fa-solid-900.eot | Bin 191332 -> 0 bytes .../src/assets/font/webfonts/fa-solid-900.svg | 2564 ----- .../src/assets/font/webfonts/fa-solid-900.ttf | Bin 191112 -> 0 bytes .../assets/font/webfonts/fa-solid-900.woff | Bin 92696 -> 0 bytes .../assets/font/webfonts/fa-solid-900.woff2 | Bin 72000 -> 0 bytes .../Dashboard/DashboardMessages.vue | 2 +- .../Dashboard/DashboardServices.vue | 3 + frontend/src/components/Footer.vue | 4 +- frontend/src/components/Index/Group.vue | 4 +- .../src/components/Index/MessageBlock.vue | 4 +- .../src/components/Service/ServiceBlock.vue | 8 +- frontend/src/forms/Message.vue | 4 +- frontend/src/mixin.js | 17 +- frontend/src/pages/Index.vue | 9 +- frontend/src/pages/Settings.vue | 5 +- handlers/api.go | 10 +- handlers/cache.go | 24 + source/wiki.go | 2 +- 43 files changed, 11778 insertions(+), 8199 deletions(-) rename frontend/{src/assets => public}/css/base.css (99%) create mode 100644 frontend/public/css/bootstrap.min.css create mode 100644 frontend/public/css/codemirror-colorpicker.css create mode 100644 frontend/public/css/codemirror.css create mode 100644 frontend/public/img/banner.png create mode 100644 frontend/public/js/codemirror-colorpicker.min.js create mode 100644 frontend/public/js/codemirror.js create mode 100644 frontend/public/js/css.js create mode 100755 frontend/public/js/inputTags.min.js create mode 100644 frontend/public/js/rangePlugin.js delete mode 100644 frontend/src/assets/css/flatpickr.min.css delete mode 100644 frontend/src/assets/font/all.css delete mode 100644 frontend/src/assets/font/all.min.css delete mode 100644 frontend/src/assets/font/webfonts/fa-brands-400.eot delete mode 100644 frontend/src/assets/font/webfonts/fa-brands-400.svg delete mode 100644 frontend/src/assets/font/webfonts/fa-brands-400.ttf delete mode 100644 frontend/src/assets/font/webfonts/fa-brands-400.woff delete mode 100644 frontend/src/assets/font/webfonts/fa-brands-400.woff2 delete mode 100644 frontend/src/assets/font/webfonts/fa-regular-400.eot delete mode 100644 frontend/src/assets/font/webfonts/fa-regular-400.svg delete mode 100644 frontend/src/assets/font/webfonts/fa-regular-400.ttf delete mode 100644 frontend/src/assets/font/webfonts/fa-regular-400.woff delete mode 100644 frontend/src/assets/font/webfonts/fa-regular-400.woff2 delete mode 100644 frontend/src/assets/font/webfonts/fa-solid-900.eot delete mode 100644 frontend/src/assets/font/webfonts/fa-solid-900.svg delete mode 100644 frontend/src/assets/font/webfonts/fa-solid-900.ttf delete mode 100644 frontend/src/assets/font/webfonts/fa-solid-900.woff delete mode 100644 frontend/src/assets/font/webfonts/fa-solid-900.woff2 diff --git a/.gitignore b/.gitignore index 3d89ec53..a63425a9 100644 --- a/.gitignore +++ b/.gitignore @@ -14,7 +14,6 @@ dev/plugin/*.so html/scss/.sass-cache dart-sass .sass-cache -public *.log .env logs diff --git a/frontend/src/assets/css/base.css b/frontend/public/css/base.css similarity index 99% rename from frontend/src/assets/css/base.css rename to frontend/public/css/base.css index 0018ead3..1120d47f 100644 --- a/frontend/src/assets/css/base.css +++ b/frontend/public/css/base.css @@ -137,7 +137,7 @@ HTML, BODY { .chart-container { position: relative; - height: 200px; + height: 190px; width: 100%; overflow: hidden; } diff --git a/frontend/public/css/bootstrap.min.css b/frontend/public/css/bootstrap.min.css new file mode 100644 index 00000000..92e3fe87 --- /dev/null +++ b/frontend/public/css/bootstrap.min.css @@ -0,0 +1,7 @@ +/*! + * Bootstrap v4.3.1 (https://getbootstrap.com/) + * Copyright 2011-2019 The Bootstrap Authors + * Copyright 2011-2019 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */:root{--blue:#007bff;--indigo:#6610f2;--purple:#6f42c1;--pink:#e83e8c;--red:#dc3545;--orange:#fd7e14;--yellow:#ffc107;--green:#28a745;--teal:#20c997;--cyan:#17a2b8;--white:#fff;--gray:#6c757d;--gray-dark:#343a40;--primary:#007bff;--secondary:#6c757d;--success:#28a745;--info:#17a2b8;--warning:#ffc107;--danger:#dc3545;--light:#f8f9fa;--dark:#343a40;--breakpoint-xs:0;--breakpoint-sm:576px;--breakpoint-md:768px;--breakpoint-lg:992px;--breakpoint-xl:1200px;--font-family-sans-serif:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg{overflow:hidden;vertical-align:middle}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}select{word-wrap:normal}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-bottom:.5rem;font-weight:500;line-height:1.2}.h1,h1{font-size:2.5rem}.h2,h2{font-size:2rem}.h3,h3{font-size:1.75rem}.h4,h4{font-size:1.5rem}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:6rem;font-weight:300;line-height:1.2}.display-2{font-size:5.5rem;font-weight:300;line-height:1.2}.display-3{font-size:4.5rem;font-weight:300;line-height:1.2}.display-4{font-size:3.5rem;font-weight:300;line-height:1.2}hr{margin-top:1rem;margin-bottom:1rem;border:0;border-top:1px solid rgba(0,0,0,.1)}.small,small{font-size:80%;font-weight:400}.mark,mark{padding:.2em;background-color:#fcf8e3}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:90%;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote-footer{display:block;font-size:80%;color:#6c757d}.blockquote-footer::before{content:"\2014\00A0"}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #dee2e6;border-radius:.25rem;max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:90%;color:#6c757d}code{font-size:87.5%;color:#e83e8c;word-break:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:87.5%;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:100%;font-weight:700}pre{display:block;font-size:87.5%;color:#212529}pre code{font-size:inherit;color:inherit;word-break:normal}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:576px){.container{max-width:540px}}@media (min-width:768px){.container{max-width:720px}}@media (min-width:992px){.container{max-width:960px}}@media (min-width:1200px){.container{max-width:1140px}}.container-fluid{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-15px;margin-left:-15px}.no-gutters{margin-right:0;margin-left:0}.no-gutters>.col,.no-gutters>[class*=col-]{padding-right:0;padding-left:0}.col,.col-1,.col-10,.col-11,.col-12,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-auto,.col-lg,.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-auto,.col-md,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-auto,.col-sm,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-auto,.col-xl,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-auto{position:relative;width:100%;padding-right:15px;padding-left:15px}.col{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:100%}.col-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-first{-ms-flex-order:-1;order:-1}.order-last{-ms-flex-order:13;order:13}.order-0{-ms-flex-order:0;order:0}.order-1{-ms-flex-order:1;order:1}.order-2{-ms-flex-order:2;order:2}.order-3{-ms-flex-order:3;order:3}.order-4{-ms-flex-order:4;order:4}.order-5{-ms-flex-order:5;order:5}.order-6{-ms-flex-order:6;order:6}.order-7{-ms-flex-order:7;order:7}.order-8{-ms-flex-order:8;order:8}.order-9{-ms-flex-order:9;order:9}.order-10{-ms-flex-order:10;order:10}.order-11{-ms-flex-order:11;order:11}.order-12{-ms-flex-order:12;order:12}.offset-1{margin-left:8.333333%}.offset-2{margin-left:16.666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.333333%}.offset-5{margin-left:41.666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.333333%}.offset-8{margin-left:66.666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.333333%}.offset-11{margin-left:91.666667%}@media (min-width:576px){.col-sm{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-sm-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:100%}.col-sm-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-sm-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-sm-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-sm-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-sm-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-sm-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-sm-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-sm-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-sm-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-sm-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-sm-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-sm-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-sm-first{-ms-flex-order:-1;order:-1}.order-sm-last{-ms-flex-order:13;order:13}.order-sm-0{-ms-flex-order:0;order:0}.order-sm-1{-ms-flex-order:1;order:1}.order-sm-2{-ms-flex-order:2;order:2}.order-sm-3{-ms-flex-order:3;order:3}.order-sm-4{-ms-flex-order:4;order:4}.order-sm-5{-ms-flex-order:5;order:5}.order-sm-6{-ms-flex-order:6;order:6}.order-sm-7{-ms-flex-order:7;order:7}.order-sm-8{-ms-flex-order:8;order:8}.order-sm-9{-ms-flex-order:9;order:9}.order-sm-10{-ms-flex-order:10;order:10}.order-sm-11{-ms-flex-order:11;order:11}.order-sm-12{-ms-flex-order:12;order:12}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.333333%}.offset-sm-2{margin-left:16.666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.333333%}.offset-sm-5{margin-left:41.666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.333333%}.offset-sm-8{margin-left:66.666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.333333%}.offset-sm-11{margin-left:91.666667%}}@media (min-width:768px){.col-md{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-md-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:100%}.col-md-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-md-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-md-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-md-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-md-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-md-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-md-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-md-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-md-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-md-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-md-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-md-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-md-first{-ms-flex-order:-1;order:-1}.order-md-last{-ms-flex-order:13;order:13}.order-md-0{-ms-flex-order:0;order:0}.order-md-1{-ms-flex-order:1;order:1}.order-md-2{-ms-flex-order:2;order:2}.order-md-3{-ms-flex-order:3;order:3}.order-md-4{-ms-flex-order:4;order:4}.order-md-5{-ms-flex-order:5;order:5}.order-md-6{-ms-flex-order:6;order:6}.order-md-7{-ms-flex-order:7;order:7}.order-md-8{-ms-flex-order:8;order:8}.order-md-9{-ms-flex-order:9;order:9}.order-md-10{-ms-flex-order:10;order:10}.order-md-11{-ms-flex-order:11;order:11}.order-md-12{-ms-flex-order:12;order:12}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.333333%}.offset-md-2{margin-left:16.666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.333333%}.offset-md-5{margin-left:41.666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.333333%}.offset-md-8{margin-left:66.666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.333333%}.offset-md-11{margin-left:91.666667%}}@media (min-width:992px){.col-lg{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-lg-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:100%}.col-lg-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-lg-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-lg-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-lg-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-lg-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-lg-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-lg-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-lg-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-lg-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-lg-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-lg-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-lg-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-lg-first{-ms-flex-order:-1;order:-1}.order-lg-last{-ms-flex-order:13;order:13}.order-lg-0{-ms-flex-order:0;order:0}.order-lg-1{-ms-flex-order:1;order:1}.order-lg-2{-ms-flex-order:2;order:2}.order-lg-3{-ms-flex-order:3;order:3}.order-lg-4{-ms-flex-order:4;order:4}.order-lg-5{-ms-flex-order:5;order:5}.order-lg-6{-ms-flex-order:6;order:6}.order-lg-7{-ms-flex-order:7;order:7}.order-lg-8{-ms-flex-order:8;order:8}.order-lg-9{-ms-flex-order:9;order:9}.order-lg-10{-ms-flex-order:10;order:10}.order-lg-11{-ms-flex-order:11;order:11}.order-lg-12{-ms-flex-order:12;order:12}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.333333%}.offset-lg-2{margin-left:16.666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.333333%}.offset-lg-5{margin-left:41.666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.333333%}.offset-lg-8{margin-left:66.666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.333333%}.offset-lg-11{margin-left:91.666667%}}@media (min-width:1200px){.col-xl{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-xl-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:100%}.col-xl-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-xl-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-xl-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-xl-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-xl-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-xl-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-xl-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-xl-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-xl-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-xl-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-xl-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-xl-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-xl-first{-ms-flex-order:-1;order:-1}.order-xl-last{-ms-flex-order:13;order:13}.order-xl-0{-ms-flex-order:0;order:0}.order-xl-1{-ms-flex-order:1;order:1}.order-xl-2{-ms-flex-order:2;order:2}.order-xl-3{-ms-flex-order:3;order:3}.order-xl-4{-ms-flex-order:4;order:4}.order-xl-5{-ms-flex-order:5;order:5}.order-xl-6{-ms-flex-order:6;order:6}.order-xl-7{-ms-flex-order:7;order:7}.order-xl-8{-ms-flex-order:8;order:8}.order-xl-9{-ms-flex-order:9;order:9}.order-xl-10{-ms-flex-order:10;order:10}.order-xl-11{-ms-flex-order:11;order:11}.order-xl-12{-ms-flex-order:12;order:12}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.333333%}.offset-xl-2{margin-left:16.666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.333333%}.offset-xl-5{margin-left:41.666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.333333%}.offset-xl-8{margin-left:66.666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.333333%}.offset-xl-11{margin-left:91.666667%}}.table{width:100%;margin-bottom:1rem;color:#212529}.table td,.table th{padding:.75rem;vertical-align:top;border-top:1px solid #dee2e6}.table thead th{vertical-align:bottom;border-bottom:2px solid #dee2e6}.table tbody+tbody{border-top:2px solid #dee2e6}.table-sm td,.table-sm th{padding:.3rem}.table-bordered{border:1px solid #dee2e6}.table-bordered td,.table-bordered th{border:1px solid #dee2e6}.table-bordered thead td,.table-bordered thead th{border-bottom-width:2px}.table-borderless tbody+tbody,.table-borderless td,.table-borderless th,.table-borderless thead th{border:0}.table-striped tbody tr:nth-of-type(odd){background-color:rgba(0,0,0,.05)}.table-hover tbody tr:hover{color:#212529;background-color:rgba(0,0,0,.075)}.table-primary,.table-primary>td,.table-primary>th{background-color:#b8daff}.table-primary tbody+tbody,.table-primary td,.table-primary th,.table-primary thead th{border-color:#7abaff}.table-hover .table-primary:hover{background-color:#9fcdff}.table-hover .table-primary:hover>td,.table-hover .table-primary:hover>th{background-color:#9fcdff}.table-secondary,.table-secondary>td,.table-secondary>th{background-color:#d6d8db}.table-secondary tbody+tbody,.table-secondary td,.table-secondary th,.table-secondary thead th{border-color:#b3b7bb}.table-hover .table-secondary:hover{background-color:#c8cbcf}.table-hover .table-secondary:hover>td,.table-hover .table-secondary:hover>th{background-color:#c8cbcf}.table-success,.table-success>td,.table-success>th{background-color:#c3e6cb}.table-success tbody+tbody,.table-success td,.table-success th,.table-success thead th{border-color:#8fd19e}.table-hover .table-success:hover{background-color:#b1dfbb}.table-hover .table-success:hover>td,.table-hover .table-success:hover>th{background-color:#b1dfbb}.table-info,.table-info>td,.table-info>th{background-color:#bee5eb}.table-info tbody+tbody,.table-info td,.table-info th,.table-info thead th{border-color:#86cfda}.table-hover .table-info:hover{background-color:#abdde5}.table-hover .table-info:hover>td,.table-hover .table-info:hover>th{background-color:#abdde5}.table-warning,.table-warning>td,.table-warning>th{background-color:#ffeeba}.table-warning tbody+tbody,.table-warning td,.table-warning th,.table-warning thead th{border-color:#ffdf7e}.table-hover .table-warning:hover{background-color:#ffe8a1}.table-hover .table-warning:hover>td,.table-hover .table-warning:hover>th{background-color:#ffe8a1}.table-danger,.table-danger>td,.table-danger>th{background-color:#f5c6cb}.table-danger tbody+tbody,.table-danger td,.table-danger th,.table-danger thead th{border-color:#ed969e}.table-hover .table-danger:hover{background-color:#f1b0b7}.table-hover .table-danger:hover>td,.table-hover .table-danger:hover>th{background-color:#f1b0b7}.table-light,.table-light>td,.table-light>th{background-color:#fdfdfe}.table-light tbody+tbody,.table-light td,.table-light th,.table-light thead th{border-color:#fbfcfc}.table-hover .table-light:hover{background-color:#ececf6}.table-hover .table-light:hover>td,.table-hover .table-light:hover>th{background-color:#ececf6}.table-dark,.table-dark>td,.table-dark>th{background-color:#c6c8ca}.table-dark tbody+tbody,.table-dark td,.table-dark th,.table-dark thead th{border-color:#95999c}.table-hover .table-dark:hover{background-color:#b9bbbe}.table-hover .table-dark:hover>td,.table-hover .table-dark:hover>th{background-color:#b9bbbe}.table-active,.table-active>td,.table-active>th{background-color:rgba(0,0,0,.075)}.table-hover .table-active:hover{background-color:rgba(0,0,0,.075)}.table-hover .table-active:hover>td,.table-hover .table-active:hover>th{background-color:rgba(0,0,0,.075)}.table .thead-dark th{color:#fff;background-color:#343a40;border-color:#454d55}.table .thead-light th{color:#495057;background-color:#e9ecef;border-color:#dee2e6}.table-dark{color:#fff;background-color:#343a40}.table-dark td,.table-dark th,.table-dark thead th{border-color:#454d55}.table-dark.table-bordered{border:0}.table-dark.table-striped tbody tr:nth-of-type(odd){background-color:rgba(255,255,255,.05)}.table-dark.table-hover tbody tr:hover{color:#fff;background-color:rgba(255,255,255,.075)}@media (max-width:575.98px){.table-responsive-sm{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-sm>.table-bordered{border:0}}@media (max-width:767.98px){.table-responsive-md{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-md>.table-bordered{border:0}}@media (max-width:991.98px){.table-responsive-lg{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-lg>.table-bordered{border:0}}@media (max-width:1199.98px){.table-responsive-xl{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-xl>.table-bordered{border:0}}.table-responsive{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive>.table-bordered{border:0}.form-control{display:block;width:100%;height:calc(1.5em + .75rem + 2px);padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#495057;background-color:#fff;background-clip:padding-box;border:1px solid #ced4da;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control{transition:none}}.form-control::-ms-expand{background-color:transparent;border:0}.form-control:focus{color:#495057;background-color:#fff;border-color:#80bdff;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.form-control::-webkit-input-placeholder{color:#6c757d;opacity:1}.form-control::-moz-placeholder{color:#6c757d;opacity:1}.form-control:-ms-input-placeholder{color:#6c757d;opacity:1}.form-control::-ms-input-placeholder{color:#6c757d;opacity:1}.form-control::placeholder{color:#6c757d;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#e9ecef;opacity:1}select.form-control:focus::-ms-value{color:#495057;background-color:#fff}.form-control-file,.form-control-range{display:block;width:100%}.col-form-label{padding-top:calc(.375rem + 1px);padding-bottom:calc(.375rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + 1px);padding-bottom:calc(.5rem + 1px);font-size:1.25rem;line-height:1.5}.col-form-label-sm{padding-top:calc(.25rem + 1px);padding-bottom:calc(.25rem + 1px);font-size:.875rem;line-height:1.5}.form-control-plaintext{display:block;width:100%;padding-top:.375rem;padding-bottom:.375rem;margin-bottom:0;line-height:1.5;color:#212529;background-color:transparent;border:solid transparent;border-width:1px 0}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm{padding-right:0;padding-left:0}.form-control-sm{height:calc(1.5em + .5rem + 2px);padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.form-control-lg{height:calc(1.5em + 1rem + 2px);padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}select.form-control[multiple],select.form-control[size]{height:auto}textarea.form-control{height:auto}.form-group{margin-bottom:1rem}.form-text{display:block;margin-top:.25rem}.form-row{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-5px;margin-left:-5px}.form-row>.col,.form-row>[class*=col-]{padding-right:5px;padding-left:5px}.form-check{position:relative;display:block;padding-left:1.25rem}.form-check-input{position:absolute;margin-top:.3rem;margin-left:-1.25rem}.form-check-input:disabled~.form-check-label{color:#6c757d}.form-check-label{margin-bottom:0}.form-check-inline{display:-ms-inline-flexbox;display:inline-flex;-ms-flex-align:center;align-items:center;padding-left:0;margin-right:.75rem}.form-check-inline .form-check-input{position:static;margin-top:0;margin-right:.3125rem;margin-left:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#28a745}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;line-height:1.5;color:#fff;background-color:rgba(40,167,69,.9);border-radius:.25rem}.form-control.is-valid,.was-validated .form-control:valid{border-color:#28a745;padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%2328a745' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:center right calc(.375em + .1875rem);background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-valid:focus,.was-validated .form-control:valid:focus{border-color:#28a745;box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.form-control.is-valid~.valid-feedback,.form-control.is-valid~.valid-tooltip,.was-validated .form-control:valid~.valid-feedback,.was-validated .form-control:valid~.valid-tooltip{display:block}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.custom-select.is-valid,.was-validated .custom-select:valid{border-color:#28a745;padding-right:calc((1em + .75rem) * 3 / 4 + 1.75rem);background:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right .75rem center/8px 10px,url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%2328a745' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e") #fff no-repeat center right 1.75rem/calc(.75em + .375rem) calc(.75em + .375rem)}.custom-select.is-valid:focus,.was-validated .custom-select:valid:focus{border-color:#28a745;box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.custom-select.is-valid~.valid-feedback,.custom-select.is-valid~.valid-tooltip,.was-validated .custom-select:valid~.valid-feedback,.was-validated .custom-select:valid~.valid-tooltip{display:block}.form-control-file.is-valid~.valid-feedback,.form-control-file.is-valid~.valid-tooltip,.was-validated .form-control-file:valid~.valid-feedback,.was-validated .form-control-file:valid~.valid-tooltip{display:block}.form-check-input.is-valid~.form-check-label,.was-validated .form-check-input:valid~.form-check-label{color:#28a745}.form-check-input.is-valid~.valid-feedback,.form-check-input.is-valid~.valid-tooltip,.was-validated .form-check-input:valid~.valid-feedback,.was-validated .form-check-input:valid~.valid-tooltip{display:block}.custom-control-input.is-valid~.custom-control-label,.was-validated .custom-control-input:valid~.custom-control-label{color:#28a745}.custom-control-input.is-valid~.custom-control-label::before,.was-validated .custom-control-input:valid~.custom-control-label::before{border-color:#28a745}.custom-control-input.is-valid~.valid-feedback,.custom-control-input.is-valid~.valid-tooltip,.was-validated .custom-control-input:valid~.valid-feedback,.was-validated .custom-control-input:valid~.valid-tooltip{display:block}.custom-control-input.is-valid:checked~.custom-control-label::before,.was-validated .custom-control-input:valid:checked~.custom-control-label::before{border-color:#34ce57;background-color:#34ce57}.custom-control-input.is-valid:focus~.custom-control-label::before,.was-validated .custom-control-input:valid:focus~.custom-control-label::before{box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.custom-control-input.is-valid:focus:not(:checked)~.custom-control-label::before,.was-validated .custom-control-input:valid:focus:not(:checked)~.custom-control-label::before{border-color:#28a745}.custom-file-input.is-valid~.custom-file-label,.was-validated .custom-file-input:valid~.custom-file-label{border-color:#28a745}.custom-file-input.is-valid~.valid-feedback,.custom-file-input.is-valid~.valid-tooltip,.was-validated .custom-file-input:valid~.valid-feedback,.was-validated .custom-file-input:valid~.valid-tooltip{display:block}.custom-file-input.is-valid:focus~.custom-file-label,.was-validated .custom-file-input:valid:focus~.custom-file-label{border-color:#28a745;box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#dc3545}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;line-height:1.5;color:#fff;background-color:rgba(220,53,69,.9);border-radius:.25rem}.form-control.is-invalid,.was-validated .form-control:invalid{border-color:#dc3545;padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23dc3545' viewBox='-2 -2 7 7'%3e%3cpath stroke='%23dc3545' d='M0 0l3 3m0-3L0 3'/%3e%3ccircle r='.5'/%3e%3ccircle cx='3' r='.5'/%3e%3ccircle cy='3' r='.5'/%3e%3ccircle cx='3' cy='3' r='.5'/%3e%3c/svg%3E");background-repeat:no-repeat;background-position:center right calc(.375em + .1875rem);background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-invalid:focus,.was-validated .form-control:invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.form-control.is-invalid~.invalid-feedback,.form-control.is-invalid~.invalid-tooltip,.was-validated .form-control:invalid~.invalid-feedback,.was-validated .form-control:invalid~.invalid-tooltip{display:block}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.custom-select.is-invalid,.was-validated .custom-select:invalid{border-color:#dc3545;padding-right:calc((1em + .75rem) * 3 / 4 + 1.75rem);background:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right .75rem center/8px 10px,url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23dc3545' viewBox='-2 -2 7 7'%3e%3cpath stroke='%23dc3545' d='M0 0l3 3m0-3L0 3'/%3e%3ccircle r='.5'/%3e%3ccircle cx='3' r='.5'/%3e%3ccircle cy='3' r='.5'/%3e%3ccircle cx='3' cy='3' r='.5'/%3e%3c/svg%3E") #fff no-repeat center right 1.75rem/calc(.75em + .375rem) calc(.75em + .375rem)}.custom-select.is-invalid:focus,.was-validated .custom-select:invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.custom-select.is-invalid~.invalid-feedback,.custom-select.is-invalid~.invalid-tooltip,.was-validated .custom-select:invalid~.invalid-feedback,.was-validated .custom-select:invalid~.invalid-tooltip{display:block}.form-control-file.is-invalid~.invalid-feedback,.form-control-file.is-invalid~.invalid-tooltip,.was-validated .form-control-file:invalid~.invalid-feedback,.was-validated .form-control-file:invalid~.invalid-tooltip{display:block}.form-check-input.is-invalid~.form-check-label,.was-validated .form-check-input:invalid~.form-check-label{color:#dc3545}.form-check-input.is-invalid~.invalid-feedback,.form-check-input.is-invalid~.invalid-tooltip,.was-validated .form-check-input:invalid~.invalid-feedback,.was-validated .form-check-input:invalid~.invalid-tooltip{display:block}.custom-control-input.is-invalid~.custom-control-label,.was-validated .custom-control-input:invalid~.custom-control-label{color:#dc3545}.custom-control-input.is-invalid~.custom-control-label::before,.was-validated .custom-control-input:invalid~.custom-control-label::before{border-color:#dc3545}.custom-control-input.is-invalid~.invalid-feedback,.custom-control-input.is-invalid~.invalid-tooltip,.was-validated .custom-control-input:invalid~.invalid-feedback,.was-validated .custom-control-input:invalid~.invalid-tooltip{display:block}.custom-control-input.is-invalid:checked~.custom-control-label::before,.was-validated .custom-control-input:invalid:checked~.custom-control-label::before{border-color:#e4606d;background-color:#e4606d}.custom-control-input.is-invalid:focus~.custom-control-label::before,.was-validated .custom-control-input:invalid:focus~.custom-control-label::before{box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.custom-control-input.is-invalid:focus:not(:checked)~.custom-control-label::before,.was-validated .custom-control-input:invalid:focus:not(:checked)~.custom-control-label::before{border-color:#dc3545}.custom-file-input.is-invalid~.custom-file-label,.was-validated .custom-file-input:invalid~.custom-file-label{border-color:#dc3545}.custom-file-input.is-invalid~.invalid-feedback,.custom-file-input.is-invalid~.invalid-tooltip,.was-validated .custom-file-input:invalid~.invalid-feedback,.was-validated .custom-file-input:invalid~.invalid-tooltip{display:block}.custom-file-input.is-invalid:focus~.custom-file-label,.was-validated .custom-file-input:invalid:focus~.custom-file-label{border-color:#dc3545;box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.form-inline{display:-ms-flexbox;display:flex;-ms-flex-flow:row wrap;flex-flow:row wrap;-ms-flex-align:center;align-items:center}.form-inline .form-check{width:100%}@media (min-width:576px){.form-inline label{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;margin-bottom:0}.form-inline .form-group{display:-ms-flexbox;display:flex;-ms-flex:0 0 auto;flex:0 0 auto;-ms-flex-flow:row wrap;flex-flow:row wrap;-ms-flex-align:center;align-items:center;margin-bottom:0}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-plaintext{display:inline-block}.form-inline .custom-select,.form-inline .input-group{width:auto}.form-inline .form-check{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:auto;padding-left:0}.form-inline .form-check-input{position:relative;-ms-flex-negative:0;flex-shrink:0;margin-top:0;margin-right:.25rem;margin-left:0}.form-inline .custom-control{-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center}.form-inline .custom-control-label{margin-bottom:0}}.btn{display:inline-block;font-weight:400;color:#212529;text-align:center;vertical-align:middle;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:transparent;border:1px solid transparent;padding:.375rem .75rem;font-size:1rem;line-height:1.5;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.btn{transition:none}}.btn:hover{color:#212529;text-decoration:none}.btn.focus,.btn:focus{outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.btn.disabled,.btn:disabled{opacity:.65}a.btn.disabled,fieldset:disabled a.btn{pointer-events:none}.btn-primary{color:#fff;background-color:#007bff;border-color:#007bff}.btn-primary:hover{color:#fff;background-color:#0069d9;border-color:#0062cc}.btn-primary.focus,.btn-primary:focus{box-shadow:0 0 0 .2rem rgba(38,143,255,.5)}.btn-primary.disabled,.btn-primary:disabled{color:#fff;background-color:#007bff;border-color:#007bff}.btn-primary:not(:disabled):not(.disabled).active,.btn-primary:not(:disabled):not(.disabled):active,.show>.btn-primary.dropdown-toggle{color:#fff;background-color:#0062cc;border-color:#005cbf}.btn-primary:not(:disabled):not(.disabled).active:focus,.btn-primary:not(:disabled):not(.disabled):active:focus,.show>.btn-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(38,143,255,.5)}.btn-secondary{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:hover{color:#fff;background-color:#5a6268;border-color:#545b62}.btn-secondary.focus,.btn-secondary:focus{box-shadow:0 0 0 .2rem rgba(130,138,145,.5)}.btn-secondary.disabled,.btn-secondary:disabled{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:not(:disabled):not(.disabled).active,.btn-secondary:not(:disabled):not(.disabled):active,.show>.btn-secondary.dropdown-toggle{color:#fff;background-color:#545b62;border-color:#4e555b}.btn-secondary:not(:disabled):not(.disabled).active:focus,.btn-secondary:not(:disabled):not(.disabled):active:focus,.show>.btn-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(130,138,145,.5)}.btn-success{color:#fff;background-color:#28a745;border-color:#28a745}.btn-success:hover{color:#fff;background-color:#218838;border-color:#1e7e34}.btn-success.focus,.btn-success:focus{box-shadow:0 0 0 .2rem rgba(72,180,97,.5)}.btn-success.disabled,.btn-success:disabled{color:#fff;background-color:#28a745;border-color:#28a745}.btn-success:not(:disabled):not(.disabled).active,.btn-success:not(:disabled):not(.disabled):active,.show>.btn-success.dropdown-toggle{color:#fff;background-color:#1e7e34;border-color:#1c7430}.btn-success:not(:disabled):not(.disabled).active:focus,.btn-success:not(:disabled):not(.disabled):active:focus,.show>.btn-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(72,180,97,.5)}.btn-info{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-info:hover{color:#fff;background-color:#138496;border-color:#117a8b}.btn-info.focus,.btn-info:focus{box-shadow:0 0 0 .2rem rgba(58,176,195,.5)}.btn-info.disabled,.btn-info:disabled{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-info:not(:disabled):not(.disabled).active,.btn-info:not(:disabled):not(.disabled):active,.show>.btn-info.dropdown-toggle{color:#fff;background-color:#117a8b;border-color:#10707f}.btn-info:not(:disabled):not(.disabled).active:focus,.btn-info:not(:disabled):not(.disabled):active:focus,.show>.btn-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(58,176,195,.5)}.btn-warning{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-warning:hover{color:#212529;background-color:#e0a800;border-color:#d39e00}.btn-warning.focus,.btn-warning:focus{box-shadow:0 0 0 .2rem rgba(222,170,12,.5)}.btn-warning.disabled,.btn-warning:disabled{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-warning:not(:disabled):not(.disabled).active,.btn-warning:not(:disabled):not(.disabled):active,.show>.btn-warning.dropdown-toggle{color:#212529;background-color:#d39e00;border-color:#c69500}.btn-warning:not(:disabled):not(.disabled).active:focus,.btn-warning:not(:disabled):not(.disabled):active:focus,.show>.btn-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(222,170,12,.5)}.btn-danger{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:hover{color:#fff;background-color:#c82333;border-color:#bd2130}.btn-danger.focus,.btn-danger:focus{box-shadow:0 0 0 .2rem rgba(225,83,97,.5)}.btn-danger.disabled,.btn-danger:disabled{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:not(:disabled):not(.disabled).active,.btn-danger:not(:disabled):not(.disabled):active,.show>.btn-danger.dropdown-toggle{color:#fff;background-color:#bd2130;border-color:#b21f2d}.btn-danger:not(:disabled):not(.disabled).active:focus,.btn-danger:not(:disabled):not(.disabled):active:focus,.show>.btn-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(225,83,97,.5)}.btn-light{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:hover{color:#212529;background-color:#e2e6ea;border-color:#dae0e5}.btn-light.focus,.btn-light:focus{box-shadow:0 0 0 .2rem rgba(216,217,219,.5)}.btn-light.disabled,.btn-light:disabled{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:not(:disabled):not(.disabled).active,.btn-light:not(:disabled):not(.disabled):active,.show>.btn-light.dropdown-toggle{color:#212529;background-color:#dae0e5;border-color:#d3d9df}.btn-light:not(:disabled):not(.disabled).active:focus,.btn-light:not(:disabled):not(.disabled):active:focus,.show>.btn-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(216,217,219,.5)}.btn-dark{color:#fff;background-color:#343a40;border-color:#343a40}.btn-dark:hover{color:#fff;background-color:#23272b;border-color:#1d2124}.btn-dark.focus,.btn-dark:focus{box-shadow:0 0 0 .2rem rgba(82,88,93,.5)}.btn-dark.disabled,.btn-dark:disabled{color:#fff;background-color:#343a40;border-color:#343a40}.btn-dark:not(:disabled):not(.disabled).active,.btn-dark:not(:disabled):not(.disabled):active,.show>.btn-dark.dropdown-toggle{color:#fff;background-color:#1d2124;border-color:#171a1d}.btn-dark:not(:disabled):not(.disabled).active:focus,.btn-dark:not(:disabled):not(.disabled):active:focus,.show>.btn-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(82,88,93,.5)}.btn-outline-primary{color:#007bff;border-color:#007bff}.btn-outline-primary:hover{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-primary.focus,.btn-outline-primary:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-outline-primary.disabled,.btn-outline-primary:disabled{color:#007bff;background-color:transparent}.btn-outline-primary:not(:disabled):not(.disabled).active,.btn-outline-primary:not(:disabled):not(.disabled):active,.show>.btn-outline-primary.dropdown-toggle{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-primary:not(:disabled):not(.disabled).active:focus,.btn-outline-primary:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-outline-secondary{color:#6c757d;border-color:#6c757d}.btn-outline-secondary:hover{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-outline-secondary.focus,.btn-outline-secondary:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-outline-secondary.disabled,.btn-outline-secondary:disabled{color:#6c757d;background-color:transparent}.btn-outline-secondary:not(:disabled):not(.disabled).active,.btn-outline-secondary:not(:disabled):not(.disabled):active,.show>.btn-outline-secondary.dropdown-toggle{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-outline-secondary:not(:disabled):not(.disabled).active:focus,.btn-outline-secondary:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-outline-success{color:#28a745;border-color:#28a745}.btn-outline-success:hover{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-success.focus,.btn-outline-success:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-outline-success.disabled,.btn-outline-success:disabled{color:#28a745;background-color:transparent}.btn-outline-success:not(:disabled):not(.disabled).active,.btn-outline-success:not(:disabled):not(.disabled):active,.show>.btn-outline-success.dropdown-toggle{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-success:not(:disabled):not(.disabled).active:focus,.btn-outline-success:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-outline-info{color:#17a2b8;border-color:#17a2b8}.btn-outline-info:hover{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-info.focus,.btn-outline-info:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-outline-info.disabled,.btn-outline-info:disabled{color:#17a2b8;background-color:transparent}.btn-outline-info:not(:disabled):not(.disabled).active,.btn-outline-info:not(:disabled):not(.disabled):active,.show>.btn-outline-info.dropdown-toggle{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-info:not(:disabled):not(.disabled).active:focus,.btn-outline-info:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-outline-warning{color:#ffc107;border-color:#ffc107}.btn-outline-warning:hover{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-outline-warning.focus,.btn-outline-warning:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-outline-warning.disabled,.btn-outline-warning:disabled{color:#ffc107;background-color:transparent}.btn-outline-warning:not(:disabled):not(.disabled).active,.btn-outline-warning:not(:disabled):not(.disabled):active,.show>.btn-outline-warning.dropdown-toggle{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-outline-warning:not(:disabled):not(.disabled).active:focus,.btn-outline-warning:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-outline-danger{color:#dc3545;border-color:#dc3545}.btn-outline-danger:hover{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-danger.focus,.btn-outline-danger:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-outline-danger.disabled,.btn-outline-danger:disabled{color:#dc3545;background-color:transparent}.btn-outline-danger:not(:disabled):not(.disabled).active,.btn-outline-danger:not(:disabled):not(.disabled):active,.show>.btn-outline-danger.dropdown-toggle{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-danger:not(:disabled):not(.disabled).active:focus,.btn-outline-danger:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-outline-light{color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light:hover{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light.focus,.btn-outline-light:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-outline-light.disabled,.btn-outline-light:disabled{color:#f8f9fa;background-color:transparent}.btn-outline-light:not(:disabled):not(.disabled).active,.btn-outline-light:not(:disabled):not(.disabled):active,.show>.btn-outline-light.dropdown-toggle{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light:not(:disabled):not(.disabled).active:focus,.btn-outline-light:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-outline-dark{color:#343a40;border-color:#343a40}.btn-outline-dark:hover{color:#fff;background-color:#343a40;border-color:#343a40}.btn-outline-dark.focus,.btn-outline-dark:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-outline-dark.disabled,.btn-outline-dark:disabled{color:#343a40;background-color:transparent}.btn-outline-dark:not(:disabled):not(.disabled).active,.btn-outline-dark:not(:disabled):not(.disabled):active,.show>.btn-outline-dark.dropdown-toggle{color:#fff;background-color:#343a40;border-color:#343a40}.btn-outline-dark:not(:disabled):not(.disabled).active:focus,.btn-outline-dark:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-link{font-weight:400;color:#007bff;text-decoration:none}.btn-link:hover{color:#0056b3;text-decoration:underline}.btn-link.focus,.btn-link:focus{text-decoration:underline;box-shadow:none}.btn-link.disabled,.btn-link:disabled{color:#6c757d;pointer-events:none}.btn-group-lg>.btn,.btn-lg{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.btn-group-sm>.btn,.btn-sm{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:.5rem}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{transition:opacity .15s linear}@media (prefers-reduced-motion:reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{position:relative;height:0;overflow:hidden;transition:height .35s ease}@media (prefers-reduced-motion:reduce){.collapsing{transition:none}}.dropdown,.dropleft,.dropright,.dropup{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:10rem;padding:.5rem 0;margin:.125rem 0 0;font-size:1rem;color:#212529;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.dropdown-menu-left{right:auto;left:0}.dropdown-menu-right{right:0;left:auto}@media (min-width:576px){.dropdown-menu-sm-left{right:auto;left:0}.dropdown-menu-sm-right{right:0;left:auto}}@media (min-width:768px){.dropdown-menu-md-left{right:auto;left:0}.dropdown-menu-md-right{right:0;left:auto}}@media (min-width:992px){.dropdown-menu-lg-left{right:auto;left:0}.dropdown-menu-lg-right{right:0;left:auto}}@media (min-width:1200px){.dropdown-menu-xl-left{right:auto;left:0}.dropdown-menu-xl-right{right:0;left:auto}}.dropup .dropdown-menu{top:auto;bottom:100%;margin-top:0;margin-bottom:.125rem}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-menu{top:0;right:auto;left:100%;margin-top:0;margin-left:.125rem}.dropright .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropright .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-toggle::after{vertical-align:0}.dropleft .dropdown-menu{top:0;right:100%;left:auto;margin-top:0;margin-right:.125rem}.dropleft .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropleft .dropdown-toggle::after{display:none}.dropleft .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropleft .dropdown-toggle:empty::after{margin-left:0}.dropleft .dropdown-toggle::before{vertical-align:0}.dropdown-menu[x-placement^=bottom],.dropdown-menu[x-placement^=left],.dropdown-menu[x-placement^=right],.dropdown-menu[x-placement^=top]{right:auto;bottom:auto}.dropdown-divider{height:0;margin:.5rem 0;overflow:hidden;border-top:1px solid #e9ecef}.dropdown-item{display:block;width:100%;padding:.25rem 1.5rem;clear:both;font-weight:400;color:#212529;text-align:inherit;white-space:nowrap;background-color:transparent;border:0}.dropdown-item:focus,.dropdown-item:hover{color:#16181b;text-decoration:none;background-color:#f8f9fa}.dropdown-item.active,.dropdown-item:active{color:#fff;text-decoration:none;background-color:#007bff}.dropdown-item.disabled,.dropdown-item:disabled{color:#6c757d;pointer-events:none;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:.5rem 1.5rem;margin-bottom:0;font-size:.875rem;color:#6c757d;white-space:nowrap}.dropdown-item-text{display:block;padding:.25rem 1.5rem;color:#212529}.btn-group,.btn-group-vertical{position:relative;display:-ms-inline-flexbox;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;-ms-flex:1 1 auto;flex:1 1 auto}.btn-group-vertical>.btn:hover,.btn-group>.btn:hover{z-index:1}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus{z-index:1}.btn-toolbar{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-pack:start;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn-group:not(:first-child),.btn-group>.btn:not(:first-child){margin-left:-1px}.btn-group>.btn-group:not(:last-child)>.btn,.btn-group>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:not(:first-child)>.btn,.btn-group>.btn:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after,.dropright .dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after{margin-left:0}.dropleft .dropdown-toggle-split::before{margin-right:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{-ms-flex-direction:column;flex-direction:column;-ms-flex-align:start;align-items:flex-start;-ms-flex-pack:center;justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn-group:not(:first-child),.btn-group-vertical>.btn:not(:first-child){margin-top:-1px}.btn-group-vertical>.btn-group:not(:last-child)>.btn,.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child)>.btn,.btn-group-vertical>.btn:not(:first-child){border-top-left-radius:0;border-top-right-radius:0}.btn-group-toggle>.btn,.btn-group-toggle>.btn-group>.btn{margin-bottom:0}.btn-group-toggle>.btn input[type=checkbox],.btn-group-toggle>.btn input[type=radio],.btn-group-toggle>.btn-group>.btn input[type=checkbox],.btn-group-toggle>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:stretch;align-items:stretch;width:100%}.input-group>.custom-file,.input-group>.custom-select,.input-group>.form-control,.input-group>.form-control-plaintext{position:relative;-ms-flex:1 1 auto;flex:1 1 auto;width:1%;margin-bottom:0}.input-group>.custom-file+.custom-file,.input-group>.custom-file+.custom-select,.input-group>.custom-file+.form-control,.input-group>.custom-select+.custom-file,.input-group>.custom-select+.custom-select,.input-group>.custom-select+.form-control,.input-group>.form-control+.custom-file,.input-group>.form-control+.custom-select,.input-group>.form-control+.form-control,.input-group>.form-control-plaintext+.custom-file,.input-group>.form-control-plaintext+.custom-select,.input-group>.form-control-plaintext+.form-control{margin-left:-1px}.input-group>.custom-file .custom-file-input:focus~.custom-file-label,.input-group>.custom-select:focus,.input-group>.form-control:focus{z-index:3}.input-group>.custom-file .custom-file-input:focus{z-index:4}.input-group>.custom-select:not(:last-child),.input-group>.form-control:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.custom-select:not(:first-child),.input-group>.form-control:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.custom-file{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center}.input-group>.custom-file:not(:last-child) .custom-file-label,.input-group>.custom-file:not(:last-child) .custom-file-label::after{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.custom-file:not(:first-child) .custom-file-label{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-append,.input-group-prepend{display:-ms-flexbox;display:flex}.input-group-append .btn,.input-group-prepend .btn{position:relative;z-index:2}.input-group-append .btn:focus,.input-group-prepend .btn:focus{z-index:3}.input-group-append .btn+.btn,.input-group-append .btn+.input-group-text,.input-group-append .input-group-text+.btn,.input-group-append .input-group-text+.input-group-text,.input-group-prepend .btn+.btn,.input-group-prepend .btn+.input-group-text,.input-group-prepend .input-group-text+.btn,.input-group-prepend .input-group-text+.input-group-text{margin-left:-1px}.input-group-prepend{margin-right:-1px}.input-group-append{margin-left:-1px}.input-group-text{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;padding:.375rem .75rem;margin-bottom:0;font-size:1rem;font-weight:400;line-height:1.5;color:#495057;text-align:center;white-space:nowrap;background-color:#e9ecef;border:1px solid #ced4da;border-radius:.25rem}.input-group-text input[type=checkbox],.input-group-text input[type=radio]{margin-top:0}.input-group-lg>.custom-select,.input-group-lg>.form-control:not(textarea){height:calc(1.5em + 1rem + 2px)}.input-group-lg>.custom-select,.input-group-lg>.form-control,.input-group-lg>.input-group-append>.btn,.input-group-lg>.input-group-append>.input-group-text,.input-group-lg>.input-group-prepend>.btn,.input-group-lg>.input-group-prepend>.input-group-text{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.input-group-sm>.custom-select,.input-group-sm>.form-control:not(textarea){height:calc(1.5em + .5rem + 2px)}.input-group-sm>.custom-select,.input-group-sm>.form-control,.input-group-sm>.input-group-append>.btn,.input-group-sm>.input-group-append>.input-group-text,.input-group-sm>.input-group-prepend>.btn,.input-group-sm>.input-group-prepend>.input-group-text{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.input-group-lg>.custom-select,.input-group-sm>.custom-select{padding-right:1.75rem}.input-group>.input-group-append:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group>.input-group-append:last-child>.input-group-text:not(:last-child),.input-group>.input-group-append:not(:last-child)>.btn,.input-group>.input-group-append:not(:last-child)>.input-group-text,.input-group>.input-group-prepend>.btn,.input-group>.input-group-prepend>.input-group-text{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.input-group-append>.btn,.input-group>.input-group-append>.input-group-text,.input-group>.input-group-prepend:first-child>.btn:not(:first-child),.input-group>.input-group-prepend:first-child>.input-group-text:not(:first-child),.input-group>.input-group-prepend:not(:first-child)>.btn,.input-group>.input-group-prepend:not(:first-child)>.input-group-text{border-top-left-radius:0;border-bottom-left-radius:0}.custom-control{position:relative;display:block;min-height:1.5rem;padding-left:1.5rem}.custom-control-inline{display:-ms-inline-flexbox;display:inline-flex;margin-right:1rem}.custom-control-input{position:absolute;z-index:-1;opacity:0}.custom-control-input:checked~.custom-control-label::before{color:#fff;border-color:#007bff;background-color:#007bff}.custom-control-input:focus~.custom-control-label::before{box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.custom-control-input:focus:not(:checked)~.custom-control-label::before{border-color:#80bdff}.custom-control-input:not(:disabled):active~.custom-control-label::before{color:#fff;background-color:#b3d7ff;border-color:#b3d7ff}.custom-control-input:disabled~.custom-control-label{color:#6c757d}.custom-control-input:disabled~.custom-control-label::before{background-color:#e9ecef}.custom-control-label{position:relative;margin-bottom:0;vertical-align:top}.custom-control-label::before{position:absolute;top:.25rem;left:-1.5rem;display:block;width:1rem;height:1rem;pointer-events:none;content:"";background-color:#fff;border:#adb5bd solid 1px}.custom-control-label::after{position:absolute;top:.25rem;left:-1.5rem;display:block;width:1rem;height:1rem;content:"";background:no-repeat 50%/50% 50%}.custom-checkbox .custom-control-label::before{border-radius:.25rem}.custom-checkbox .custom-control-input:checked~.custom-control-label::after{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3e%3c/svg%3e")}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::before{border-color:#007bff;background-color:#007bff}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::after{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 4'%3e%3cpath stroke='%23fff' d='M0 2h4'/%3e%3c/svg%3e")}.custom-checkbox .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-checkbox .custom-control-input:disabled:indeterminate~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-radio .custom-control-label::before{border-radius:50%}.custom-radio .custom-control-input:checked~.custom-control-label::after{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e")}.custom-radio .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-switch{padding-left:2.25rem}.custom-switch .custom-control-label::before{left:-2.25rem;width:1.75rem;pointer-events:all;border-radius:.5rem}.custom-switch .custom-control-label::after{top:calc(.25rem + 2px);left:calc(-2.25rem + 2px);width:calc(1rem - 4px);height:calc(1rem - 4px);background-color:#adb5bd;border-radius:.5rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out,-webkit-transform .15s ease-in-out;transition:transform .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:transform .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out,-webkit-transform .15s ease-in-out}@media (prefers-reduced-motion:reduce){.custom-switch .custom-control-label::after{transition:none}}.custom-switch .custom-control-input:checked~.custom-control-label::after{background-color:#fff;-webkit-transform:translateX(.75rem);transform:translateX(.75rem)}.custom-switch .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-select{display:inline-block;width:100%;height:calc(1.5em + .75rem + 2px);padding:.375rem 1.75rem .375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#495057;vertical-align:middle;background:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right .75rem center/8px 10px;background-color:#fff;border:1px solid #ced4da;border-radius:.25rem;-webkit-appearance:none;-moz-appearance:none;appearance:none}.custom-select:focus{border-color:#80bdff;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.custom-select:focus::-ms-value{color:#495057;background-color:#fff}.custom-select[multiple],.custom-select[size]:not([size="1"]){height:auto;padding-right:.75rem;background-image:none}.custom-select:disabled{color:#6c757d;background-color:#e9ecef}.custom-select::-ms-expand{display:none}.custom-select-sm{height:calc(1.5em + .5rem + 2px);padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:.875rem}.custom-select-lg{height:calc(1.5em + 1rem + 2px);padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem}.custom-file{position:relative;display:inline-block;width:100%;height:calc(1.5em + .75rem + 2px);margin-bottom:0}.custom-file-input{position:relative;z-index:2;width:100%;height:calc(1.5em + .75rem + 2px);margin:0;opacity:0}.custom-file-input:focus~.custom-file-label{border-color:#80bdff;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.custom-file-input:disabled~.custom-file-label{background-color:#e9ecef}.custom-file-input:lang(en)~.custom-file-label::after{content:"Browse"}.custom-file-input~.custom-file-label[data-browse]::after{content:attr(data-browse)}.custom-file-label{position:absolute;top:0;right:0;left:0;z-index:1;height:calc(1.5em + .75rem + 2px);padding:.375rem .75rem;font-weight:400;line-height:1.5;color:#495057;background-color:#fff;border:1px solid #ced4da;border-radius:.25rem}.custom-file-label::after{position:absolute;top:0;right:0;bottom:0;z-index:3;display:block;height:calc(1.5em + .75rem);padding:.375rem .75rem;line-height:1.5;color:#495057;content:"Browse";background-color:#e9ecef;border-left:inherit;border-radius:0 .25rem .25rem 0}.custom-range{width:100%;height:calc(1rem + .4rem);padding:0;background-color:transparent;-webkit-appearance:none;-moz-appearance:none;appearance:none}.custom-range:focus{outline:0}.custom-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-range:focus::-ms-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-range::-moz-focus-outer{border:0}.custom-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.25rem;background-color:#007bff;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-webkit-appearance:none;appearance:none}@media (prefers-reduced-motion:reduce){.custom-range::-webkit-slider-thumb{transition:none}}.custom-range::-webkit-slider-thumb:active{background-color:#b3d7ff}.custom-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.custom-range::-moz-range-thumb{width:1rem;height:1rem;background-color:#007bff;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-moz-appearance:none;appearance:none}@media (prefers-reduced-motion:reduce){.custom-range::-moz-range-thumb{transition:none}}.custom-range::-moz-range-thumb:active{background-color:#b3d7ff}.custom-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.custom-range::-ms-thumb{width:1rem;height:1rem;margin-top:0;margin-right:.2rem;margin-left:.2rem;background-color:#007bff;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;appearance:none}@media (prefers-reduced-motion:reduce){.custom-range::-ms-thumb{transition:none}}.custom-range::-ms-thumb:active{background-color:#b3d7ff}.custom-range::-ms-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:transparent;border-color:transparent;border-width:.5rem}.custom-range::-ms-fill-lower{background-color:#dee2e6;border-radius:1rem}.custom-range::-ms-fill-upper{margin-right:15px;background-color:#dee2e6;border-radius:1rem}.custom-range:disabled::-webkit-slider-thumb{background-color:#adb5bd}.custom-range:disabled::-webkit-slider-runnable-track{cursor:default}.custom-range:disabled::-moz-range-thumb{background-color:#adb5bd}.custom-range:disabled::-moz-range-track{cursor:default}.custom-range:disabled::-ms-thumb{background-color:#adb5bd}.custom-control-label::before,.custom-file-label,.custom-select{transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.custom-control-label::before,.custom-file-label,.custom-select{transition:none}}.nav{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:.5rem 1rem}.nav-link:focus,.nav-link:hover{text-decoration:none}.nav-link.disabled{color:#6c757d;pointer-events:none;cursor:default}.nav-tabs{border-bottom:1px solid #dee2e6}.nav-tabs .nav-item{margin-bottom:-1px}.nav-tabs .nav-link{border:1px solid transparent;border-top-left-radius:.25rem;border-top-right-radius:.25rem}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{border-color:#e9ecef #e9ecef #dee2e6}.nav-tabs .nav-link.disabled{color:#6c757d;background-color:transparent;border-color:transparent}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:#495057;background-color:#fff;border-color:#dee2e6 #dee2e6 #fff}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.nav-pills .nav-link{border-radius:.25rem}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:#fff;background-color:#007bff}.nav-fill .nav-item{-ms-flex:1 1 auto;flex:1 1 auto;text-align:center}.nav-justified .nav-item{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;text-align:center}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between;padding:.5rem 1rem}.navbar>.container,.navbar>.container-fluid{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between}.navbar-brand{display:inline-block;padding-top:.3125rem;padding-bottom:.3125rem;margin-right:1rem;font-size:1.25rem;line-height:inherit;white-space:nowrap}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-nav{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0;padding-left:0}.navbar-nav .dropdown-menu{position:static;float:none}.navbar-text{display:inline-block;padding-top:.5rem;padding-bottom:.5rem}.navbar-collapse{-ms-flex-preferred-size:100%;flex-basis:100%;-ms-flex-positive:1;flex-grow:1;-ms-flex-align:center;align-items:center}.navbar-toggler{padding:.25rem .75rem;font-size:1.25rem;line-height:1;background-color:transparent;border:1px solid transparent;border-radius:.25rem}.navbar-toggler:focus,.navbar-toggler:hover{text-decoration:none}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;content:"";background:no-repeat center center;background-size:100% 100%}@media (max-width:575.98px){.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:576px){.navbar-expand-sm{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-sm .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-sm .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}}@media (max-width:767.98px){.navbar-expand-md>.container,.navbar-expand-md>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:768px){.navbar-expand-md{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-md .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-md>.container,.navbar-expand-md>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-md .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}}@media (max-width:991.98px){.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:992px){.navbar-expand-lg{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-lg .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-lg .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}}@media (max-width:1199.98px){.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:1200px){.navbar-expand-xl{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-xl .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-xl .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}}.navbar-expand{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand>.container,.navbar-expand>.container-fluid{padding-right:0;padding-left:0}.navbar-expand .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand>.container,.navbar-expand>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-light .navbar-brand{color:rgba(0,0,0,.9)}.navbar-light .navbar-brand:focus,.navbar-light .navbar-brand:hover{color:rgba(0,0,0,.9)}.navbar-light .navbar-nav .nav-link{color:rgba(0,0,0,.5)}.navbar-light .navbar-nav .nav-link:focus,.navbar-light .navbar-nav .nav-link:hover{color:rgba(0,0,0,.7)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(0,0,0,.3)}.navbar-light .navbar-nav .active>.nav-link,.navbar-light .navbar-nav .nav-link.active,.navbar-light .navbar-nav .nav-link.show,.navbar-light .navbar-nav .show>.nav-link{color:rgba(0,0,0,.9)}.navbar-light .navbar-toggler{color:rgba(0,0,0,.5);border-color:rgba(0,0,0,.1)}.navbar-light .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3e%3cpath stroke='rgba(0, 0, 0, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-light .navbar-text{color:rgba(0,0,0,.5)}.navbar-light .navbar-text a{color:rgba(0,0,0,.9)}.navbar-light .navbar-text a:focus,.navbar-light .navbar-text a:hover{color:rgba(0,0,0,.9)}.navbar-dark .navbar-brand{color:#fff}.navbar-dark .navbar-brand:focus,.navbar-dark .navbar-brand:hover{color:#fff}.navbar-dark .navbar-nav .nav-link{color:rgba(255,255,255,.5)}.navbar-dark .navbar-nav .nav-link:focus,.navbar-dark .navbar-nav .nav-link:hover{color:rgba(255,255,255,.75)}.navbar-dark .navbar-nav .nav-link.disabled{color:rgba(255,255,255,.25)}.navbar-dark .navbar-nav .active>.nav-link,.navbar-dark .navbar-nav .nav-link.active,.navbar-dark .navbar-nav .nav-link.show,.navbar-dark .navbar-nav .show>.nav-link{color:#fff}.navbar-dark .navbar-toggler{color:rgba(255,255,255,.5);border-color:rgba(255,255,255,.1)}.navbar-dark .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3e%3cpath stroke='rgba(255, 255, 255, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-dark .navbar-text{color:rgba(255,255,255,.5)}.navbar-dark .navbar-text a{color:#fff}.navbar-dark .navbar-text a:focus,.navbar-dark .navbar-text a:hover{color:#fff}.card{position:relative;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;min-width:0;word-wrap:break-word;background-color:#fff;background-clip:border-box;border:1px solid rgba(0,0,0,.125);border-radius:.25rem}.card>hr{margin-right:0;margin-left:0}.card>.list-group:first-child .list-group-item:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card>.list-group:last-child .list-group-item:last-child{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.card-body{-ms-flex:1 1 auto;flex:1 1 auto;padding:1.25rem}.card-title{margin-bottom:.75rem}.card-subtitle{margin-top:-.375rem;margin-bottom:0}.card-text:last-child{margin-bottom:0}.card-link:hover{text-decoration:none}.card-link+.card-link{margin-left:1.25rem}.card-header{padding:.75rem 1.25rem;margin-bottom:0;background-color:rgba(0,0,0,.03);border-bottom:1px solid rgba(0,0,0,.125)}.card-header:first-child{border-radius:calc(.25rem - 1px) calc(.25rem - 1px) 0 0}.card-header+.list-group .list-group-item:first-child{border-top:0}.card-footer{padding:.75rem 1.25rem;background-color:rgba(0,0,0,.03);border-top:1px solid rgba(0,0,0,.125)}.card-footer:last-child{border-radius:0 0 calc(.25rem - 1px) calc(.25rem - 1px)}.card-header-tabs{margin-right:-.625rem;margin-bottom:-.75rem;margin-left:-.625rem;border-bottom:0}.card-header-pills{margin-right:-.625rem;margin-left:-.625rem}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1.25rem}.card-img{width:100%;border-radius:calc(.25rem - 1px)}.card-img-top{width:100%;border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card-img-bottom{width:100%;border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card-deck{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column}.card-deck .card{margin-bottom:15px}@media (min-width:576px){.card-deck{-ms-flex-flow:row wrap;flex-flow:row wrap;margin-right:-15px;margin-left:-15px}.card-deck .card{display:-ms-flexbox;display:flex;-ms-flex:1 0 0%;flex:1 0 0%;-ms-flex-direction:column;flex-direction:column;margin-right:15px;margin-bottom:0;margin-left:15px}}.card-group{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column}.card-group>.card{margin-bottom:15px}@media (min-width:576px){.card-group{-ms-flex-flow:row wrap;flex-flow:row wrap}.card-group>.card{-ms-flex:1 0 0%;flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:not(:last-child) .card-header,.card-group>.card:not(:last-child) .card-img-top{border-top-right-radius:0}.card-group>.card:not(:last-child) .card-footer,.card-group>.card:not(:last-child) .card-img-bottom{border-bottom-right-radius:0}.card-group>.card:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:not(:first-child) .card-header,.card-group>.card:not(:first-child) .card-img-top{border-top-left-radius:0}.card-group>.card:not(:first-child) .card-footer,.card-group>.card:not(:first-child) .card-img-bottom{border-bottom-left-radius:0}}.card-columns .card{margin-bottom:.75rem}@media (min-width:576px){.card-columns{-webkit-column-count:3;-moz-column-count:3;column-count:3;-webkit-column-gap:1.25rem;-moz-column-gap:1.25rem;column-gap:1.25rem;orphans:1;widows:1}.card-columns .card{display:inline-block;width:100%}}.accordion>.card{overflow:hidden}.accordion>.card:not(:first-of-type) .card-header:first-child{border-radius:0}.accordion>.card:not(:first-of-type):not(:last-of-type){border-bottom:0;border-radius:0}.accordion>.card:first-of-type{border-bottom:0;border-bottom-right-radius:0;border-bottom-left-radius:0}.accordion>.card:last-of-type{border-top-left-radius:0;border-top-right-radius:0}.accordion>.card .card-header{margin-bottom:-1px}.breadcrumb{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;padding:.75rem 1rem;margin-bottom:1rem;list-style:none;background-color:#e9ecef;border-radius:.25rem}.breadcrumb-item+.breadcrumb-item{padding-left:.5rem}.breadcrumb-item+.breadcrumb-item::before{display:inline-block;padding-right:.5rem;color:#6c757d;content:"/"}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:underline}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:none}.breadcrumb-item.active{color:#6c757d}.pagination{display:-ms-flexbox;display:flex;padding-left:0;list-style:none;border-radius:.25rem}.page-link{position:relative;display:block;padding:.5rem .75rem;margin-left:-1px;line-height:1.25;color:#007bff;background-color:#fff;border:1px solid #dee2e6}.page-link:hover{z-index:2;color:#0056b3;text-decoration:none;background-color:#e9ecef;border-color:#dee2e6}.page-link:focus{z-index:2;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.page-item:first-child .page-link{margin-left:0;border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.page-item:last-child .page-link{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.page-item.active .page-link{z-index:1;color:#fff;background-color:#007bff;border-color:#007bff}.page-item.disabled .page-link{color:#6c757d;pointer-events:none;cursor:auto;background-color:#fff;border-color:#dee2e6}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem;line-height:1.5}.pagination-lg .page-item:first-child .page-link{border-top-left-radius:.3rem;border-bottom-left-radius:.3rem}.pagination-lg .page-item:last-child .page-link{border-top-right-radius:.3rem;border-bottom-right-radius:.3rem}.pagination-sm .page-link{padding:.25rem .5rem;font-size:.875rem;line-height:1.5}.pagination-sm .page-item:first-child .page-link{border-top-left-radius:.2rem;border-bottom-left-radius:.2rem}.pagination-sm .page-item:last-child .page-link{border-top-right-radius:.2rem;border-bottom-right-radius:.2rem}.badge{display:inline-block;padding:.25em .4em;font-size:75%;font-weight:700;line-height:1;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.badge{transition:none}}a.badge:focus,a.badge:hover{text-decoration:none}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.badge-pill{padding-right:.6em;padding-left:.6em;border-radius:10rem}.badge-primary{color:#fff;background-color:#007bff}a.badge-primary:focus,a.badge-primary:hover{color:#fff;background-color:#0062cc}a.badge-primary.focus,a.badge-primary:focus{outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.badge-secondary{color:#fff;background-color:#6c757d}a.badge-secondary:focus,a.badge-secondary:hover{color:#fff;background-color:#545b62}a.badge-secondary.focus,a.badge-secondary:focus{outline:0;box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.badge-success{color:#fff;background-color:#28a745}a.badge-success:focus,a.badge-success:hover{color:#fff;background-color:#1e7e34}a.badge-success.focus,a.badge-success:focus{outline:0;box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.badge-info{color:#fff;background-color:#17a2b8}a.badge-info:focus,a.badge-info:hover{color:#fff;background-color:#117a8b}a.badge-info.focus,a.badge-info:focus{outline:0;box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.badge-warning{color:#212529;background-color:#ffc107}a.badge-warning:focus,a.badge-warning:hover{color:#212529;background-color:#d39e00}a.badge-warning.focus,a.badge-warning:focus{outline:0;box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.badge-danger{color:#fff;background-color:#dc3545}a.badge-danger:focus,a.badge-danger:hover{color:#fff;background-color:#bd2130}a.badge-danger.focus,a.badge-danger:focus{outline:0;box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.badge-light{color:#212529;background-color:#f8f9fa}a.badge-light:focus,a.badge-light:hover{color:#212529;background-color:#dae0e5}a.badge-light.focus,a.badge-light:focus{outline:0;box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.badge-dark{color:#fff;background-color:#343a40}a.badge-dark:focus,a.badge-dark:hover{color:#fff;background-color:#1d2124}a.badge-dark.focus,a.badge-dark:focus{outline:0;box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.jumbotron{padding:2rem 1rem;margin-bottom:2rem;background-color:#e9ecef;border-radius:.3rem}@media (min-width:576px){.jumbotron{padding:4rem 2rem}}.jumbotron-fluid{padding-right:0;padding-left:0;border-radius:0}.alert{position:relative;padding:.75rem 1.25rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible{padding-right:4rem}.alert-dismissible .close{position:absolute;top:0;right:0;padding:.75rem 1.25rem;color:inherit}.alert-primary{color:#004085;background-color:#cce5ff;border-color:#b8daff}.alert-primary hr{border-top-color:#9fcdff}.alert-primary .alert-link{color:#002752}.alert-secondary{color:#383d41;background-color:#e2e3e5;border-color:#d6d8db}.alert-secondary hr{border-top-color:#c8cbcf}.alert-secondary .alert-link{color:#202326}.alert-success{color:#155724;background-color:#d4edda;border-color:#c3e6cb}.alert-success hr{border-top-color:#b1dfbb}.alert-success .alert-link{color:#0b2e13}.alert-info{color:#0c5460;background-color:#d1ecf1;border-color:#bee5eb}.alert-info hr{border-top-color:#abdde5}.alert-info .alert-link{color:#062c33}.alert-warning{color:#856404;background-color:#fff3cd;border-color:#ffeeba}.alert-warning hr{border-top-color:#ffe8a1}.alert-warning .alert-link{color:#533f03}.alert-danger{color:#721c24;background-color:#f8d7da;border-color:#f5c6cb}.alert-danger hr{border-top-color:#f1b0b7}.alert-danger .alert-link{color:#491217}.alert-light{color:#818182;background-color:#fefefe;border-color:#fdfdfe}.alert-light hr{border-top-color:#ececf6}.alert-light .alert-link{color:#686868}.alert-dark{color:#1b1e21;background-color:#d6d8d9;border-color:#c6c8ca}.alert-dark hr{border-top-color:#b9bbbe}.alert-dark .alert-link{color:#040505}@-webkit-keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}.progress{display:-ms-flexbox;display:flex;height:1rem;overflow:hidden;font-size:.75rem;background-color:#e9ecef;border-radius:.25rem}.progress-bar{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;-ms-flex-pack:center;justify-content:center;color:#fff;text-align:center;white-space:nowrap;background-color:#007bff;transition:width .6s ease}@media (prefers-reduced-motion:reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:1rem 1rem}.progress-bar-animated{-webkit-animation:progress-bar-stripes 1s linear infinite;animation:progress-bar-stripes 1s linear infinite}@media (prefers-reduced-motion:reduce){.progress-bar-animated{-webkit-animation:none;animation:none}}.media{display:-ms-flexbox;display:flex;-ms-flex-align:start;align-items:flex-start}.media-body{-ms-flex:1;flex:1}.list-group{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;padding-left:0;margin-bottom:0}.list-group-item-action{width:100%;color:#495057;text-align:inherit}.list-group-item-action:focus,.list-group-item-action:hover{z-index:1;color:#495057;text-decoration:none;background-color:#f8f9fa}.list-group-item-action:active{color:#212529;background-color:#e9ecef}.list-group-item{position:relative;display:block;padding:.75rem 1.25rem;margin-bottom:-1px;background-color:#fff;border:1px solid rgba(0,0,0,.125)}.list-group-item:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.list-group-item.disabled,.list-group-item:disabled{color:#6c757d;pointer-events:none;background-color:#fff}.list-group-item.active{z-index:2;color:#fff;background-color:#007bff;border-color:#007bff}.list-group-horizontal{-ms-flex-direction:row;flex-direction:row}.list-group-horizontal .list-group-item{margin-right:-1px;margin-bottom:0}.list-group-horizontal .list-group-item:first-child{border-top-left-radius:.25rem;border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal .list-group-item:last-child{margin-right:0;border-top-right-radius:.25rem;border-bottom-right-radius:.25rem;border-bottom-left-radius:0}@media (min-width:576px){.list-group-horizontal-sm{-ms-flex-direction:row;flex-direction:row}.list-group-horizontal-sm .list-group-item{margin-right:-1px;margin-bottom:0}.list-group-horizontal-sm .list-group-item:first-child{border-top-left-radius:.25rem;border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-sm .list-group-item:last-child{margin-right:0;border-top-right-radius:.25rem;border-bottom-right-radius:.25rem;border-bottom-left-radius:0}}@media (min-width:768px){.list-group-horizontal-md{-ms-flex-direction:row;flex-direction:row}.list-group-horizontal-md .list-group-item{margin-right:-1px;margin-bottom:0}.list-group-horizontal-md .list-group-item:first-child{border-top-left-radius:.25rem;border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-md .list-group-item:last-child{margin-right:0;border-top-right-radius:.25rem;border-bottom-right-radius:.25rem;border-bottom-left-radius:0}}@media (min-width:992px){.list-group-horizontal-lg{-ms-flex-direction:row;flex-direction:row}.list-group-horizontal-lg .list-group-item{margin-right:-1px;margin-bottom:0}.list-group-horizontal-lg .list-group-item:first-child{border-top-left-radius:.25rem;border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-lg .list-group-item:last-child{margin-right:0;border-top-right-radius:.25rem;border-bottom-right-radius:.25rem;border-bottom-left-radius:0}}@media (min-width:1200px){.list-group-horizontal-xl{-ms-flex-direction:row;flex-direction:row}.list-group-horizontal-xl .list-group-item{margin-right:-1px;margin-bottom:0}.list-group-horizontal-xl .list-group-item:first-child{border-top-left-radius:.25rem;border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-xl .list-group-item:last-child{margin-right:0;border-top-right-radius:.25rem;border-bottom-right-radius:.25rem;border-bottom-left-radius:0}}.list-group-flush .list-group-item{border-right:0;border-left:0;border-radius:0}.list-group-flush .list-group-item:last-child{margin-bottom:-1px}.list-group-flush:first-child .list-group-item:first-child{border-top:0}.list-group-flush:last-child .list-group-item:last-child{margin-bottom:0;border-bottom:0}.list-group-item-primary{color:#004085;background-color:#b8daff}.list-group-item-primary.list-group-item-action:focus,.list-group-item-primary.list-group-item-action:hover{color:#004085;background-color:#9fcdff}.list-group-item-primary.list-group-item-action.active{color:#fff;background-color:#004085;border-color:#004085}.list-group-item-secondary{color:#383d41;background-color:#d6d8db}.list-group-item-secondary.list-group-item-action:focus,.list-group-item-secondary.list-group-item-action:hover{color:#383d41;background-color:#c8cbcf}.list-group-item-secondary.list-group-item-action.active{color:#fff;background-color:#383d41;border-color:#383d41}.list-group-item-success{color:#155724;background-color:#c3e6cb}.list-group-item-success.list-group-item-action:focus,.list-group-item-success.list-group-item-action:hover{color:#155724;background-color:#b1dfbb}.list-group-item-success.list-group-item-action.active{color:#fff;background-color:#155724;border-color:#155724}.list-group-item-info{color:#0c5460;background-color:#bee5eb}.list-group-item-info.list-group-item-action:focus,.list-group-item-info.list-group-item-action:hover{color:#0c5460;background-color:#abdde5}.list-group-item-info.list-group-item-action.active{color:#fff;background-color:#0c5460;border-color:#0c5460}.list-group-item-warning{color:#856404;background-color:#ffeeba}.list-group-item-warning.list-group-item-action:focus,.list-group-item-warning.list-group-item-action:hover{color:#856404;background-color:#ffe8a1}.list-group-item-warning.list-group-item-action.active{color:#fff;background-color:#856404;border-color:#856404}.list-group-item-danger{color:#721c24;background-color:#f5c6cb}.list-group-item-danger.list-group-item-action:focus,.list-group-item-danger.list-group-item-action:hover{color:#721c24;background-color:#f1b0b7}.list-group-item-danger.list-group-item-action.active{color:#fff;background-color:#721c24;border-color:#721c24}.list-group-item-light{color:#818182;background-color:#fdfdfe}.list-group-item-light.list-group-item-action:focus,.list-group-item-light.list-group-item-action:hover{color:#818182;background-color:#ececf6}.list-group-item-light.list-group-item-action.active{color:#fff;background-color:#818182;border-color:#818182}.list-group-item-dark{color:#1b1e21;background-color:#c6c8ca}.list-group-item-dark.list-group-item-action:focus,.list-group-item-dark.list-group-item-action:hover{color:#1b1e21;background-color:#b9bbbe}.list-group-item-dark.list-group-item-action.active{color:#fff;background-color:#1b1e21;border-color:#1b1e21}.close{float:right;font-size:1.5rem;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.5}.close:hover{color:#000;text-decoration:none}.close:not(:disabled):not(.disabled):focus,.close:not(:disabled):not(.disabled):hover{opacity:.75}button.close{padding:0;background-color:transparent;border:0;-webkit-appearance:none;-moz-appearance:none;appearance:none}a.close.disabled{pointer-events:none}.toast{max-width:350px;overflow:hidden;font-size:.875rem;background-color:rgba(255,255,255,.85);background-clip:padding-box;border:1px solid rgba(0,0,0,.1);box-shadow:0 .25rem .75rem rgba(0,0,0,.1);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);opacity:0;border-radius:.25rem}.toast:not(:last-child){margin-bottom:.75rem}.toast.showing{opacity:1}.toast.show{display:block;opacity:1}.toast.hide{display:none}.toast-header{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;padding:.25rem .75rem;color:#6c757d;background-color:rgba(255,255,255,.85);background-clip:padding-box;border-bottom:1px solid rgba(0,0,0,.05)}.toast-body{padding:.75rem}.modal-open{overflow:hidden}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal{position:fixed;top:0;left:0;z-index:1050;display:none;width:100%;height:100%;overflow:hidden;outline:0}.modal-dialog{position:relative;width:auto;margin:.5rem;pointer-events:none}.modal.fade .modal-dialog{transition:-webkit-transform .3s ease-out;transition:transform .3s ease-out;transition:transform .3s ease-out,-webkit-transform .3s ease-out;-webkit-transform:translate(0,-50px);transform:translate(0,-50px)}@media (prefers-reduced-motion:reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{-webkit-transform:none;transform:none}.modal-dialog-scrollable{display:-ms-flexbox;display:flex;max-height:calc(100% - 1rem)}.modal-dialog-scrollable .modal-content{max-height:calc(100vh - 1rem);overflow:hidden}.modal-dialog-scrollable .modal-footer,.modal-dialog-scrollable .modal-header{-ms-flex-negative:0;flex-shrink:0}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;min-height:calc(100% - 1rem)}.modal-dialog-centered::before{display:block;height:calc(100vh - 1rem);content:""}.modal-dialog-centered.modal-dialog-scrollable{-ms-flex-direction:column;flex-direction:column;-ms-flex-pack:center;justify-content:center;height:100%}.modal-dialog-centered.modal-dialog-scrollable .modal-content{max-height:none}.modal-dialog-centered.modal-dialog-scrollable::before{content:none}.modal-content{position:relative;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;width:100%;pointer-events:auto;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem;outline:0}.modal-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.5}.modal-header{display:-ms-flexbox;display:flex;-ms-flex-align:start;align-items:flex-start;-ms-flex-pack:justify;justify-content:space-between;padding:1rem 1rem;border-bottom:1px solid #dee2e6;border-top-left-radius:.3rem;border-top-right-radius:.3rem}.modal-header .close{padding:1rem 1rem;margin:-1rem -1rem -1rem auto}.modal-title{margin-bottom:0;line-height:1.5}.modal-body{position:relative;-ms-flex:1 1 auto;flex:1 1 auto;padding:1rem}.modal-footer{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:end;justify-content:flex-end;padding:1rem;border-top:1px solid #dee2e6;border-bottom-right-radius:.3rem;border-bottom-left-radius:.3rem}.modal-footer>:not(:first-child){margin-left:.25rem}.modal-footer>:not(:last-child){margin-right:.25rem}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:576px){.modal-dialog{max-width:500px;margin:1.75rem auto}.modal-dialog-scrollable{max-height:calc(100% - 3.5rem)}.modal-dialog-scrollable .modal-content{max-height:calc(100vh - 3.5rem)}.modal-dialog-centered{min-height:calc(100% - 3.5rem)}.modal-dialog-centered::before{height:calc(100vh - 3.5rem)}.modal-sm{max-width:300px}}@media (min-width:992px){.modal-lg,.modal-xl{max-width:800px}}@media (min-width:1200px){.modal-xl{max-width:1140px}}.tooltip{position:absolute;z-index:1070;display:block;margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;opacity:0}.tooltip.show{opacity:.9}.tooltip .arrow{position:absolute;display:block;width:.8rem;height:.4rem}.tooltip .arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-auto[x-placement^=top],.bs-tooltip-top{padding:.4rem 0}.bs-tooltip-auto[x-placement^=top] .arrow,.bs-tooltip-top .arrow{bottom:0}.bs-tooltip-auto[x-placement^=top] .arrow::before,.bs-tooltip-top .arrow::before{top:0;border-width:.4rem .4rem 0;border-top-color:#000}.bs-tooltip-auto[x-placement^=right],.bs-tooltip-right{padding:0 .4rem}.bs-tooltip-auto[x-placement^=right] .arrow,.bs-tooltip-right .arrow{left:0;width:.4rem;height:.8rem}.bs-tooltip-auto[x-placement^=right] .arrow::before,.bs-tooltip-right .arrow::before{right:0;border-width:.4rem .4rem .4rem 0;border-right-color:#000}.bs-tooltip-auto[x-placement^=bottom],.bs-tooltip-bottom{padding:.4rem 0}.bs-tooltip-auto[x-placement^=bottom] .arrow,.bs-tooltip-bottom .arrow{top:0}.bs-tooltip-auto[x-placement^=bottom] .arrow::before,.bs-tooltip-bottom .arrow::before{bottom:0;border-width:0 .4rem .4rem;border-bottom-color:#000}.bs-tooltip-auto[x-placement^=left],.bs-tooltip-left{padding:0 .4rem}.bs-tooltip-auto[x-placement^=left] .arrow,.bs-tooltip-left .arrow{right:0;width:.4rem;height:.8rem}.bs-tooltip-auto[x-placement^=left] .arrow::before,.bs-tooltip-left .arrow::before{left:0;border-width:.4rem 0 .4rem .4rem;border-left-color:#000}.tooltip-inner{max-width:200px;padding:.25rem .5rem;color:#fff;text-align:center;background-color:#000;border-radius:.25rem}.popover{position:absolute;top:0;left:0;z-index:1060;display:block;max-width:276px;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem}.popover .arrow{position:absolute;display:block;width:1rem;height:.5rem;margin:0 .3rem}.popover .arrow::after,.popover .arrow::before{position:absolute;display:block;content:"";border-color:transparent;border-style:solid}.bs-popover-auto[x-placement^=top],.bs-popover-top{margin-bottom:.5rem}.bs-popover-auto[x-placement^=top]>.arrow,.bs-popover-top>.arrow{bottom:calc((.5rem + 1px) * -1)}.bs-popover-auto[x-placement^=top]>.arrow::before,.bs-popover-top>.arrow::before{bottom:0;border-width:.5rem .5rem 0;border-top-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=top]>.arrow::after,.bs-popover-top>.arrow::after{bottom:1px;border-width:.5rem .5rem 0;border-top-color:#fff}.bs-popover-auto[x-placement^=right],.bs-popover-right{margin-left:.5rem}.bs-popover-auto[x-placement^=right]>.arrow,.bs-popover-right>.arrow{left:calc((.5rem + 1px) * -1);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-auto[x-placement^=right]>.arrow::before,.bs-popover-right>.arrow::before{left:0;border-width:.5rem .5rem .5rem 0;border-right-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=right]>.arrow::after,.bs-popover-right>.arrow::after{left:1px;border-width:.5rem .5rem .5rem 0;border-right-color:#fff}.bs-popover-auto[x-placement^=bottom],.bs-popover-bottom{margin-top:.5rem}.bs-popover-auto[x-placement^=bottom]>.arrow,.bs-popover-bottom>.arrow{top:calc((.5rem + 1px) * -1)}.bs-popover-auto[x-placement^=bottom]>.arrow::before,.bs-popover-bottom>.arrow::before{top:0;border-width:0 .5rem .5rem .5rem;border-bottom-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=bottom]>.arrow::after,.bs-popover-bottom>.arrow::after{top:1px;border-width:0 .5rem .5rem .5rem;border-bottom-color:#fff}.bs-popover-auto[x-placement^=bottom] .popover-header::before,.bs-popover-bottom .popover-header::before{position:absolute;top:0;left:50%;display:block;width:1rem;margin-left:-.5rem;content:"";border-bottom:1px solid #f7f7f7}.bs-popover-auto[x-placement^=left],.bs-popover-left{margin-right:.5rem}.bs-popover-auto[x-placement^=left]>.arrow,.bs-popover-left>.arrow{right:calc((.5rem + 1px) * -1);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-auto[x-placement^=left]>.arrow::before,.bs-popover-left>.arrow::before{right:0;border-width:.5rem 0 .5rem .5rem;border-left-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=left]>.arrow::after,.bs-popover-left>.arrow::after{right:1px;border-width:.5rem 0 .5rem .5rem;border-left-color:#fff}.popover-header{padding:.5rem .75rem;margin-bottom:0;font-size:1rem;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.popover-header:empty{display:none}.popover-body{padding:.5rem .75rem;color:#212529}.carousel{position:relative}.carousel.pointer-event{-ms-touch-action:pan-y;touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner::after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;-webkit-backface-visibility:hidden;backface-visibility:hidden;transition:-webkit-transform .6s ease-in-out;transition:transform .6s ease-in-out;transition:transform .6s ease-in-out,-webkit-transform .6s ease-in-out}@media (prefers-reduced-motion:reduce){.carousel-item{transition:none}}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block}.active.carousel-item-right,.carousel-item-next:not(.carousel-item-left){-webkit-transform:translateX(100%);transform:translateX(100%)}.active.carousel-item-left,.carousel-item-prev:not(.carousel-item-right){-webkit-transform:translateX(-100%);transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;-webkit-transform:none;transform:none}.carousel-fade .carousel-item-next.carousel-item-left,.carousel-fade .carousel-item-prev.carousel-item-right,.carousel-fade .carousel-item.active{z-index:1;opacity:1}.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-right{z-index:0;opacity:0;transition:0s .6s opacity}@media (prefers-reduced-motion:reduce){.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-right{transition:none}}.carousel-control-next,.carousel-control-prev{position:absolute;top:0;bottom:0;z-index:1;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:15%;color:#fff;text-align:center;opacity:.5;transition:opacity .15s ease}@media (prefers-reduced-motion:reduce){.carousel-control-next,.carousel-control-prev{transition:none}}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:20px;height:20px;background:no-repeat 50%/100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3e%3cpath d='M5.25 0l-4 4 4 4 1.5-1.5-2.5-2.5 2.5-2.5-1.5-1.5z'/%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3e%3cpath d='M2.75 0l-1.5 1.5 2.5 2.5-2.5 2.5 1.5 1.5 4-4-4-4z'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:15;display:-ms-flexbox;display:flex;-ms-flex-pack:center;justify-content:center;padding-left:0;margin-right:15%;margin-left:15%;list-style:none}.carousel-indicators li{box-sizing:content-box;-ms-flex:0 1 auto;flex:0 1 auto;width:30px;height:3px;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:#fff;background-clip:padding-box;border-top:10px solid transparent;border-bottom:10px solid transparent;opacity:.5;transition:opacity .6s ease}@media (prefers-reduced-motion:reduce){.carousel-indicators li{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center}@-webkit-keyframes spinner-border{to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes spinner-border{to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.spinner-border{display:inline-block;width:2rem;height:2rem;vertical-align:text-bottom;border:.25em solid currentColor;border-right-color:transparent;border-radius:50%;-webkit-animation:spinner-border .75s linear infinite;animation:spinner-border .75s linear infinite}.spinner-border-sm{width:1rem;height:1rem;border-width:.2em}@-webkit-keyframes spinner-grow{0%{-webkit-transform:scale(0);transform:scale(0)}50%{opacity:1}}@keyframes spinner-grow{0%{-webkit-transform:scale(0);transform:scale(0)}50%{opacity:1}}.spinner-grow{display:inline-block;width:2rem;height:2rem;vertical-align:text-bottom;background-color:currentColor;border-radius:50%;opacity:0;-webkit-animation:spinner-grow .75s linear infinite;animation:spinner-grow .75s linear infinite}.spinner-grow-sm{width:1rem;height:1rem}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.bg-primary{background-color:#007bff!important}a.bg-primary:focus,a.bg-primary:hover,button.bg-primary:focus,button.bg-primary:hover{background-color:#0062cc!important}.bg-secondary{background-color:#6c757d!important}a.bg-secondary:focus,a.bg-secondary:hover,button.bg-secondary:focus,button.bg-secondary:hover{background-color:#545b62!important}.bg-success{background-color:#28a745!important}a.bg-success:focus,a.bg-success:hover,button.bg-success:focus,button.bg-success:hover{background-color:#1e7e34!important}.bg-info{background-color:#17a2b8!important}a.bg-info:focus,a.bg-info:hover,button.bg-info:focus,button.bg-info:hover{background-color:#117a8b!important}.bg-warning{background-color:#ffc107!important}a.bg-warning:focus,a.bg-warning:hover,button.bg-warning:focus,button.bg-warning:hover{background-color:#d39e00!important}.bg-danger{background-color:#dc3545!important}a.bg-danger:focus,a.bg-danger:hover,button.bg-danger:focus,button.bg-danger:hover{background-color:#bd2130!important}.bg-light{background-color:#f8f9fa!important}a.bg-light:focus,a.bg-light:hover,button.bg-light:focus,button.bg-light:hover{background-color:#dae0e5!important}.bg-dark{background-color:#343a40!important}a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover{background-color:#1d2124!important}.bg-white{background-color:#fff!important}.bg-transparent{background-color:transparent!important}.border{border:1px solid #dee2e6!important}.border-top{border-top:1px solid #dee2e6!important}.border-right{border-right:1px solid #dee2e6!important}.border-bottom{border-bottom:1px solid #dee2e6!important}.border-left{border-left:1px solid #dee2e6!important}.border-0{border:0!important}.border-top-0{border-top:0!important}.border-right-0{border-right:0!important}.border-bottom-0{border-bottom:0!important}.border-left-0{border-left:0!important}.border-primary{border-color:#007bff!important}.border-secondary{border-color:#6c757d!important}.border-success{border-color:#28a745!important}.border-info{border-color:#17a2b8!important}.border-warning{border-color:#ffc107!important}.border-danger{border-color:#dc3545!important}.border-light{border-color:#f8f9fa!important}.border-dark{border-color:#343a40!important}.border-white{border-color:#fff!important}.rounded-sm{border-radius:.2rem!important}.rounded{border-radius:.25rem!important}.rounded-top{border-top-left-radius:.25rem!important;border-top-right-radius:.25rem!important}.rounded-right{border-top-right-radius:.25rem!important;border-bottom-right-radius:.25rem!important}.rounded-bottom{border-bottom-right-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-left{border-top-left-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-lg{border-radius:.3rem!important}.rounded-circle{border-radius:50%!important}.rounded-pill{border-radius:50rem!important}.rounded-0{border-radius:0!important}.clearfix::after{display:block;clear:both;content:""}.d-none{display:none!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:-ms-flexbox!important;display:flex!important}.d-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}@media (min-width:576px){.d-sm-none{display:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:-ms-flexbox!important;display:flex!important}.d-sm-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:768px){.d-md-none{display:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:-ms-flexbox!important;display:flex!important}.d-md-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:992px){.d-lg-none{display:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:-ms-flexbox!important;display:flex!important}.d-lg-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:1200px){.d-xl-none{display:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:-ms-flexbox!important;display:flex!important}.d-xl-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media print{.d-print-none{display:none!important}.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:-ms-flexbox!important;display:flex!important}.d-print-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}.embed-responsive{position:relative;display:block;width:100%;padding:0;overflow:hidden}.embed-responsive::before{display:block;content:""}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-21by9::before{padding-top:42.857143%}.embed-responsive-16by9::before{padding-top:56.25%}.embed-responsive-4by3::before{padding-top:75%}.embed-responsive-1by1::before{padding-top:100%}.flex-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-center{-ms-flex-align:center!important;align-items:center!important}.align-items-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}@media (min-width:576px){.flex-sm-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-sm-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-sm-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-sm-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-sm-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-sm-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-sm-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-sm-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-sm-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-sm-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-sm-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-sm-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-sm-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-sm-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-sm-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-sm-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-sm-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-sm-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-sm-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-sm-center{-ms-flex-align:center!important;align-items:center!important}.align-items-sm-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-sm-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-sm-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-sm-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-sm-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-sm-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-sm-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-sm-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-sm-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-sm-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-sm-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-sm-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-sm-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-sm-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:768px){.flex-md-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-md-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-md-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-md-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-md-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-md-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-md-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-md-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-md-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-md-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-md-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-md-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-md-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-md-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-md-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-md-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-md-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-md-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-md-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-md-center{-ms-flex-align:center!important;align-items:center!important}.align-items-md-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-md-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-md-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-md-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-md-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-md-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-md-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-md-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-md-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-md-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-md-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-md-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-md-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-md-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:992px){.flex-lg-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-lg-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-lg-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-lg-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-lg-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-lg-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-lg-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-lg-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-lg-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-lg-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-lg-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-lg-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-lg-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-lg-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-lg-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-lg-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-lg-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-lg-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-lg-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-lg-center{-ms-flex-align:center!important;align-items:center!important}.align-items-lg-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-lg-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-lg-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-lg-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-lg-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-lg-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-lg-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-lg-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-lg-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-lg-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-lg-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-lg-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-lg-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-lg-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:1200px){.flex-xl-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-xl-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-xl-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-xl-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-xl-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-xl-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-xl-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-xl-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-xl-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-xl-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-xl-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-xl-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-xl-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-xl-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-xl-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-xl-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-xl-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-xl-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-xl-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-xl-center{-ms-flex-align:center!important;align-items:center!important}.align-items-xl-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-xl-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-xl-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-xl-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-xl-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-xl-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-xl-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-xl-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-xl-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-xl-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-xl-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-xl-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-xl-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-xl-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}.float-left{float:left!important}.float-right{float:right!important}.float-none{float:none!important}@media (min-width:576px){.float-sm-left{float:left!important}.float-sm-right{float:right!important}.float-sm-none{float:none!important}}@media (min-width:768px){.float-md-left{float:left!important}.float-md-right{float:right!important}.float-md-none{float:none!important}}@media (min-width:992px){.float-lg-left{float:left!important}.float-lg-right{float:right!important}.float-lg-none{float:none!important}}@media (min-width:1200px){.float-xl-left{float:left!important}.float-xl-right{float:right!important}.float-xl-none{float:none!important}}.overflow-auto{overflow:auto!important}.overflow-hidden{overflow:hidden!important}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:-webkit-sticky!important;position:sticky!important}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}@supports ((position:-webkit-sticky) or (position:sticky)){.sticky-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}.sr-only{position:absolute;width:1px;height:1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;overflow:visible;clip:auto;white-space:normal}.shadow-sm{box-shadow:0 .125rem .25rem rgba(0,0,0,.075)!important}.shadow{box-shadow:0 .5rem 1rem rgba(0,0,0,.15)!important}.shadow-lg{box-shadow:0 1rem 3rem rgba(0,0,0,.175)!important}.shadow-none{box-shadow:none!important}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.w-auto{width:auto!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}.mw-100{max-width:100%!important}.mh-100{max-height:100%!important}.min-vw-100{min-width:100vw!important}.min-vh-100{min-height:100vh!important}.vw-100{width:100vw!important}.vh-100{height:100vh!important}.stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;pointer-events:auto;content:"";background-color:rgba(0,0,0,0)}.m-0{margin:0!important}.mt-0,.my-0{margin-top:0!important}.mr-0,.mx-0{margin-right:0!important}.mb-0,.my-0{margin-bottom:0!important}.ml-0,.mx-0{margin-left:0!important}.m-1{margin:.25rem!important}.mt-1,.my-1{margin-top:.25rem!important}.mr-1,.mx-1{margin-right:.25rem!important}.mb-1,.my-1{margin-bottom:.25rem!important}.ml-1,.mx-1{margin-left:.25rem!important}.m-2{margin:.5rem!important}.mt-2,.my-2{margin-top:.5rem!important}.mr-2,.mx-2{margin-right:.5rem!important}.mb-2,.my-2{margin-bottom:.5rem!important}.ml-2,.mx-2{margin-left:.5rem!important}.m-3{margin:1rem!important}.mt-3,.my-3{margin-top:1rem!important}.mr-3,.mx-3{margin-right:1rem!important}.mb-3,.my-3{margin-bottom:1rem!important}.ml-3,.mx-3{margin-left:1rem!important}.m-4{margin:1.5rem!important}.mt-4,.my-4{margin-top:1.5rem!important}.mr-4,.mx-4{margin-right:1.5rem!important}.mb-4,.my-4{margin-bottom:1.5rem!important}.ml-4,.mx-4{margin-left:1.5rem!important}.m-5{margin:3rem!important}.mt-5,.my-5{margin-top:3rem!important}.mr-5,.mx-5{margin-right:3rem!important}.mb-5,.my-5{margin-bottom:3rem!important}.ml-5,.mx-5{margin-left:3rem!important}.p-0{padding:0!important}.pt-0,.py-0{padding-top:0!important}.pr-0,.px-0{padding-right:0!important}.pb-0,.py-0{padding-bottom:0!important}.pl-0,.px-0{padding-left:0!important}.p-1{padding:.25rem!important}.pt-1,.py-1{padding-top:.25rem!important}.pr-1,.px-1{padding-right:.25rem!important}.pb-1,.py-1{padding-bottom:.25rem!important}.pl-1,.px-1{padding-left:.25rem!important}.p-2{padding:.5rem!important}.pt-2,.py-2{padding-top:.5rem!important}.pr-2,.px-2{padding-right:.5rem!important}.pb-2,.py-2{padding-bottom:.5rem!important}.pl-2,.px-2{padding-left:.5rem!important}.p-3{padding:1rem!important}.pt-3,.py-3{padding-top:1rem!important}.pr-3,.px-3{padding-right:1rem!important}.pb-3,.py-3{padding-bottom:1rem!important}.pl-3,.px-3{padding-left:1rem!important}.p-4{padding:1.5rem!important}.pt-4,.py-4{padding-top:1.5rem!important}.pr-4,.px-4{padding-right:1.5rem!important}.pb-4,.py-4{padding-bottom:1.5rem!important}.pl-4,.px-4{padding-left:1.5rem!important}.p-5{padding:3rem!important}.pt-5,.py-5{padding-top:3rem!important}.pr-5,.px-5{padding-right:3rem!important}.pb-5,.py-5{padding-bottom:3rem!important}.pl-5,.px-5{padding-left:3rem!important}.m-n1{margin:-.25rem!important}.mt-n1,.my-n1{margin-top:-.25rem!important}.mr-n1,.mx-n1{margin-right:-.25rem!important}.mb-n1,.my-n1{margin-bottom:-.25rem!important}.ml-n1,.mx-n1{margin-left:-.25rem!important}.m-n2{margin:-.5rem!important}.mt-n2,.my-n2{margin-top:-.5rem!important}.mr-n2,.mx-n2{margin-right:-.5rem!important}.mb-n2,.my-n2{margin-bottom:-.5rem!important}.ml-n2,.mx-n2{margin-left:-.5rem!important}.m-n3{margin:-1rem!important}.mt-n3,.my-n3{margin-top:-1rem!important}.mr-n3,.mx-n3{margin-right:-1rem!important}.mb-n3,.my-n3{margin-bottom:-1rem!important}.ml-n3,.mx-n3{margin-left:-1rem!important}.m-n4{margin:-1.5rem!important}.mt-n4,.my-n4{margin-top:-1.5rem!important}.mr-n4,.mx-n4{margin-right:-1.5rem!important}.mb-n4,.my-n4{margin-bottom:-1.5rem!important}.ml-n4,.mx-n4{margin-left:-1.5rem!important}.m-n5{margin:-3rem!important}.mt-n5,.my-n5{margin-top:-3rem!important}.mr-n5,.mx-n5{margin-right:-3rem!important}.mb-n5,.my-n5{margin-bottom:-3rem!important}.ml-n5,.mx-n5{margin-left:-3rem!important}.m-auto{margin:auto!important}.mt-auto,.my-auto{margin-top:auto!important}.mr-auto,.mx-auto{margin-right:auto!important}.mb-auto,.my-auto{margin-bottom:auto!important}.ml-auto,.mx-auto{margin-left:auto!important}@media (min-width:576px){.m-sm-0{margin:0!important}.mt-sm-0,.my-sm-0{margin-top:0!important}.mr-sm-0,.mx-sm-0{margin-right:0!important}.mb-sm-0,.my-sm-0{margin-bottom:0!important}.ml-sm-0,.mx-sm-0{margin-left:0!important}.m-sm-1{margin:.25rem!important}.mt-sm-1,.my-sm-1{margin-top:.25rem!important}.mr-sm-1,.mx-sm-1{margin-right:.25rem!important}.mb-sm-1,.my-sm-1{margin-bottom:.25rem!important}.ml-sm-1,.mx-sm-1{margin-left:.25rem!important}.m-sm-2{margin:.5rem!important}.mt-sm-2,.my-sm-2{margin-top:.5rem!important}.mr-sm-2,.mx-sm-2{margin-right:.5rem!important}.mb-sm-2,.my-sm-2{margin-bottom:.5rem!important}.ml-sm-2,.mx-sm-2{margin-left:.5rem!important}.m-sm-3{margin:1rem!important}.mt-sm-3,.my-sm-3{margin-top:1rem!important}.mr-sm-3,.mx-sm-3{margin-right:1rem!important}.mb-sm-3,.my-sm-3{margin-bottom:1rem!important}.ml-sm-3,.mx-sm-3{margin-left:1rem!important}.m-sm-4{margin:1.5rem!important}.mt-sm-4,.my-sm-4{margin-top:1.5rem!important}.mr-sm-4,.mx-sm-4{margin-right:1.5rem!important}.mb-sm-4,.my-sm-4{margin-bottom:1.5rem!important}.ml-sm-4,.mx-sm-4{margin-left:1.5rem!important}.m-sm-5{margin:3rem!important}.mt-sm-5,.my-sm-5{margin-top:3rem!important}.mr-sm-5,.mx-sm-5{margin-right:3rem!important}.mb-sm-5,.my-sm-5{margin-bottom:3rem!important}.ml-sm-5,.mx-sm-5{margin-left:3rem!important}.p-sm-0{padding:0!important}.pt-sm-0,.py-sm-0{padding-top:0!important}.pr-sm-0,.px-sm-0{padding-right:0!important}.pb-sm-0,.py-sm-0{padding-bottom:0!important}.pl-sm-0,.px-sm-0{padding-left:0!important}.p-sm-1{padding:.25rem!important}.pt-sm-1,.py-sm-1{padding-top:.25rem!important}.pr-sm-1,.px-sm-1{padding-right:.25rem!important}.pb-sm-1,.py-sm-1{padding-bottom:.25rem!important}.pl-sm-1,.px-sm-1{padding-left:.25rem!important}.p-sm-2{padding:.5rem!important}.pt-sm-2,.py-sm-2{padding-top:.5rem!important}.pr-sm-2,.px-sm-2{padding-right:.5rem!important}.pb-sm-2,.py-sm-2{padding-bottom:.5rem!important}.pl-sm-2,.px-sm-2{padding-left:.5rem!important}.p-sm-3{padding:1rem!important}.pt-sm-3,.py-sm-3{padding-top:1rem!important}.pr-sm-3,.px-sm-3{padding-right:1rem!important}.pb-sm-3,.py-sm-3{padding-bottom:1rem!important}.pl-sm-3,.px-sm-3{padding-left:1rem!important}.p-sm-4{padding:1.5rem!important}.pt-sm-4,.py-sm-4{padding-top:1.5rem!important}.pr-sm-4,.px-sm-4{padding-right:1.5rem!important}.pb-sm-4,.py-sm-4{padding-bottom:1.5rem!important}.pl-sm-4,.px-sm-4{padding-left:1.5rem!important}.p-sm-5{padding:3rem!important}.pt-sm-5,.py-sm-5{padding-top:3rem!important}.pr-sm-5,.px-sm-5{padding-right:3rem!important}.pb-sm-5,.py-sm-5{padding-bottom:3rem!important}.pl-sm-5,.px-sm-5{padding-left:3rem!important}.m-sm-n1{margin:-.25rem!important}.mt-sm-n1,.my-sm-n1{margin-top:-.25rem!important}.mr-sm-n1,.mx-sm-n1{margin-right:-.25rem!important}.mb-sm-n1,.my-sm-n1{margin-bottom:-.25rem!important}.ml-sm-n1,.mx-sm-n1{margin-left:-.25rem!important}.m-sm-n2{margin:-.5rem!important}.mt-sm-n2,.my-sm-n2{margin-top:-.5rem!important}.mr-sm-n2,.mx-sm-n2{margin-right:-.5rem!important}.mb-sm-n2,.my-sm-n2{margin-bottom:-.5rem!important}.ml-sm-n2,.mx-sm-n2{margin-left:-.5rem!important}.m-sm-n3{margin:-1rem!important}.mt-sm-n3,.my-sm-n3{margin-top:-1rem!important}.mr-sm-n3,.mx-sm-n3{margin-right:-1rem!important}.mb-sm-n3,.my-sm-n3{margin-bottom:-1rem!important}.ml-sm-n3,.mx-sm-n3{margin-left:-1rem!important}.m-sm-n4{margin:-1.5rem!important}.mt-sm-n4,.my-sm-n4{margin-top:-1.5rem!important}.mr-sm-n4,.mx-sm-n4{margin-right:-1.5rem!important}.mb-sm-n4,.my-sm-n4{margin-bottom:-1.5rem!important}.ml-sm-n4,.mx-sm-n4{margin-left:-1.5rem!important}.m-sm-n5{margin:-3rem!important}.mt-sm-n5,.my-sm-n5{margin-top:-3rem!important}.mr-sm-n5,.mx-sm-n5{margin-right:-3rem!important}.mb-sm-n5,.my-sm-n5{margin-bottom:-3rem!important}.ml-sm-n5,.mx-sm-n5{margin-left:-3rem!important}.m-sm-auto{margin:auto!important}.mt-sm-auto,.my-sm-auto{margin-top:auto!important}.mr-sm-auto,.mx-sm-auto{margin-right:auto!important}.mb-sm-auto,.my-sm-auto{margin-bottom:auto!important}.ml-sm-auto,.mx-sm-auto{margin-left:auto!important}}@media (min-width:768px){.m-md-0{margin:0!important}.mt-md-0,.my-md-0{margin-top:0!important}.mr-md-0,.mx-md-0{margin-right:0!important}.mb-md-0,.my-md-0{margin-bottom:0!important}.ml-md-0,.mx-md-0{margin-left:0!important}.m-md-1{margin:.25rem!important}.mt-md-1,.my-md-1{margin-top:.25rem!important}.mr-md-1,.mx-md-1{margin-right:.25rem!important}.mb-md-1,.my-md-1{margin-bottom:.25rem!important}.ml-md-1,.mx-md-1{margin-left:.25rem!important}.m-md-2{margin:.5rem!important}.mt-md-2,.my-md-2{margin-top:.5rem!important}.mr-md-2,.mx-md-2{margin-right:.5rem!important}.mb-md-2,.my-md-2{margin-bottom:.5rem!important}.ml-md-2,.mx-md-2{margin-left:.5rem!important}.m-md-3{margin:1rem!important}.mt-md-3,.my-md-3{margin-top:1rem!important}.mr-md-3,.mx-md-3{margin-right:1rem!important}.mb-md-3,.my-md-3{margin-bottom:1rem!important}.ml-md-3,.mx-md-3{margin-left:1rem!important}.m-md-4{margin:1.5rem!important}.mt-md-4,.my-md-4{margin-top:1.5rem!important}.mr-md-4,.mx-md-4{margin-right:1.5rem!important}.mb-md-4,.my-md-4{margin-bottom:1.5rem!important}.ml-md-4,.mx-md-4{margin-left:1.5rem!important}.m-md-5{margin:3rem!important}.mt-md-5,.my-md-5{margin-top:3rem!important}.mr-md-5,.mx-md-5{margin-right:3rem!important}.mb-md-5,.my-md-5{margin-bottom:3rem!important}.ml-md-5,.mx-md-5{margin-left:3rem!important}.p-md-0{padding:0!important}.pt-md-0,.py-md-0{padding-top:0!important}.pr-md-0,.px-md-0{padding-right:0!important}.pb-md-0,.py-md-0{padding-bottom:0!important}.pl-md-0,.px-md-0{padding-left:0!important}.p-md-1{padding:.25rem!important}.pt-md-1,.py-md-1{padding-top:.25rem!important}.pr-md-1,.px-md-1{padding-right:.25rem!important}.pb-md-1,.py-md-1{padding-bottom:.25rem!important}.pl-md-1,.px-md-1{padding-left:.25rem!important}.p-md-2{padding:.5rem!important}.pt-md-2,.py-md-2{padding-top:.5rem!important}.pr-md-2,.px-md-2{padding-right:.5rem!important}.pb-md-2,.py-md-2{padding-bottom:.5rem!important}.pl-md-2,.px-md-2{padding-left:.5rem!important}.p-md-3{padding:1rem!important}.pt-md-3,.py-md-3{padding-top:1rem!important}.pr-md-3,.px-md-3{padding-right:1rem!important}.pb-md-3,.py-md-3{padding-bottom:1rem!important}.pl-md-3,.px-md-3{padding-left:1rem!important}.p-md-4{padding:1.5rem!important}.pt-md-4,.py-md-4{padding-top:1.5rem!important}.pr-md-4,.px-md-4{padding-right:1.5rem!important}.pb-md-4,.py-md-4{padding-bottom:1.5rem!important}.pl-md-4,.px-md-4{padding-left:1.5rem!important}.p-md-5{padding:3rem!important}.pt-md-5,.py-md-5{padding-top:3rem!important}.pr-md-5,.px-md-5{padding-right:3rem!important}.pb-md-5,.py-md-5{padding-bottom:3rem!important}.pl-md-5,.px-md-5{padding-left:3rem!important}.m-md-n1{margin:-.25rem!important}.mt-md-n1,.my-md-n1{margin-top:-.25rem!important}.mr-md-n1,.mx-md-n1{margin-right:-.25rem!important}.mb-md-n1,.my-md-n1{margin-bottom:-.25rem!important}.ml-md-n1,.mx-md-n1{margin-left:-.25rem!important}.m-md-n2{margin:-.5rem!important}.mt-md-n2,.my-md-n2{margin-top:-.5rem!important}.mr-md-n2,.mx-md-n2{margin-right:-.5rem!important}.mb-md-n2,.my-md-n2{margin-bottom:-.5rem!important}.ml-md-n2,.mx-md-n2{margin-left:-.5rem!important}.m-md-n3{margin:-1rem!important}.mt-md-n3,.my-md-n3{margin-top:-1rem!important}.mr-md-n3,.mx-md-n3{margin-right:-1rem!important}.mb-md-n3,.my-md-n3{margin-bottom:-1rem!important}.ml-md-n3,.mx-md-n3{margin-left:-1rem!important}.m-md-n4{margin:-1.5rem!important}.mt-md-n4,.my-md-n4{margin-top:-1.5rem!important}.mr-md-n4,.mx-md-n4{margin-right:-1.5rem!important}.mb-md-n4,.my-md-n4{margin-bottom:-1.5rem!important}.ml-md-n4,.mx-md-n4{margin-left:-1.5rem!important}.m-md-n5{margin:-3rem!important}.mt-md-n5,.my-md-n5{margin-top:-3rem!important}.mr-md-n5,.mx-md-n5{margin-right:-3rem!important}.mb-md-n5,.my-md-n5{margin-bottom:-3rem!important}.ml-md-n5,.mx-md-n5{margin-left:-3rem!important}.m-md-auto{margin:auto!important}.mt-md-auto,.my-md-auto{margin-top:auto!important}.mr-md-auto,.mx-md-auto{margin-right:auto!important}.mb-md-auto,.my-md-auto{margin-bottom:auto!important}.ml-md-auto,.mx-md-auto{margin-left:auto!important}}@media (min-width:992px){.m-lg-0{margin:0!important}.mt-lg-0,.my-lg-0{margin-top:0!important}.mr-lg-0,.mx-lg-0{margin-right:0!important}.mb-lg-0,.my-lg-0{margin-bottom:0!important}.ml-lg-0,.mx-lg-0{margin-left:0!important}.m-lg-1{margin:.25rem!important}.mt-lg-1,.my-lg-1{margin-top:.25rem!important}.mr-lg-1,.mx-lg-1{margin-right:.25rem!important}.mb-lg-1,.my-lg-1{margin-bottom:.25rem!important}.ml-lg-1,.mx-lg-1{margin-left:.25rem!important}.m-lg-2{margin:.5rem!important}.mt-lg-2,.my-lg-2{margin-top:.5rem!important}.mr-lg-2,.mx-lg-2{margin-right:.5rem!important}.mb-lg-2,.my-lg-2{margin-bottom:.5rem!important}.ml-lg-2,.mx-lg-2{margin-left:.5rem!important}.m-lg-3{margin:1rem!important}.mt-lg-3,.my-lg-3{margin-top:1rem!important}.mr-lg-3,.mx-lg-3{margin-right:1rem!important}.mb-lg-3,.my-lg-3{margin-bottom:1rem!important}.ml-lg-3,.mx-lg-3{margin-left:1rem!important}.m-lg-4{margin:1.5rem!important}.mt-lg-4,.my-lg-4{margin-top:1.5rem!important}.mr-lg-4,.mx-lg-4{margin-right:1.5rem!important}.mb-lg-4,.my-lg-4{margin-bottom:1.5rem!important}.ml-lg-4,.mx-lg-4{margin-left:1.5rem!important}.m-lg-5{margin:3rem!important}.mt-lg-5,.my-lg-5{margin-top:3rem!important}.mr-lg-5,.mx-lg-5{margin-right:3rem!important}.mb-lg-5,.my-lg-5{margin-bottom:3rem!important}.ml-lg-5,.mx-lg-5{margin-left:3rem!important}.p-lg-0{padding:0!important}.pt-lg-0,.py-lg-0{padding-top:0!important}.pr-lg-0,.px-lg-0{padding-right:0!important}.pb-lg-0,.py-lg-0{padding-bottom:0!important}.pl-lg-0,.px-lg-0{padding-left:0!important}.p-lg-1{padding:.25rem!important}.pt-lg-1,.py-lg-1{padding-top:.25rem!important}.pr-lg-1,.px-lg-1{padding-right:.25rem!important}.pb-lg-1,.py-lg-1{padding-bottom:.25rem!important}.pl-lg-1,.px-lg-1{padding-left:.25rem!important}.p-lg-2{padding:.5rem!important}.pt-lg-2,.py-lg-2{padding-top:.5rem!important}.pr-lg-2,.px-lg-2{padding-right:.5rem!important}.pb-lg-2,.py-lg-2{padding-bottom:.5rem!important}.pl-lg-2,.px-lg-2{padding-left:.5rem!important}.p-lg-3{padding:1rem!important}.pt-lg-3,.py-lg-3{padding-top:1rem!important}.pr-lg-3,.px-lg-3{padding-right:1rem!important}.pb-lg-3,.py-lg-3{padding-bottom:1rem!important}.pl-lg-3,.px-lg-3{padding-left:1rem!important}.p-lg-4{padding:1.5rem!important}.pt-lg-4,.py-lg-4{padding-top:1.5rem!important}.pr-lg-4,.px-lg-4{padding-right:1.5rem!important}.pb-lg-4,.py-lg-4{padding-bottom:1.5rem!important}.pl-lg-4,.px-lg-4{padding-left:1.5rem!important}.p-lg-5{padding:3rem!important}.pt-lg-5,.py-lg-5{padding-top:3rem!important}.pr-lg-5,.px-lg-5{padding-right:3rem!important}.pb-lg-5,.py-lg-5{padding-bottom:3rem!important}.pl-lg-5,.px-lg-5{padding-left:3rem!important}.m-lg-n1{margin:-.25rem!important}.mt-lg-n1,.my-lg-n1{margin-top:-.25rem!important}.mr-lg-n1,.mx-lg-n1{margin-right:-.25rem!important}.mb-lg-n1,.my-lg-n1{margin-bottom:-.25rem!important}.ml-lg-n1,.mx-lg-n1{margin-left:-.25rem!important}.m-lg-n2{margin:-.5rem!important}.mt-lg-n2,.my-lg-n2{margin-top:-.5rem!important}.mr-lg-n2,.mx-lg-n2{margin-right:-.5rem!important}.mb-lg-n2,.my-lg-n2{margin-bottom:-.5rem!important}.ml-lg-n2,.mx-lg-n2{margin-left:-.5rem!important}.m-lg-n3{margin:-1rem!important}.mt-lg-n3,.my-lg-n3{margin-top:-1rem!important}.mr-lg-n3,.mx-lg-n3{margin-right:-1rem!important}.mb-lg-n3,.my-lg-n3{margin-bottom:-1rem!important}.ml-lg-n3,.mx-lg-n3{margin-left:-1rem!important}.m-lg-n4{margin:-1.5rem!important}.mt-lg-n4,.my-lg-n4{margin-top:-1.5rem!important}.mr-lg-n4,.mx-lg-n4{margin-right:-1.5rem!important}.mb-lg-n4,.my-lg-n4{margin-bottom:-1.5rem!important}.ml-lg-n4,.mx-lg-n4{margin-left:-1.5rem!important}.m-lg-n5{margin:-3rem!important}.mt-lg-n5,.my-lg-n5{margin-top:-3rem!important}.mr-lg-n5,.mx-lg-n5{margin-right:-3rem!important}.mb-lg-n5,.my-lg-n5{margin-bottom:-3rem!important}.ml-lg-n5,.mx-lg-n5{margin-left:-3rem!important}.m-lg-auto{margin:auto!important}.mt-lg-auto,.my-lg-auto{margin-top:auto!important}.mr-lg-auto,.mx-lg-auto{margin-right:auto!important}.mb-lg-auto,.my-lg-auto{margin-bottom:auto!important}.ml-lg-auto,.mx-lg-auto{margin-left:auto!important}}@media (min-width:1200px){.m-xl-0{margin:0!important}.mt-xl-0,.my-xl-0{margin-top:0!important}.mr-xl-0,.mx-xl-0{margin-right:0!important}.mb-xl-0,.my-xl-0{margin-bottom:0!important}.ml-xl-0,.mx-xl-0{margin-left:0!important}.m-xl-1{margin:.25rem!important}.mt-xl-1,.my-xl-1{margin-top:.25rem!important}.mr-xl-1,.mx-xl-1{margin-right:.25rem!important}.mb-xl-1,.my-xl-1{margin-bottom:.25rem!important}.ml-xl-1,.mx-xl-1{margin-left:.25rem!important}.m-xl-2{margin:.5rem!important}.mt-xl-2,.my-xl-2{margin-top:.5rem!important}.mr-xl-2,.mx-xl-2{margin-right:.5rem!important}.mb-xl-2,.my-xl-2{margin-bottom:.5rem!important}.ml-xl-2,.mx-xl-2{margin-left:.5rem!important}.m-xl-3{margin:1rem!important}.mt-xl-3,.my-xl-3{margin-top:1rem!important}.mr-xl-3,.mx-xl-3{margin-right:1rem!important}.mb-xl-3,.my-xl-3{margin-bottom:1rem!important}.ml-xl-3,.mx-xl-3{margin-left:1rem!important}.m-xl-4{margin:1.5rem!important}.mt-xl-4,.my-xl-4{margin-top:1.5rem!important}.mr-xl-4,.mx-xl-4{margin-right:1.5rem!important}.mb-xl-4,.my-xl-4{margin-bottom:1.5rem!important}.ml-xl-4,.mx-xl-4{margin-left:1.5rem!important}.m-xl-5{margin:3rem!important}.mt-xl-5,.my-xl-5{margin-top:3rem!important}.mr-xl-5,.mx-xl-5{margin-right:3rem!important}.mb-xl-5,.my-xl-5{margin-bottom:3rem!important}.ml-xl-5,.mx-xl-5{margin-left:3rem!important}.p-xl-0{padding:0!important}.pt-xl-0,.py-xl-0{padding-top:0!important}.pr-xl-0,.px-xl-0{padding-right:0!important}.pb-xl-0,.py-xl-0{padding-bottom:0!important}.pl-xl-0,.px-xl-0{padding-left:0!important}.p-xl-1{padding:.25rem!important}.pt-xl-1,.py-xl-1{padding-top:.25rem!important}.pr-xl-1,.px-xl-1{padding-right:.25rem!important}.pb-xl-1,.py-xl-1{padding-bottom:.25rem!important}.pl-xl-1,.px-xl-1{padding-left:.25rem!important}.p-xl-2{padding:.5rem!important}.pt-xl-2,.py-xl-2{padding-top:.5rem!important}.pr-xl-2,.px-xl-2{padding-right:.5rem!important}.pb-xl-2,.py-xl-2{padding-bottom:.5rem!important}.pl-xl-2,.px-xl-2{padding-left:.5rem!important}.p-xl-3{padding:1rem!important}.pt-xl-3,.py-xl-3{padding-top:1rem!important}.pr-xl-3,.px-xl-3{padding-right:1rem!important}.pb-xl-3,.py-xl-3{padding-bottom:1rem!important}.pl-xl-3,.px-xl-3{padding-left:1rem!important}.p-xl-4{padding:1.5rem!important}.pt-xl-4,.py-xl-4{padding-top:1.5rem!important}.pr-xl-4,.px-xl-4{padding-right:1.5rem!important}.pb-xl-4,.py-xl-4{padding-bottom:1.5rem!important}.pl-xl-4,.px-xl-4{padding-left:1.5rem!important}.p-xl-5{padding:3rem!important}.pt-xl-5,.py-xl-5{padding-top:3rem!important}.pr-xl-5,.px-xl-5{padding-right:3rem!important}.pb-xl-5,.py-xl-5{padding-bottom:3rem!important}.pl-xl-5,.px-xl-5{padding-left:3rem!important}.m-xl-n1{margin:-.25rem!important}.mt-xl-n1,.my-xl-n1{margin-top:-.25rem!important}.mr-xl-n1,.mx-xl-n1{margin-right:-.25rem!important}.mb-xl-n1,.my-xl-n1{margin-bottom:-.25rem!important}.ml-xl-n1,.mx-xl-n1{margin-left:-.25rem!important}.m-xl-n2{margin:-.5rem!important}.mt-xl-n2,.my-xl-n2{margin-top:-.5rem!important}.mr-xl-n2,.mx-xl-n2{margin-right:-.5rem!important}.mb-xl-n2,.my-xl-n2{margin-bottom:-.5rem!important}.ml-xl-n2,.mx-xl-n2{margin-left:-.5rem!important}.m-xl-n3{margin:-1rem!important}.mt-xl-n3,.my-xl-n3{margin-top:-1rem!important}.mr-xl-n3,.mx-xl-n3{margin-right:-1rem!important}.mb-xl-n3,.my-xl-n3{margin-bottom:-1rem!important}.ml-xl-n3,.mx-xl-n3{margin-left:-1rem!important}.m-xl-n4{margin:-1.5rem!important}.mt-xl-n4,.my-xl-n4{margin-top:-1.5rem!important}.mr-xl-n4,.mx-xl-n4{margin-right:-1.5rem!important}.mb-xl-n4,.my-xl-n4{margin-bottom:-1.5rem!important}.ml-xl-n4,.mx-xl-n4{margin-left:-1.5rem!important}.m-xl-n5{margin:-3rem!important}.mt-xl-n5,.my-xl-n5{margin-top:-3rem!important}.mr-xl-n5,.mx-xl-n5{margin-right:-3rem!important}.mb-xl-n5,.my-xl-n5{margin-bottom:-3rem!important}.ml-xl-n5,.mx-xl-n5{margin-left:-3rem!important}.m-xl-auto{margin:auto!important}.mt-xl-auto,.my-xl-auto{margin-top:auto!important}.mr-xl-auto,.mx-xl-auto{margin-right:auto!important}.mb-xl-auto,.my-xl-auto{margin-bottom:auto!important}.ml-xl-auto,.mx-xl-auto{margin-left:auto!important}}.text-monospace{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace!important}.text-justify{text-align:justify!important}.text-wrap{white-space:normal!important}.text-nowrap{white-space:nowrap!important}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text-left{text-align:left!important}.text-right{text-align:right!important}.text-center{text-align:center!important}@media (min-width:576px){.text-sm-left{text-align:left!important}.text-sm-right{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.text-md-left{text-align:left!important}.text-md-right{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.text-lg-left{text-align:left!important}.text-lg-right{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.text-xl-left{text-align:left!important}.text-xl-right{text-align:right!important}.text-xl-center{text-align:center!important}}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.font-weight-light{font-weight:300!important}.font-weight-lighter{font-weight:lighter!important}.font-weight-normal{font-weight:400!important}.font-weight-bold{font-weight:700!important}.font-weight-bolder{font-weight:bolder!important}.font-italic{font-style:italic!important}.text-white{color:#fff!important}.text-primary{color:#007bff!important}a.text-primary:focus,a.text-primary:hover{color:#0056b3!important}.text-secondary{color:#6c757d!important}a.text-secondary:focus,a.text-secondary:hover{color:#494f54!important}.text-success{color:#28a745!important}a.text-success:focus,a.text-success:hover{color:#19692c!important}.text-info{color:#17a2b8!important}a.text-info:focus,a.text-info:hover{color:#0f6674!important}.text-warning{color:#ffc107!important}a.text-warning:focus,a.text-warning:hover{color:#ba8b00!important}.text-danger{color:#dc3545!important}a.text-danger:focus,a.text-danger:hover{color:#a71d2a!important}.text-light{color:#f8f9fa!important}a.text-light:focus,a.text-light:hover{color:#cbd3da!important}.text-dark{color:#343a40!important}a.text-dark:focus,a.text-dark:hover{color:#121416!important}.text-body{color:#212529!important}.text-muted{color:#6c757d!important}.text-black-50{color:rgba(0,0,0,.5)!important}.text-white-50{color:rgba(255,255,255,.5)!important}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.text-decoration-none{text-decoration:none!important}.text-break{word-break:break-word!important;overflow-wrap:break-word!important}.text-reset{color:inherit!important}.visible{visibility:visible!important}.invisible{visibility:hidden!important}@media print{*,::after,::before{text-shadow:none!important;box-shadow:none!important}a:not(.btn){text-decoration:underline}abbr[title]::after{content:" (" attr(title) ")"}pre{white-space:pre-wrap!important}blockquote,pre{border:1px solid #adb5bd;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}@page{size:a3}body{min-width:992px!important}.container{min-width:992px!important}.navbar{display:none}.badge{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #dee2e6!important}.table-dark{color:inherit}.table-dark tbody+tbody,.table-dark td,.table-dark th,.table-dark thead th{border-color:#dee2e6}.table .thead-dark th{color:inherit;border-color:#dee2e6}} +/*# sourceMappingURL=bootstrap.min.css.map */ \ No newline at end of file diff --git a/frontend/public/css/codemirror-colorpicker.css b/frontend/public/css/codemirror-colorpicker.css new file mode 100644 index 00000000..5b114d63 --- /dev/null +++ b/frontend/public/css/codemirror-colorpicker.css @@ -0,0 +1,679 @@ +/* codemirror colorview */ +.codemirror-colorview { + border: 1px solid #b8b8b8; + position: relative; + display: inline-block; + -webkit-box-sizing: border-box; + box-sizing: border-box; + margin: -4px 5px 0px 0px; + width: 15px; + height: 15px; + cursor: pointer; + vertical-align: middle; + background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAJElEQVQYV2NctWrVfwYkEBYWxojMZ6SDAmT7QGx0K1EcRBsFAADeG/3M/HteAAAAAElFTkSuQmCC") repeat; } + .codemirror-colorview .codemirror-colorview-background { + content: ""; + position: absolute; + left: 0px; + right: 0px; + bottom: 0px; + top: 0px; } + .codemirror-colorview:hover { + border-color: #494949; } + +/* codemirror-colorpicker */ +.codemirror-colorpicker { + position: relative; + width: 224px; + z-index: 1000; + display: inline-block; + border: 1px solid rgba(0, 0, 0, 0.2); + background-color: #fff; + border-radius: 3px; + -webkit-box-shadow: 0 0px 10px 2px rgba(0, 0, 0, 0.12); + box-shadow: 0 0px 10px 2px rgba(0, 0, 0, 0.12); + /* theme */ } + .codemirror-colorpicker > .arrow { + position: absolute; + top: -10px; + left: 7px; + width: 0; + height: 0; + border-left: 10px solid transparent; + border-right: 10px solid transparent; + display: none; + border-bottom: 10px solid rgba(0, 0, 0, 0.2); + pointer-events: none; } + .codemirror-colorpicker > .arrow:after { + position: absolute; + content: ""; + top: 1px; + left: -9px; + width: 0; + height: 0; + border-left: 9px solid transparent; + border-right: 9px solid transparent; + border-bottom: 9px solid white; } + .codemirror-colorpicker .arrow-button { + position: relative; + width: 10px; + height: 12px; + padding: 0px; } + .codemirror-colorpicker .arrow-button:before { + content: ""; + display: inline-block; + position: absolute; + left: 0px; + right: 0px; + top: 0px; + height: 50%; + width: 0; + height: 0; + border-left: 3px solid transparent; + border-right: 3px solid transparent; + border-bottom: 3px solid black; + pointer-events: none; + margin: 2px; + -webkit-box-sizing: border-box; + box-sizing: border-box; } + .codemirror-colorpicker .arrow-button:after { + content: ""; + display: inline-block; + position: absolute; + left: 0px; + right: 0px; + bottom: 0px; + top: 50%; + width: 0; + height: 0; + border-left: 3px solid transparent; + border-right: 3px solid transparent; + border-top: 3px solid black; + pointer-events: none; + margin: 2px; + -webkit-box-sizing: border-box; + box-sizing: border-box; } + .codemirror-colorpicker > .color { + position: relative; + height: 120px; + overflow: hidden; + cursor: pointer; } + .codemirror-colorpicker > .color > .saturation { + position: relative; + width: 100%; + height: 100%; } + .codemirror-colorpicker > .color > .saturation > .value { + position: relative; + width: 100%; + height: 100%; } + .codemirror-colorpicker > .color > .saturation > .value > .drag-pointer { + position: absolute; + width: 10px; + height: 10px; + border-radius: 50%; + left: -5px; + top: -5px; } + .codemirror-colorpicker > .color > .saturation { + background-color: rgba(204, 154, 129, 0); + background-image: -webkit-gradient(linear, left top, right top, from(#FFF), to(rgba(204, 154, 129, 0))); + background-image: linear-gradient(to right, #FFF, rgba(204, 154, 129, 0)); + background-repeat: repeat-x; } + .codemirror-colorpicker > .color > .saturation > .value { + background-image: -webkit-gradient(linear, left bottom, left top, from(#000000), to(rgba(204, 154, 129, 0))); + background-image: linear-gradient(to top, #000000, rgba(204, 154, 129, 0)); } + .codemirror-colorpicker > .color > .saturation > .value > .drag-pointer { + border: 1px solid #fff; + -webkit-box-shadow: 0 0 2px 0 rgba(0, 0, 0, 0.05); + box-shadow: 0 0 2px 0 rgba(0, 0, 0, 0.05); } + .codemirror-colorpicker > .control { + position: relative; + padding: 10px 0px 10px 0px; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; } + .codemirror-colorpicker > .control > .color, .codemirror-colorpicker > .control > .empty { + position: absolute; + left: 12px; + top: 14px; + width: 30px; + height: 30px; + border-radius: 50%; + -webkit-box-sizing: border-box; + box-sizing: border-box; } + .codemirror-colorpicker > .control > .color { + border: 1px solid rgba(0, 0, 0, 0.1); } + .codemirror-colorpicker > .control > .hue { + position: relative; + padding: 6px 16px; + margin: 0px 0px 0px 42px; + -webkit-box-sizing: border-box; + box-sizing: border-box; + cursor: pointer; } + .codemirror-colorpicker > .control > .hue > .hue-container { + position: relative; + width: 100%; + height: 10px; + border-radius: 3px; } + .codemirror-colorpicker > .control > .opacity { + position: relative; + padding: 3px 16px; + margin: 0px 0px 0px 42px; + -webkit-box-sizing: border-box; + box-sizing: border-box; + cursor: pointer; } + .codemirror-colorpicker > .control > .opacity > .opacity-container { + position: relative; + width: 100%; + height: 10px; + border-radius: 3px; } + .codemirror-colorpicker > .control .drag-bar, .codemirror-colorpicker > .control .drag-bar2 { + position: absolute; + cursor: pointer; + top: 50% !important; + margin-top: -7px !important; + left: -3px; + width: 12px; + height: 12px; + border-radius: 50px; } + .codemirror-colorpicker > .control > .hue > .hue-container { + background: -webkit-gradient(linear, left top, right top, from(#ff0000), color-stop(17%, #ffff00), color-stop(33%, #00ff00), color-stop(50%, #00ffff), color-stop(67%, #0000ff), color-stop(83%, #ff00ff), to(#ff0000)); + background: linear-gradient(to right, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); } + .codemirror-colorpicker > .control > .opacity > .opacity-container { + background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAJElEQVQYV2NctWrVfwYkEBYWxojMZ6SDAmT7QGx0K1EcRBsFAADeG/3M/HteAAAAAElFTkSuQmCC") repeat; } + .codemirror-colorpicker > .control > .opacity > .opacity-container > .color-bar { + position: absolute; + display: block; + content: ""; + left: 0px; + right: 0px; + bottom: 0px; + top: 0px; + background: -webkit-gradient(linear, left top, right top, from(rgba(232, 232, 232, 0)), to(#e8e8e8)); + background: linear-gradient(to right, rgba(232, 232, 232, 0), #e8e8e8); } + .codemirror-colorpicker > .control > .empty { + background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAJElEQVQYV2NctWrVfwYkEBYWxojMZ6SDAmT7QGx0K1EcRBsFAADeG/3M/HteAAAAAElFTkSuQmCC") repeat; } + .codemirror-colorpicker > .control .drag-bar, + .codemirror-colorpicker > .control .drag-bar2 { + border: 1px solid rgba(0, 0, 0, 0.05); + -webkit-box-shadow: 2px 2px 2px 0px rgba(0, 0, 0, 0.2); + box-shadow: 2px 2px 2px 0px rgba(0, 0, 0, 0.2); + background-color: #fefefe; } + .codemirror-colorpicker > .information { + /*border-top: 1px solid #e8e8e8;*/ + position: relative; + -webkit-box-sizing: padding-box; + box-sizing: padding-box; } + .codemirror-colorpicker > .information > input { + position: absolute; + font-size: 10px; + height: 20px; + bottom: 20px; + padding: 0 0 0 2px; + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-user-select: text; + -moz-user-select: text; + -ms-user-select: text; + user-select: text; } + .codemirror-colorpicker > .information > input[type=number] { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; } + .codemirror-colorpicker > .information > input[type=number]::-webkit-inner-spin-button, .codemirror-colorpicker > .information > input[type=number]::-webkit-outer-spin-button { + -webkit-appearance: none; + appearance: none; + margin: 0; } + .codemirror-colorpicker > .information.hex > .information-item.hex { + display: -webkit-box; + display: -ms-flexbox; + display: flex; } + .codemirror-colorpicker > .information.rgb > .information-item.rgb { + display: -webkit-box; + display: -ms-flexbox; + display: flex; } + .codemirror-colorpicker > .information.hsl > .information-item.hsl { + display: -webkit-box; + display: -ms-flexbox; + display: flex; } + .codemirror-colorpicker > .information > .information-item { + display: none; + position: relative; + padding: 0px 5px; + padding-left: 9px; + -webkit-box-sizing: border-box; + box-sizing: border-box; + margin-right: 40px; } + .codemirror-colorpicker > .information > .information-item > .input-field { + display: block; + -webkit-box-flex: 1; + -ms-flex: 1; + flex: 1; + padding: 3px; + -webkit-box-sizing: border-box; + box-sizing: border-box; + position: relative; } + .codemirror-colorpicker > .information > .information-item > .input-field > .title { + text-align: center; + font-size: 12px; + color: #a9a9a9; + padding-top: 2px; } + .codemirror-colorpicker > .information > .information-item > .input-field input { + text-align: center; + width: 100%; + padding: 3px; + height: 21px; + font-size: 11px; + color: #333; + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-user-select: text; + -moz-user-select: text; + -ms-user-select: text; + user-select: text; + border: 1px solid #cbcbcb; + border-radius: 2px; } + .codemirror-colorpicker > .information > .information-item > .input-field input[type=number] { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; } + .codemirror-colorpicker > .information > .information-item > .input-field input[type=number]::-webkit-inner-spin-button, .codemirror-colorpicker > .information > .information-item > .input-field input[type=number]::-webkit-outer-spin-button { + -webkit-appearance: none; + appearance: none; + margin: 0; } + .codemirror-colorpicker > .information > .information-item > .input-field.hsl-l input[type=number], .codemirror-colorpicker > .information > .information-item > .input-field.hsl-s input[type=number] { + padding-left: 1px; + padding-right: 10px; } + .codemirror-colorpicker > .information > .information-item > .input-field .postfix { + display: inline-block; + position: absolute; + right: 4px; + top: 2px; + height: 21px; + line-height: 2; + padding: 2px; + -webkit-box-sizing: border-box; + box-sizing: border-box; + text-align: center; + font-size: 11px; } + .codemirror-colorpicker > .information > .information-change { + position: absolute; + display: block; + width: 40px; + top: 0px; + right: 0px; + bottom: 0px; + text-align: center; + -webkit-box-sizing: border-box; + box-sizing: border-box; + padding-top: 5px; } + .codemirror-colorpicker > .information > .information-change > .format-change-button { + -webkit-box-sizing: border-box; + box-sizing: border-box; + background: transparent; + border: 0px; + cursor: pointer; + outline: none; } + .codemirror-colorpicker > .information > .title { + color: #a3a3a3; } + .codemirror-colorpicker > .information > .input { + color: #333; } + .codemirror-colorpicker > .colorsets { + border-top: 1px solid #e2e2e2; } + .codemirror-colorpicker > .colorsets > .menu { + float: right; + padding: 10px 5px; + padding-right: 15px; } + .codemirror-colorpicker > .colorsets > .menu button { + border: 0px; + font-size: 14px; + font-weight: 300; + font-family: serif, sans-serif; + outline: none; + cursor: pointer; } + .codemirror-colorpicker > .colorsets > .color-list { + margin-right: 30px; + display: block; + padding: 12px 0px 0px 12px; + -webkit-box-sizing: border-box; + box-sizing: border-box; + line-height: 0; } + .codemirror-colorpicker > .colorsets > .color-list .color-item { + width: 13px; + height: 13px; + border-radius: 2px; + display: inline-block; + margin-right: 12px; + margin-bottom: 12px; + position: relative; + background-size: contain; + overflow: hidden; + -webkit-box-sizing: border-box; + box-sizing: border-box; + cursor: pointer; + vertical-align: middle; } + .codemirror-colorpicker > .colorsets > .color-list .color-item:hover { + -webkit-transform: scale(1.2); + transform: scale(1.2); } + .codemirror-colorpicker > .colorsets > .color-list .color-item .empty { + position: absolute; + left: 0px; + top: 0px; + background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAJElEQVQYV2NctWrVfwYkEBYWxojMZ6SDAmT7QGx0K1EcRBsFAADeG/3M/HteAAAAAElFTkSuQmCC") repeat; + width: 100%; + height: 100%; + padding: 0px; + margin: 0px; + pointer-events: none; } + .codemirror-colorpicker > .colorsets > .color-list .color-item .color-view { + position: absolute; + left: 0px; + top: 0px; + width: 100%; + height: 100%; + padding: 0px; + margin: 0px; + pointer-events: none; + border: 1px solid rgba(0, 0, 0, 0.1); + -webkit-box-sizing: border-box; + box-sizing: border-box; } + .codemirror-colorpicker > .colorsets > .color-list .add-color-item { + width: 13px; + height: 13px; + display: inline-block; + margin-right: 12px; + margin-bottom: 12px; + cursor: pointer; + line-height: 1; + text-align: center; + font-size: 16px; + font-weight: 400; + font-family: serif,sans-serif; + color: #8e8e8e; + vertical-align: middle; } + .codemirror-colorpicker > .color-chooser { + position: absolute; + left: 0px; + right: 0px; + bottom: 0px; + top: 0px; + opacity: 0; + background-color: rgba(0, 0, 0, 0.5); + -webkit-transition: opacity 0.05s ease-out; + transition: opacity 0.05s ease-out; + pointer-events: none; } + .codemirror-colorpicker > .color-chooser.open { + opacity: 1; + pointer-events: all; } + .codemirror-colorpicker > .color-chooser .color-chooser-container { + position: absolute; + top: 120px; + left: 0px; + right: 0px; + bottom: 0px; + background-color: white; } + .codemirror-colorpicker > .color-chooser .color-chooser-container .colorsets-item-header { + position: absolute; + top: 0px; + left: 0px; + right: 0px; + height: 34px; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + padding: 3px 0px; + -webkit-box-sizing: border-box; + box-sizing: border-box; + border-bottom: 1px solid rgba(0, 0, 0, 0.2); } + .codemirror-colorpicker > .color-chooser .color-chooser-container .colorsets-item-header .title { + -webkit-box-flex: 2; + -ms-flex: 2; + flex: 2; + font-weight: bold; + font-size: 15px; + -webkit-box-sizing: border-box; + box-sizing: border-box; + margin-right: 30px; + vertical-align: middle; + margin: 0px; + padding: 5px; + padding-left: 14px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } + .codemirror-colorpicker > .color-chooser .color-chooser-container .colorsets-item-header .items { + -webkit-box-flex: 1; + -ms-flex: 1; + flex: 1; + text-align: right; + padding-right: 10px; + display: block; + height: 100%; + line-height: 1.6; + cursor: pointer; } + .codemirror-colorpicker > .color-chooser .color-chooser-container .colorsets-list { + position: absolute; + top: 34px; + left: 0px; + right: 0px; + bottom: 0px; + overflow: auto; } + .codemirror-colorpicker > .color-chooser .color-chooser-container .colorsets-list .colorsets-item { + cursor: pointer; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + padding: 3px 0px; + border-bottom: 1px solid rgba(0, 0, 0, 0.1); } + .codemirror-colorpicker > .color-chooser .color-chooser-container .colorsets-list .colorsets-item:hover { + background-color: rgba(0, 0, 0, 0.05); } + .codemirror-colorpicker > .color-chooser .color-chooser-container .colorsets-list .colorsets-item .title { + -webkit-box-flex: 2; + -ms-flex: 2; + flex: 2; + font-size: 14px; + -webkit-box-sizing: border-box; + box-sizing: border-box; + margin-right: 30px; + vertical-align: middle; + pointer-events: none; + margin: 0px; + padding: 5px; + padding-left: 14px; + font-weight: normal; + font-size: 13px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } + .codemirror-colorpicker > .color-chooser .color-chooser-container .colorsets-list .colorsets-item .items { + -webkit-box-flex: 3; + -ms-flex: 3; + flex: 3; + display: block; + height: 100%; + line-height: 1.6; + cursor: pointer; + pointer-events: none; } + .codemirror-colorpicker > .color-chooser .color-chooser-container .colorsets-list .colorsets-item .items .color-item { + width: 13px; + height: 13px; + border-radius: 3px; + display: inline-block; + margin-right: 10px; + background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAJElEQVQYV2NctWrVfwYkEBYWxojMZ6SDAmT7QGx0K1EcRBsFAADeG/3M/HteAAAAAElFTkSuQmCC") repeat; + background-size: contain; + border: 1px solid #dddddd; + overflow: hidden; + -webkit-box-sizing: border-box; + box-sizing: border-box; + cursor: pointer; + vertical-align: middle; } + .codemirror-colorpicker > .color-chooser .color-chooser-container .colorsets-list .colorsets-item .items .color-item .color-view { + width: 100%; + height: 100%; + padding: 0px; + margin: 0px; + pointer-events: none; } + .codemirror-colorpicker.sketch { + border-radius: 5px; } + .codemirror-colorpicker.sketch > .color { + margin: 10px 10px 2px 10px; + -webkit-box-sizing: border-box; + box-sizing: border-box; + height: 150px; } + .codemirror-colorpicker.sketch > .control { + padding: 0px; } + .codemirror-colorpicker.sketch > .control > .color, .codemirror-colorpicker.sketch > .control > .empty { + position: absolute; + right: 10px; + left: auto; + top: 1px; + width: 26px; + height: 26px; + border-radius: 2px; + -webkit-box-sizing: border-box; + box-sizing: border-box; } + .codemirror-colorpicker.sketch > .control > .color { + -webkit-box-shadow: inset 0px 0px 1px 0px rgba(0, 0, 0, 0.5); + box-shadow: inset 0px 0px 1px 0px rgba(0, 0, 0, 0.5); } + .codemirror-colorpicker.sketch > .control > .hue { + position: relative; + padding: 2px 2px 2px 10px; + margin: 0px 38px 0px 0px; } + .codemirror-colorpicker.sketch > .control > .hue > .hue-container { + border-radius: 0px; } + .codemirror-colorpicker.sketch > .control > .opacity { + position: relative; + padding: 2px 2px 2px 10px; + margin: 0px 38px 0px 0px; } + .codemirror-colorpicker.sketch > .control > .opacity > .opacity-container { + border-radius: 0px; } + .codemirror-colorpicker.sketch > .control .drag-bar, .codemirror-colorpicker.sketch > .control .drag-bar2 { + border-radius: 0px; + top: 0px !important; + left: -2px; + margin-top: 1px !important; + width: 2px; + height: auto; + border-radius: 1px; + bottom: 1px !important; } + .codemirror-colorpicker.sketch > .information .information-change { + display: none; } + .codemirror-colorpicker.sketch > .information.rgb .information-item.rgb { + display: inherit; } + .codemirror-colorpicker.sketch > .information.hex .information-item.hex { + display: inherit; } + .codemirror-colorpicker.sketch > .information .information-item { + display: -webkit-inline-box !important; + display: -ms-inline-flexbox !important; + display: inline-flex !important; + margin-right: 0px; } + .codemirror-colorpicker.sketch > .information .information-item > .input-field > .title { + color: black; + font-size: 11px; } + .codemirror-colorpicker.sketch > .information .information-item > .input-field:last-child:not(:first-child) { + padding-right: 0px; } + .codemirror-colorpicker.sketch > .information .information-item.hsl { + display: none !important; } + .codemirror-colorpicker.sketch > .information .information-item.hex { + width: 80px; + padding-right: 0px; + padding-left: 5px; } + .codemirror-colorpicker.sketch > .information .information-item.rgb { + width: 140px; + padding-left: 0px; } + .codemirror-colorpicker.sketch > .colorsets > .menu { + display: none; } + .codemirror-colorpicker.sketch > .colorsets > .color-list { + margin-right: 0px; + padding-right: 12px; } + .codemirror-colorpicker.sketch > .colorsets > .color-list .color-item { + width: 16px; + height: 16px; + border-radius: 3px; + margin-right: 9px; + margin-bottom: 10px; } + .codemirror-colorpicker.palette { + border-radius: 3px; + -webkit-box-shadow: none; + box-shadow: none; } + .codemirror-colorpicker.palette > .color { + display: none; } + .codemirror-colorpicker.palette > .control { + display: none; } + .codemirror-colorpicker.palette > .information { + display: none; } + .codemirror-colorpicker.palette > .colorsets { + -webkit-box-sizing: border-box; + box-sizing: border-box; + border-top: 0px; } + .codemirror-colorpicker.palette > .colorsets > .color-list .color-item { + width: 15px; + height: 15px; + margin-right: 10px; + margin-bottom: 10px; } + .codemirror-colorpicker.palette > .color-chooser { + display: none; + -webkit-box-sizing: border-box; + box-sizing: border-box; } + .codemirror-colorpicker.palette > .color-chooser.open { + display: block; + top: -1px; + left: -1px; + right: -1px; + bottom: auto; + border-radius: 3px; + border: 1px solid #d8d8d8; + -webkit-box-shadow: 0 0px 10px 2px rgba(0, 0, 0, 0.12); + box-shadow: 0 0px 10px 2px rgba(0, 0, 0, 0.12); } + .codemirror-colorpicker.palette > .color-chooser.open .color-chooser-container { + position: relative; + top: auto; + left: auto; + right: auto; + bottom: auto; + background-color: white; + -webkit-box-sizing: border-box; + box-sizing: border-box; + border-radius: 3px; } + .codemirror-colorpicker.palette > .color-chooser.open .color-chooser-container .colorsets-item-header { + position: relative; + left: auto; + top: auto; + right: auto; + bottom: auto; + border-top-left-radius: 3px; + border-top-right-radius: 3px; } + .codemirror-colorpicker.palette > .color-chooser.open .color-chooser-container .colorsets-list { + position: relative; + top: auto; + left: auto; + right: auto; + bottom: auto; + overflow: auto; } + .codemirror-colorpicker.palette > .color-chooser.open .color-chooser-container .colorsets-list .colorsets-item:last-child { + border-bottom-left-radius: 3px; + border-bottom-right-radius: 3px; } + +.colorsets-contextmenu { + position: fixed; + padding-top: 4px; + padding-bottom: 4px; + border-radius: 6px; + background-color: #ececec; + border: 1px solid #cccccc; + display: none; + list-style: none; + font-size: 13px; + padding-left: 0px; + padding-right: 0px; } + .colorsets-contextmenu.show { + display: inline-block; } + .colorsets-contextmenu .menu-item { + padding: 2px 20px; + cursor: default; } + .colorsets-contextmenu .menu-item:hover { + background-color: #5ea3fb; + color: white; } + .colorsets-contextmenu.small .menu-item.small-hide { + display: none; } diff --git a/frontend/public/css/codemirror.css b/frontend/public/css/codemirror.css new file mode 100644 index 00000000..c7a8ae70 --- /dev/null +++ b/frontend/public/css/codemirror.css @@ -0,0 +1,346 @@ +/* BASICS */ + +.CodeMirror { + /* Set height, width, borders, and global font properties here */ + font-family: monospace; + height: 300px; + color: black; + direction: ltr; +} + +/* PADDING */ + +.CodeMirror-lines { + padding: 4px 0; /* Vertical padding around content */ +} +.CodeMirror pre { + padding: 0 4px; /* Horizontal padding of content */ +} + +.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { + background-color: white; /* The little square between H and V scrollbars */ +} + +/* GUTTER */ + +.CodeMirror-gutters { + border-right: 1px solid #ddd; + background-color: #f7f7f7; + white-space: nowrap; +} +.CodeMirror-linenumbers {} +.CodeMirror-linenumber { + padding: 0 3px 0 5px; + min-width: 20px; + text-align: right; + color: #999; + white-space: nowrap; +} + +.CodeMirror-guttermarker { color: black; } +.CodeMirror-guttermarker-subtle { color: #999; } + +/* CURSOR */ + +.CodeMirror-cursor { + border-left: 1px solid black; + border-right: none; + width: 0; +} +/* Shown when moving in bi-directional text */ +.CodeMirror div.CodeMirror-secondarycursor { + border-left: 1px solid silver; +} +.cm-fat-cursor .CodeMirror-cursor { + width: auto; + border: 0 !important; + background: #7e7; +} +.cm-fat-cursor div.CodeMirror-cursors { + z-index: 1; +} +.cm-fat-cursor-mark { + background-color: rgba(20, 255, 20, 0.5); + -webkit-animation: blink 1.06s steps(1) infinite; + -moz-animation: blink 1.06s steps(1) infinite; + animation: blink 1.06s steps(1) infinite; +} +.cm-animate-fat-cursor { + width: auto; + border: 0; + -webkit-animation: blink 1.06s steps(1) infinite; + -moz-animation: blink 1.06s steps(1) infinite; + animation: blink 1.06s steps(1) infinite; + background-color: #7e7; +} +@-moz-keyframes blink { + 0% {} + 50% { background-color: transparent; } + 100% {} +} +@-webkit-keyframes blink { + 0% {} + 50% { background-color: transparent; } + 100% {} +} +@keyframes blink { + 0% {} + 50% { background-color: transparent; } + 100% {} +} + +/* Can style cursor different in overwrite (non-insert) mode */ +.CodeMirror-overwrite .CodeMirror-cursor {} + +.cm-tab { display: inline-block; text-decoration: inherit; } + +.CodeMirror-rulers { + position: absolute; + left: 0; right: 0; top: -50px; bottom: -20px; + overflow: hidden; +} +.CodeMirror-ruler { + border-left: 1px solid #ccc; + top: 0; bottom: 0; + position: absolute; +} + +/* DEFAULT THEME */ + +.cm-s-default .cm-header {color: blue;} +.cm-s-default .cm-quote {color: #090;} +.cm-negative {color: #d44;} +.cm-positive {color: #292;} +.cm-header, .cm-strong {font-weight: bold;} +.cm-em {font-style: italic;} +.cm-link {text-decoration: underline;} +.cm-strikethrough {text-decoration: line-through;} + +.cm-s-default .cm-keyword {color: #708;} +.cm-s-default .cm-atom {color: #219;} +.cm-s-default .cm-number {color: #164;} +.cm-s-default .cm-def {color: #00f;} +.cm-s-default .cm-variable, +.cm-s-default .cm-punctuation, +.cm-s-default .cm-property, +.cm-s-default .cm-operator {} +.cm-s-default .cm-variable-2 {color: #05a;} +.cm-s-default .cm-variable-3, .cm-s-default .cm-type {color: #085;} +.cm-s-default .cm-comment {color: #a50;} +.cm-s-default .cm-string {color: #a11;} +.cm-s-default .cm-string-2 {color: #f50;} +.cm-s-default .cm-meta {color: #555;} +.cm-s-default .cm-qualifier {color: #555;} +.cm-s-default .cm-builtin {color: #30a;} +.cm-s-default .cm-bracket {color: #997;} +.cm-s-default .cm-tag {color: #170;} +.cm-s-default .cm-attribute {color: #00c;} +.cm-s-default .cm-hr {color: #999;} +.cm-s-default .cm-link {color: #00c;} + +.cm-s-default .cm-error {color: #f00;} +.cm-invalidchar {color: #f00;} + +.CodeMirror-composing { border-bottom: 2px solid; } + +/* Default styles for common addons */ + +div.CodeMirror span.CodeMirror-matchingbracket {color: #0b0;} +div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;} +.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); } +.CodeMirror-activeline-background {background: #e8f2ff;} + +/* STOP */ + +/* The rest of this file contains styles related to the mechanics of + the editor. You probably shouldn't touch them. */ + +.CodeMirror { + position: relative; + overflow: hidden; + background: white; +} + +.CodeMirror-scroll { + overflow: scroll !important; /* Things will break if this is overridden */ + /* 30px is the magic margin used to hide the element's real scrollbars */ + /* See overflow: hidden in .CodeMirror */ + margin-bottom: -30px; margin-right: -30px; + padding-bottom: 30px; + height: 100%; + outline: none; /* Prevent dragging from highlighting the element */ + position: relative; +} +.CodeMirror-sizer { + position: relative; + border-right: 30px solid transparent; +} + +/* The fake, visible scrollbars. Used to force redraw during scrolling + before actual scrolling happens, thus preventing shaking and + flickering artifacts. */ +.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { + position: absolute; + z-index: 6; + display: none; +} +.CodeMirror-vscrollbar { + right: 0; top: 0; + overflow-x: hidden; + overflow-y: scroll; +} +.CodeMirror-hscrollbar { + bottom: 0; left: 0; + overflow-y: hidden; + overflow-x: scroll; +} +.CodeMirror-scrollbar-filler { + right: 0; bottom: 0; +} +.CodeMirror-gutter-filler { + left: 0; bottom: 0; +} + +.CodeMirror-gutters { + position: absolute; left: 0; top: 0; + min-height: 100%; + z-index: 3; +} +.CodeMirror-gutter { + white-space: normal; + height: 100%; + display: inline-block; + vertical-align: top; + margin-bottom: -30px; +} +.CodeMirror-gutter-wrapper { + position: absolute; + z-index: 4; + background: none !important; + border: none !important; +} +.CodeMirror-gutter-background { + position: absolute; + top: 0; bottom: 0; + z-index: 4; +} +.CodeMirror-gutter-elt { + position: absolute; + cursor: default; + z-index: 4; +} +.CodeMirror-gutter-wrapper ::selection { background-color: transparent } +.CodeMirror-gutter-wrapper ::-moz-selection { background-color: transparent } + +.CodeMirror-lines { + cursor: text; + min-height: 1px; /* prevents collapsing before first draw */ +} +.CodeMirror pre { + /* Reset some styles that the rest of the page might have set */ + -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0; + border-width: 0; + background: transparent; + font-family: inherit; + font-size: inherit; + margin: 0; + white-space: pre; + word-wrap: normal; + line-height: inherit; + color: inherit; + z-index: 2; + position: relative; + overflow: visible; + -webkit-tap-highlight-color: transparent; + -webkit-font-variant-ligatures: contextual; + font-variant-ligatures: contextual; +} +.CodeMirror-wrap pre { + word-wrap: break-word; + white-space: pre-wrap; + word-break: normal; +} + +.CodeMirror-linebackground { + position: absolute; + left: 0; right: 0; top: 0; bottom: 0; + z-index: 0; +} + +.CodeMirror-linewidget { + position: relative; + z-index: 2; + padding: 0.1px; /* Force widget margins to stay inside of the container */ +} + +.CodeMirror-widget {} + +.CodeMirror-rtl pre { direction: rtl; } + +.CodeMirror-code { + outline: none; +} + +/* Force content-box sizing for the elements where we expect it */ +.CodeMirror-scroll, +.CodeMirror-sizer, +.CodeMirror-gutter, +.CodeMirror-gutters, +.CodeMirror-linenumber { + -moz-box-sizing: content-box; + box-sizing: content-box; +} + +.CodeMirror-measure { + position: absolute; + width: 100%; + height: 0; + overflow: hidden; + visibility: hidden; +} + +.CodeMirror-cursor { + position: absolute; + pointer-events: none; +} +.CodeMirror-measure pre { position: static; } + +div.CodeMirror-cursors { + visibility: hidden; + position: relative; + z-index: 3; +} +div.CodeMirror-dragcursors { + visibility: visible; +} + +.CodeMirror-focused div.CodeMirror-cursors { + visibility: visible; +} + +.CodeMirror-selected { background: #d9d9d9; } +.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; } +.CodeMirror-crosshair { cursor: crosshair; } +.CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; } +.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; } + +.cm-searching { + background-color: #ffa; + background-color: rgba(255, 255, 0, .4); +} + +/* Used to force a border model for a node */ +.cm-force-border { padding-right: .1px; } + +@media print { + /* Hide the cursor when printing */ + .CodeMirror div.CodeMirror-cursors { + visibility: hidden; + } +} + +/* See issue #2901 */ +.cm-tab-wrap-hack:after { content: ''; } + +/* Help users use markselection to safely style text background */ +span.CodeMirror-selectedtext { background: none; } diff --git a/frontend/public/img/banner.png b/frontend/public/img/banner.png new file mode 100644 index 0000000000000000000000000000000000000000..5aa272e142dd97600531d24ddec845dfb93e2159 GIT binary patch literal 98711 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 u=e[Math.floor(s()*e.length)];n=!i(u,h),o[l]=u}return n}function h(t,e,r){var i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:10,s=arguments.length>4&&void 0!==arguments[4]?arguments[4]:"linear";t=t,e=e||Math.max(2,Math.ceil(Math.sqrt(t.length/2)));var a=r||"euclidean";"string"==typeof a&&(a=o[a]);for(var h=0,u=function(){return(h=(9301*h+49297)%233280)/233280},f=function(t,e){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"linear";return n[r](t.length,e).map(function(e){return t[e]})}(t,e,s),d=!0,v=0;d;){if(d=c(e,t,l(e,t,f,a),f,!1,u),++v%i==0)break}return f}var u="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},f=function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")},d=function(){function t(t,e){for(var r=0;r1&&void 0!==arguments[1]?arguments[1]:{};f(this,t),this.isLoaded=!1,this.imageUrl=e,this.opt=r,this.initialize()}return d(t,[{key:"initialize",value:function(){this.canvas=this.createCanvas(),this.context=this.canvas.getContext("2d")}},{key:"createCanvas",value:function(){return document.createElement("canvas")}},{key:"load",value:function(t){this.loadImage(t)}},{key:"loadImage",value:function(t){var e=this,r=this.context,i=new Image;i.onload=function(){var o=i.height/i.width;e.opt.canvasWidth&&e.opt.canvasHeight?(e.canvas.width=e.opt.canvasWidth,e.canvas.height=e.opt.canvasHeight):(e.canvas.width=e.opt.maxWidth?e.opt.maxWidth:i.width,e.canvas.height=e.canvas.width*o),r.drawImage(i,0,0,i.width,i.height,0,0,e.canvas.width,e.canvas.height),e.isLoaded=!0,t&&t()},this.getImageUrl(function(t){i.src=t})}},{key:"getImageUrl",value:function(t){if("string"==typeof this.imageUrl)return t(this.imageUrl);if(this.imageUrl instanceof Blob){var e=new FileReader;e.onload=function(e){t(e.target.result)},e.readAsDataURL(this.imageUrl)}}},{key:"getRGBA",value:function(t,e,r,i){return[t,e,r,i]}},{key:"toArray",value:function(t){var e=this.context.getImageData(0,0,this.canvas.width,this.canvas.height);t=t||this.getRGBA;for(var r=e.data,i=[],o=0,n=r.length;o1&&void 0!==arguments[1]&&arguments[1],i=t.match(m),o=[];if(!i)return o;for(var n=0,s=i.length;n-1||i[n].indexOf("rgb")>-1||i[n].indexOf("hsl")>-1)o.push({color:i[n]});else if(e){var a=r.getColorByName(i[n]);a&&o.push({color:i[n],nameColor:a})}var l={next:0};return o.forEach(function(e){var r=t.indexOf(e.color,l.next);e.startIndex=r,e.endIndex=r+e.color.length,l.next=e.endIndex}),o},trim:function(t){return t.replace(/^\s+|\s+$/g,"")},format:function(t,e){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"rgba(0, 0, 0, 0)";if(Array.isArray(t)&&(t={r:t[0],g:t[1],b:t[2],a:t[3]}),"hex"==e){var i=t.r.toString(16);t.r<16&&(i="0"+i);var o=t.g.toString(16);t.g<16&&(o="0"+o);var n=t.b.toString(16);return t.b<16&&(n="0"+n),"#"+i+o+n}if("rgb"==e){if(void 0===t)return;return 1==t.a||void 0===t.a?isNaN(t.r)?r:"rgb("+t.r+","+t.g+","+t.b+")":"rgba("+t.r+","+t.g+","+t.b+","+t.a+")"}return"hsl"==e?1==t.a||void 0===t.a?"hsl("+t.h+","+t.s+"%,"+t.l+"%)":"hsla("+t.h+","+t.s+"%,"+t.l+"%,"+t.a+")":t},parse:function(t){if("string"==typeof t){if(r.isColorName(t)&&(t=r.getColorByName(t)),t.indexOf("rgb(")>-1){for(var e=0,i=(s=t.replace("rgb(","").replace(")","").split(",")).length;e-1){for(e=0,i=(s=t.replace("rgba(","").replace(")","").split(",")).length;e-1){for(e=0,i=(s=t.replace("hsl(","").replace(")","").split(",")).length;e-1){for(e=0,i=(s=t.replace("hsla(","").replace(")","").split(",")).length;e>16,g:(65280&t)>>8,b:(255&t)>>0,a:1};if(0<=t&&t<=4294967295)return{type:"hex",r:(4278190080&t)>>24,g:(16711680&t)>>16,b:(65280&t)>>8,a:(255&t)/255}}return t},HSVtoRGB:function(t,e,r){if(1==arguments.length){var i=arguments[0];t=i.h,e=i.s,r=i.v}var o=t,n=r;360==o&&(o=0);var s=e*n,a=s*(1-Math.abs(o/60%2-1)),l=n-s,c=[];return 0<=o&&o<60?c=[s,a,0]:60<=o&&o<120?c=[a,s,0]:120<=o&&o<180?c=[0,s,a]:180<=o&&o<240?c=[0,a,s]:240<=o&&o<300?c=[a,0,s]:300<=o&&o<360&&(c=[s,0,a]),{r:Math.round(255*(c[0]+l)),g:Math.round(255*(c[1]+l)),b:Math.round(255*(c[2]+l))}},RGBtoHSV:function(t,e,r){if(1==arguments.length){var i=arguments[0];t=i.r,e=i.g,r=i.b}var o=t/255,n=e/255,s=r/255,a=Math.max(o,n,s),l=a-Math.min(o,n,s),c=0;0==l?c=0:a==o?c=(n-s)/l%6*60:a==n?c=60*((s-o)/l+2):a==s&&(c=60*((o-n)/l+4)),c<0&&(c=360+c);return{h:c,s:0==a?0:l/a,v:a}},HSVtoHSL:function(t,e,r){if(1==arguments.length){var i=arguments[0];t=i.h,e=i.s,r=i.v}var o=this.HSVtoRGB(t,e,r);return this.RGBtoHSL(o.r,o.g,o.b)},RGBtoCMYK:function(t,e,r){if(1==arguments.length){var i=arguments[0];t=i.r,e=i.g,r=i.b}var o=t/255,n=e/255,s=r/255,a=1-Math.max(o,n,s);return{c:(1-o-a)/(1-a),m:(1-n-a)/(1-a),y:(1-s-a)/(1-a),k:a}},CMYKtoRGB:function(t,e,r,i){if(1==arguments.length){var o=arguments[0];t=o.c,e=o.m,r=o.y,i=o.k}return{r:255*(1-t)*(1-i),g:255*(1-e)*(1-i),b:255*(1-r)*(1-i)}},RGBtoHSL:function(t,e,r){if(1==arguments.length){var i=arguments[0];t=i.r,e=i.g,r=i.b}t/=255,e/=255,r/=255;var o,n,s=Math.max(t,e,r),a=Math.min(t,e,r),l=(s+a)/2;if(s==a)o=n=0;else{var c=s-a;switch(n=l>.5?c/(2-s-a):c/(s+a),s){case t:o=(e-r)/c+(e1&&(r-=1),r<1/6?t+6*(e-t)*r:r<.5?e:r<2/3?t+(e-t)*(2/3-r)*6:t},HSLtoHSV:function(t,e,r){if(1==arguments.length){var i=arguments[0];t=i.h,e=i.s,i.v}var o=this.HSLtoRGB(t,e,r);return this.RGBtoHSV(o.r,o.g,o.b)},HSLtoRGB:function(t,e,r){if(1==arguments.length){var i=arguments[0];t=i.h,e=i.s,i.v}var o,n,s;if(t/=360,r/=100,0==(e/=100))o=n=s=r;else{var a=r<.5?r*(1+e):r+e-r*e,l=2*r-a;o=this.HUEtoRGB(l,a,t+1/3),n=this.HUEtoRGB(l,a,t),s=this.HUEtoRGB(l,a,t-1/3)}return{r:Math.round(255*o),g:Math.round(255*n),b:Math.round(255*s)}},c:function(t,e,r){if(1==arguments.length){var i=arguments[0];t=i.r,e=i.g,r=i.b}return this.gray((t+e+r)/3>90?0:255)},gray:function(t){return{r:t,g:t,b:t}},RGBtoSimpleGray:function(t,e,r){if(1==arguments.length){var i=arguments[0];t=i.r,e=i.g,r=i.b}return this.gray(Math.ceil((t+e+r)/3))},RGBtoGray:function(t,e,r){if(1==arguments.length){var i=arguments[0];t=i.r,e=i.g,r=i.b}return this.gray(this.RGBtoYCrCb(t,e,r).y)},RGBtoYCrCb:function(t,e,r){if(1==arguments.length){var i=arguments[0];t=i.r,e=i.g,r=i.b}var o=.2126*t+.7152*e+.0722*r,n=.564*(r-o),s=.713*(t-o);return{y:Math.ceil(o),cr:s,cb:n}},YCrCbtoRGB:function(t,e,r){var i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:0;if(1==arguments.length){var o=arguments[0],n=(t=o.y,e=o.cr,r=o.cb,o.bit);i=void 0===n?0:n}var s=t+1.402*(e-i),a=t-.344*(r-i)-.714*(e-i),l=t+1.772*(r-i);return{r:Math.ceil(s),g:Math.ceil(a),b:Math.ceil(l)}},interpolateRGB:function(t,e,r){var i={r:parseInt(t.r+(e.r-t.r)*r,10),g:parseInt(t.g+(e.g-t.g)*r,10),b:parseInt(t.b+(e.b-t.b)*r,10)};return y.format(i,"hex")},scale:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:5;if(!t)return[];for(var r=(t=t||[]).length,i=[],o=0;o1&&void 0!==arguments[1]?arguments[1]:"h",r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:9,i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"rgb",o=arguments.length>4&&void 0!==arguments[4]?arguments[4]:0,n=arguments.length>5&&void 0!==arguments[5]?arguments[5]:1,s=arguments.length>6&&void 0!==arguments[6]?arguments[6]:100,a=this.parse(t),l=this.RGBtoHSV(a),c=(n-o)*s/r,h=[],u=1;u<=r;u++)l[e]=Math.abs((s-c*u)/s),h.push(this.format(this.HSVtoRGB(l),i));return h},scaleH:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:9,r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"rgb",i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:0,o=arguments.length>4&&void 0!==arguments[4]?arguments[4]:360;return this.scaleHSV(t,"h",e,r,i,o,1)},scaleS:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:9,r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"rgb",i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:0,o=arguments.length>4&&void 0!==arguments[4]?arguments[4]:1;return this.scaleHSV(t,"s",e,r,i,o,100)},scaleV:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:9,r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"rgb",i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:0,o=arguments.length>4&&void 0!==arguments[4]?arguments[4]:1;return this.scaleHSV(t,"v",e,r,i,o,100)},palette:function(t){var e=this,r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:6,i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"hex";return t.length>r&&(t=h(t,r)),t.map(function(t){return e.format(t,i)})},ImageToRGB:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},r=arguments[2];if(r){if(r){var i;(i=new k(t,e)).loadImage(function(){"function"==typeof r&&r(i.toRGB())})}}else(i=new k(t)).loadImage(function(){"function"==typeof e&&e(i.toRGB())})}};y.scale.parula=function(t){return y.scale(["#352a87","#0f5cdd","#00b5a6","#ffc337","#fdff00"],t)},y.scale.jet=function(t){return y.scale(["#00008f","#0020ff","#00ffff","#51ff77","#fdff00","#ff0000","#800000"],t)},y.scale.hsv=function(t){return y.scale(["#ff0000","#ffff00","#00ff00","#00ffff","#0000ff","#ff00ff","#ff0000"],t)},y.scale.hot=function(t){return y.scale(["#0b0000","#ff0000","#ffff00","#ffffff"],t)},y.scale.pink=function(t){return y.scale(["#1e0000","#bd7b7b","#e7e5b2","#ffffff"],t)},y.scale.bone=function(t){return y.scale(["#000000","#4a4a68","#a6c6c6","#ffffff"],t)},y.scale.copper=function(t){return y.scale(["#000000","#3d2618","#9d623e","#ffa167","#ffc77f"],t)};var b=[{rgb:"#ff0000",start:0},{rgb:"#ffff00",start:.17},{rgb:"#00ff00",start:.33},{rgb:"#00ffff",start:.5},{rgb:"#0000ff",start:.67},{rgb:"#ff00ff",start:.83},{rgb:"#ff0000",start:1}];!function(){for(var t=0,e=b.length;t=t){e=b[i-1],r=b[i];break}return e&&r?y.interpolateRGB(e,r,(t-e.start)/(r.start-e.start)):b[0].rgb}},_=0,$=[],w=function(){function t(e,r,i){if(f(this,t),"string"!=typeof e)this.el=e;else{var o=document.createElement(e);for(var n in this.uniqId=_++,r&&(o.className=r),i=i||{})o.setAttribute(n,i[n]);this.el=o}}return d(t,[{key:"attr",value:function(t,e){return 1==arguments.length?this.el.getAttribute(t):(this.el.setAttribute(t,e),this)}},{key:"closest",value:function(e){for(var r=this,i=!1;!(i=r.hasClass(e));){if(!r.el.parentNode)return null;r=new t(r.el.parentNode)}return i?r:null}},{key:"removeClass",value:function(t){this.el.className=(" "+this.el.className+" ").replace(" "+t+" "," ").trim()}},{key:"hasClass",value:function(t){return!!this.el.className&&(" "+this.el.className+" ").indexOf(" "+t+" ")>-1}},{key:"addClass",value:function(t){this.hasClass(t)||(this.el.className=this.el.className+" "+t)}},{key:"toggleClass",value:function(t){this.hasClass(t)?this.removeClass(t):this.addClass(t)}},{key:"html",value:function(t){return"string"==typeof t?this.el.innerHTML=t:this.empty().append(t),this}},{key:"empty",value:function(){return this.html("")}},{key:"append",value:function(t){return"string"==typeof t?this.el.appendChild(document.createTextNode(t)):this.el.appendChild(t.el||t),this}},{key:"appendTo",value:function(t){return(t.el?t.el:t).appendChild(this.el),this}},{key:"remove",value:function(){return this.el.parentNode&&this.el.parentNode.removeChild(this.el),this}},{key:"text",value:function(){return this.el.textContent}},{key:"css",value:function(t,e){var r=this;if(2==arguments.length)this.el.style[t]=e;else if(1==arguments.length){if("string"==typeof t)return getComputedStyle(this.el)[t];var i=t||{};Object.keys(i).forEach(function(t){r.el.style[t]=i[t]})}return this}},{key:"cssFloat",value:function(t){return parseFloat(this.css(t))}},{key:"cssInt",value:function(t){return parseInt(this.css(t))}},{key:"offset",value:function(){var t=this.el.getBoundingClientRect();return{top:t.top+document.body.scrollTop,left:t.left+document.body.scrollLeft}}},{key:"position",value:function(){return this.el.style.top?{top:parseFloat(this.css("top")),left:parseFloat(this.css("left"))}:this.el.getBoundingClientRect()}},{key:"width",value:function(){return this.el.offsetWidth}},{key:"contentWidth",value:function(){return this.width()-this.cssFloat("padding-left")-this.cssFloat("padding-right")}},{key:"height",value:function(){return this.el.offsetHeight}},{key:"contentHeight",value:function(){return this.height()-this.cssFloat("padding-top")-this.cssFloat("padding-bottom")}},{key:"dataKey",value:function(t){return this.uniqId+"."+t}},{key:"data",value:function(t,e){if(2!=arguments.length){if(1==arguments.length)return $[this.dataKey(t)];var r=Object.keys($),i=this.uniqId+".";return r.filter(function(t){return 0==t.indexOf(i)}).map(function(t){return $[t]})}return $[this.dataKey(t)]=e,this}},{key:"val",value:function(t){return 0==arguments.length?this.el.value:(1==arguments.length&&(this.el.value=t),this)}},{key:"int",value:function(){return parseInt(this.val(),10)}},{key:"float",value:function(){return parseFloat(this.val())}},{key:"show",value:function(){return this.css("display","block")}},{key:"hide",value:function(){return this.css("display","none")}},{key:"toggle",value:function(){return"none"==this.css("display")?this.show():this.hide()}},{key:"on",value:function(t,e,r,i){return this.el.addEventListener(t,e,r,i),this}},{key:"off",value:function(t,e){return this.el.removeEventListener(t,e),this}},{key:"getElement",value:function(){return this.el}},{key:"createChild",value:function(e){var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{},n=new t(e,r,i);return n.css(o),this.append(n),n}}]),t}(),S={addEvent:function(t,e,r){t.addEventListener(e,r)},removeEvent:function(t,e,r){t.removeEventListener(e,r)},pos:function(t){return t.touches&&t.touches[0]?t.touches[0]:t}},x=function(){function t(e){var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};f(this,t),this.masterObj=e,this.settingObj=r}return d(t,[{key:"set",value:function(t,e){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:void 0;this.settingObj[t]=e||r}},{key:"init",value:function(t){if(!this.has(t)){for(var e=t.split("."),r=this.masterObj[e[0]]||this.masterObj,i=e.pop(),o=arguments.length,n=Array(o>1?o-1:0),s=1;s1&&void 0!==arguments[1]?arguments[1]:"";return this.init(t,e),this.settingObj[t]||e}},{key:"has",value:function(t){return!!this.settingObj[t]}}]),t}(),H=/^(click|mouse(down|up|move|enter|leave)|key(down|up|press)|contextmenu|change|input)/gi,E=["Control","Shift","Alt","Meta"],B=function(){function t(){f(this,t),this.state=new x(this)}return d(t,[{key:"initializeEvent",value:function(){this.initializeEventMachin()}},{key:"destroy",value:function(){this.destroyEventMachin()}},{key:"destroyEventMachin",value:function(){this.removeEventAll()}},{key:"initializeEventMachin",value:function(){this.filterProps(H).forEach(this.parseEvent.bind(this))}},{key:"filterProps",value:function(t){return Object.getOwnPropertyNames(this.__proto__).filter(function(e){return e.match(t)})}},{key:"parseEvent",value:function(t){var e=t.split(" ");this.bindingEvent(e,this[t].bind(this))}},{key:"getDefaultDomElement",value:function(t){var e=void 0;return(e=t?this[t]||window[t]:this.el||this.$el||this.$root)instanceof w?e.getElement():e}},{key:"getDefaultEventObject",value:function(t){var e=this,r=t.split("."),i=r.shift(),o=r.includes("Control"),n=r.includes("Shift"),s=r.includes("Alt"),a=r.includes("Meta"),l=(r=r.filter(function(t){return!1===E.includes(t)})).filter(function(t){return!!e[t]});return{eventName:i,isControl:o,isShift:n,isAlt:s,isMeta:a,codes:r=r.filter(function(t){return!1===l.includes(t)}).map(function(t){return t.toLowerCase()}),checkMethodList:l}}},{key:"bindingEvent",value:function(t,e){var r,i=(r=t,Array.isArray(r)?r:Array.from(r)),o=i[0],n=i[1],s=i.slice(2);n=this.getDefaultDomElement(n);var a=this.getDefaultEventObject(o);a.dom=n,a.delegate=s.join(" "),this.addEvent(a,e)}},{key:"matchPath",value:function(t,e){return t?t.matches(e)?t:this.matchPath(t.parentElement,e):null}},{key:"getBindings",value:function(){return this._bindings||this.initBindings(),this._bindings}},{key:"addBinding",value:function(t){this.getBindings().push(t)}},{key:"initBindings",value:function(){this._bindings=[]}},{key:"checkEventType",value:function(t,e){var r=this,i=!t.ctrlKey||e.isControl,o=!t.shiftKey||e.isShift,n=!t.altKey||e.isAlt,s=!t.metaKey||e.isMeta,a=!0;e.codes.length&&(a=e.codes.includes(t.code.toLowerCase())||e.codes.includes(t.key.toLowerCase()));var l=!0;return e.checkMethodList.length&&(l=e.checkMethodList.every(function(e){return r[e].call(r,t)})),i&&n&&o&&s&&a&&l}},{key:"makeCallback",value:function(t,e){var r=this;return t.delegate?function(i){if(r.checkEventType(i,t)){var o=r.matchPath(i.target||i.srcElement,t.delegate);if(o)return i.delegateTarget=o,i.$delegateTarget=new w(o),e(i)}}:function(i){if(r.checkEventType(i,t))return e(i)}}},{key:"addEvent",value:function(t,e){t.callback=this.makeCallback(t,e),this.addBinding(t),S.addEvent(t.dom,t.eventName,t.callback)}},{key:"removeEventAll",value:function(){var t=this;this.getBindings().forEach(function(e){t.removeEvent(e)}),this.initBindings()}},{key:"removeEvent",value:function(t){var e=t.eventName,r=t.dom,i=t.callback;S.removeEvent(r,e,i)}}]),t}(),M=function(t){function e(t){f(this,e);var r=p(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return r.colorpicker=t,r.initialize(),r}return g(e,B),d(e,[{key:"initialize",value:function(){this.$el=new w("div","control"),this.$hue=this.$el.createChild("div","hue"),this.$opacity=this.$el.createChild("div","opacity"),this.$controlPattern=this.$el.createChild("div","empty"),this.$controlColor=this.$el.createChild("div","color"),this.$hueContainer=this.$hue.createChild("div","hue-container"),this.$drag_bar=this.$hueContainer.createChild("div","drag-bar"),this.drag_bar_pos={},this.$opacityContainer=this.$opacity.createChild("div","opacity-container"),this.$opacityColorBar=this.$opacityContainer.createChild("div","color-bar"),this.$opacity_drag_bar=this.$opacityContainer.createChild("div","drag-bar2"),this.opacity_drag_bar_pos={}}},{key:"setBackgroundColor",value:function(t){this.$controlColor.css("background-color",t)}},{key:"refresh",value:function(){this.setColorUI()}},{key:"setColorUI",value:function(){var t=this.state.get("$el.width")*this.colorpicker.currentS,e=this.state.get("$el.height")*(1-this.colorpicker.currentV);this.$drag_pointer.css({left:t+"px",top:e+"px"})}},{key:"setOpacityColorBar",value:function(t){var e=y.parse(t);e.a=0;var r=y.format(e,"rgb");e.a=1;var i=y.format(e,"rgb");this.$opacityColorBar.css("background","linear-gradient(to right, "+r+", "+i+")")}},{key:"setOpacity",value:function(t){var e,r=this.$opacityContainer.offset().left,i=r+this.state.get("$opacityContainer.width"),o=S.pos(t).clientX;e=oi?100:(o-r)/(i-r)*100;var n=this.state.get("$opacityContainer.width")*(e/100);this.$opacity_drag_bar.css({left:n-Math.ceil(this.state.get("$opacity_drag_bar.width")/2)+"px"}),this.opacity_drag_bar_pos={x:n},this.colorpicker.setCurrentA(this.caculateOpacity()),this.colorpicker.currentFormat(),this.colorpicker.setInputColor()}},{key:"setInputColor",value:function(){this.setBackgroundColor(this.colorpicker.getFormattedColor("rgb"));var t=this.colorpicker.convertRGB(),e=y.format(t,"rgb");this.setOpacityColorBar(e)}},{key:"setColorUI",value:function(){var t=this.state.get("$hueContainer.width")*(this.colorpicker.currentH/360);this.$drag_bar.css({left:t-7.5+"px"}),this.drag_bar_pos={x:t};var e=this.state.get("$opacityContainer.width")*(this.colorpicker.currentA||0);this.$opacity_drag_bar.css({left:e-7.5+"px"}),this.opacity_drag_bar_pos={x:e}}},{key:"caculateH",value:function(){return{h:(this.drag_bar_pos||{x:0}).x/this.state.get("$hueContainer.width")*360}}},{key:"caculateOpacity",value:function(){var t=this.opacity_drag_bar_pos||{x:0},e=Math.round(t.x/this.state.get("$opacityContainer.width")*100)/100;return isNaN(e)?1:e}},{key:"EventDocumentMouseMove",value:function(t){this.isHueDown&&this.setHueColor(t),this.isOpacityDown&&this.setOpacity(t)}},{key:"EventDocumentMouseUp",value:function(t){this.isHueDown=!1,this.isOpacityDown=!1}},{key:"setControlColor",value:function(t){this.$controlColor.css("background-color",t)}},{key:"setHueColor",value:function(t){var e,r=this.$hueContainer.offset().left,i=r+this.state.get("$hueContainer.width"),o=t?S.pos(t).clientX:r+(i-r)*(this.colorpicker.currentH/360);e=oi?100:(o-r)/(i-r)*100;var n=this.state.get("$hueContainer.width")*(e/100);this.$drag_bar.css({left:n-Math.ceil(this.state.get("$drag_bar.width")/2)+"px"}),this.drag_bar_pos={x:n};var s=C.checkHueColor(e/100);this.colorpicker.setBackgroundColor(s),this.colorpicker.setCurrentH(e/100*360),this.colorpicker.setInputColor()}},{key:"setOnlyHueColor",value:function(){var t,e=this.$hueContainer.offset().left,r=e+this.state.get("$hueContainer.width"),i=e+(r-e)*(this.colorpicker.currentH/360);t=ir?100:(i-e)/(r-e)*100;var o=this.state.get("$hueContainer.width")*(t/100);this.$drag_bar.css({left:o-Math.ceil(this.state.get("$drag_bar.width")/2)+"px"}),this.drag_bar_pos={x:o};var n=C.checkHueColor(t/100);this.colorpicker.setBackgroundColor(n),this.colorpicker.setCurrentH(t/100*360)}},{key:"mousedown $drag_bar",value:function(t){t.preventDefault(),this.isHueDown=!0}},{key:"mousedown $opacity_drag_bar",value:function(t){t.preventDefault(),this.isOpacityDown=!0}},{key:"mousedown $hueContainer",value:function(t){this.isHueDown=!0,this.setHueColor(t)}},{key:"mousedown $opacityContainer",value:function(t){this.isOpacityDown=!0,this.setOpacity(t)}}]),e}(),I=function(t){function e(t){f(this,e);var r=p(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return r.colorpicker=t,r.initialize(),r}return g(e,B),d(e,[{key:"initialize",value:function(){this.$el=new w("div","information hex"),this.$informationChange=this.$el.createChild("div","information-change"),this.$formatChangeButton=this.$informationChange.createChild("button","format-change-button arrow-button",{type:"button"}),this.$el.append(this.makeInputFieldHex()),this.$el.append(this.makeInputFieldRgb()),this.$el.append(this.makeInputFieldHsl()),this.format="hex"}},{key:"makeInputFieldHex",value:function(){var t=new w("div","information-item hex"),e=t.createChild("div","input-field hex");return this.$hexCode=e.createChild("input","input",{type:"text"}),e.createChild("div","title").html("HEX"),t}},{key:"makeInputFieldRgb",value:function(){var t=new w("div","information-item rgb"),e=t.createChild("div","input-field rgb-r");return this.$rgb_r=e.createChild("input","input",{type:"number",step:1,min:0,max:255}),e.createChild("div","title").html("R"),e=t.createChild("div","input-field rgb-g"),this.$rgb_g=e.createChild("input","input",{type:"number",step:1,min:0,max:255}),e.createChild("div","title").html("G"),e=t.createChild("div","input-field rgb-b"),this.$rgb_b=e.createChild("input","input",{type:"number",step:1,min:0,max:255}),e.createChild("div","title").html("B"),e=t.createChild("div","input-field rgb-a"),this.$rgb_a=e.createChild("input","input",{type:"number",step:.01,min:0,max:1}),e.createChild("div","title").html("A"),t}},{key:"makeInputFieldHsl",value:function(){var t=new w("div","information-item hsl"),e=t.createChild("div","input-field hsl-h");return this.$hsl_h=e.createChild("input","input",{type:"number",step:1,min:0,max:360}),e.createChild("div","title").html("H"),e=t.createChild("div","input-field hsl-s"),this.$hsl_s=e.createChild("input","input",{type:"number",step:1,min:0,max:100}),e.createChild("div","postfix").html("%"),e.createChild("div","title").html("S"),e=t.createChild("div","input-field hsl-l"),this.$hsl_l=e.createChild("input","input",{type:"number",step:1,min:0,max:100}),e.createChild("div","postfix").html("%"),e.createChild("div","title").html("L"),e=t.createChild("div","input-field hsl-a"),this.$hsl_a=e.createChild("input","input",{type:"number",step:.01,min:0,max:1}),e.createChild("div","title").html("A"),t}},{key:"currentFormat",value:function(){var t=this.format||"hex";if(this.colorpicker.currentA<1&&"hex"==t){this.$el.removeClass(t),this.$el.addClass("rgb"),this.format="rgb",this.colorpicker.setInputColor()}}},{key:"setCurrentFormat",value:function(t){this.format=t,this.initFormat()}},{key:"initFormat",value:function(){var t=this.format||"hex";this.$el.removeClass("hex"),this.$el.removeClass("rgb"),this.$el.removeClass("hsl"),this.$el.addClass(t)}},{key:"nextFormat",value:function(){var t=this.format||"hex",e="hex";"hex"==t?e="rgb":"rgb"==t?e="hsl":"hsl"==t&&(e=1==this.colorpicker.currentA?"hex":"rgb"),this.$el.removeClass(t),this.$el.addClass(e),this.format=e,this.setInputColor(),this.colorpicker.changeInputColorAfterNextFormat()}},{key:"setRGBInput",value:function(t,e,r){this.$rgb_r.val(t),this.$rgb_g.val(e),this.$rgb_b.val(r),this.$rgb_a.val(this.colorpicker.currentA)}},{key:"setHSLInput",value:function(t,e,r){this.$hsl_h.val(t),this.$hsl_s.val(e),this.$hsl_l.val(r),this.$hsl_a.val(this.colorpicker.currentA)}},{key:"getHexFormat",value:function(){return y.format({r:this.$rgb_r.int(),g:this.$rgb_g.int(),b:this.$rgb_b.int()},"hex",this.colorpicker.opt.color)}},{key:"getRgbFormat",value:function(){return y.format({r:this.$rgb_r.int(),g:this.$rgb_g.int(),b:this.$rgb_b.int(),a:this.$rgb_a.float()},"rgb",this.colorpicker.opt.color)}},{key:"getHslFormat",value:function(){return y.format({h:this.$hsl_h.val(),s:this.$hsl_s.val(),l:this.$hsl_l.val(),a:this.$hsl_a.float()},"hsl",this.colorpicker.opt.color)}},{key:"convertRGB",value:function(){return this.colorpicker.convertRGB()}},{key:"convertHEX",value:function(){return this.colorpicker.convertHEX()}},{key:"convertHSL",value:function(){return this.colorpicker.convertHSL()}},{key:"getFormattedColor",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]&&arguments[1];return"hex"==(t=t||this.getFormat())?this.$hexCode.val():"rgb"==t?this.getRgbFormat(e):"hsl"==t?this.getHslFormat(e):void 0}},{key:"getFormat",value:function(){return this.format||"hex"}},{key:"setInputColor",value:function(){var t=this.getFormat(),e=null;if("hex"==t){this.$hexCode.val(this.convertHEX());e=this.convertRGB();this.setRGBInput(e.r,e.g,e.b,e.a)}else if("rgb"==t){e=this.convertRGB();this.setRGBInput(e.r,e.g,e.b,e.a),this.$hexCode.val(this.convertHEX())}else if("hsl"==t){var r=this.convertHSL();this.setHSLInput(r.h,r.s,r.l,r.a)}}},{key:"checkNumberKey",value:function(t){return S.checkNumberKey(t)}},{key:"checkNotNumberKey",value:function(t){return!S.checkNumberKey(t)}},{key:"changeRgbColor",value:function(){this.colorpicker.changeInformationColor(this.getRgbFormat())}},{key:"changeHslColor",value:function(){this.colorpicker.changeInformationColor(this.getHslFormat())}},{key:"change $rgb_r",value:function(t){this.changeRgbColor()}},{key:"change $rgb_g",value:function(t){this.changeRgbColor()}},{key:"change $rgb_b",value:function(t){this.changeRgbColor()}},{key:"change $rgb_a",value:function(t){this.changeRgbColor()}},{key:"change $hsl_h",value:function(t){this.changeHslColor()}},{key:"change $hsl_s",value:function(t){this.changeHslColor()}},{key:"change $hsl_l",value:function(t){this.changeHslColor()}},{key:"change $hsl_a",value:function(t){this.changeHslColor()}},{key:"keydown $hexCode",value:function(t){if(t.which<65||t.which>70)return this.checkNumberKey(t)}},{key:"keyup $hexCode",value:function(t){var e=this.$hexCode.val();"#"==e.charAt(0)&&7==e.length&&(this.colorpicker.changeInformationColor(e),this.setInputColor())}},{key:"click $formatChangeButton",value:function(t){this.nextFormat()}},{key:"refresh",value:function(){}}]),e}(),L=function(t){function e(t){f(this,e);var r=p(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return r.colorpicker=t,r.initialize(),r}return g(e,B),d(e,[{key:"initialize",value:function(){this.$el=new w("div","color"),this.$saturation=this.$el.createChild("div","saturation"),this.$value=this.$saturation.createChild("div","value"),this.$drag_pointer=this.$value.createChild("div","drag-pointer")}},{key:"setBackgroundColor",value:function(t){this.$el.css("background-color",t)}},{key:"refresh",value:function(){this.setColorUI()}},{key:"caculateSV",value:function(){var t=this.drag_pointer_pos||{x:0,y:0},e=this.state.get("$el.width"),r=this.state.get("$el.height");return{s:t.x/e,v:(r-t.y)/r,width:e,height:r}}},{key:"setColorUI",value:function(){var t=this.state.get("$el.width")*this.colorpicker.currentS,e=this.state.get("$el.height")*(1-this.colorpicker.currentV);this.$drag_pointer.css({left:t-5+"px",top:e-5+"px"}),this.drag_pointer_pos={x:t,y:e}}},{key:"setMainColor",value:function(t){t.preventDefault();var e=this.$el.position(),r=this.state.get("$el.contentWidth"),i=this.state.get("$el.contentHeight"),o=t.clientX-e.left,n=t.clientY-e.top;o<0?o=0:o>r&&(o=r),n<0?n=0:n>i&&(n=i),this.$drag_pointer.css({left:o-5+"px",top:n-5+"px"}),this.drag_pointer_pos={x:o,y:n},this.colorpicker.caculateHSV(),this.colorpicker.setInputColor()}},{key:"EventDocumentMouseUp",value:function(t){this.isDown=!1}},{key:"EventDocumentMouseMove",value:function(t){this.isDown&&this.setMainColor(t)}},{key:"mousedown",value:function(t){this.isDown=!0,this.setMainColor(t)}},{key:"mouseup",value:function(t){this.isDown=!1}}]),e}(),O="data-colorsets-index",F=function(t){function e(t){f(this,e);var r=p(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return r.colorpicker=t,r.initialize(),r}return g(e,B),d(e,[{key:"initialize",value:function(){this.$el=new w("div","color-chooser");var t=this.$el.createChild("div","color-chooser-container"),e=t.createChild("div","colorsets-item colorsets-item-header");e.createChild("h1","title").html("Color Paletts"),this.$toggleButton=e.createChild("span","items").html("×"),this.$colorsetsList=t.createChild("div","colorsets-list"),this.refresh()}},{key:"refresh",value:function(){this.$colorsetsList.html(this.makeColorSetsList())}},{key:"makeColorItemList",value:function(t){for(var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:5,r=new w("div"),i=0;i1&&void 0!==arguments[1]&&arguments[1];if("object"==(void 0===t?"undefined":u(t))){if(!t.r||!t.g||!t.b)return;e?this.callbackColorValue(y.format(t,"hex")):this.initColor(y.format(t,"hex"))}else"string"==typeof t&&(e?this.callbackColorValue(t):this.initColor(t))}},{key:"getColor",value:function(t){this.caculateHSV();var e=this.convertRGB();return t?y.format(e,t):e}},{key:"definePositionForArrow",value:function(t,e,r){}},{key:"definePosition",value:function(t){var e=this.$root.width(),r=this.$root.height(),i=t.left-this.$body.el.scrollLeft;e+i>window.innerWidth&&(i-=e+i-window.innerWidth),i<0&&(i=0);var o=t.top-this.$body.el.scrollTop;r+o>window.innerHeight&&(o-=r+o-window.innerHeight),o<0&&(o=0),this.$root.css({left:i+"px",top:o+"px"})}},{key:"getInitalizePosition",value:function(){return"inline"==this.opt.position?{position:"relative",left:"auto",top:"auto",display:"inline-block"}:{position:"fixed",left:"-10000px",top:"-10000px"}}},{key:"show",value:function(t,e,r){this.destroy(),this.initializeEvent(),this.$root.appendTo(this.$body),this.$root.css(this.getInitalizePosition()).show(),this.definePosition(t),this.isColorPickerShow=!0,this.isShortCut=t.isShortCut||!1,this.initColor(e),this.colorpickerCallback=r,this.hideDelay=t.hideDelay||2e3,this.hideDelay>0&&this.setHideDelay(this.hideDelay)}},{key:"setHideDelay",value:function(t){var e=this;t=t||0,this.$root.off("mouseenter"),this.$root.off("mouseleave"),this.$root.on("mouseenter",function(){clearTimeout(e.timerCloseColorPicker)}),this.$root.on("mouseleave",function(){clearTimeout(e.timerCloseColorPicker),e.timerCloseColorPicker=setTimeout(e.hide.bind(e),t)}),clearTimeout(this.timerCloseColorPicker),this.timerCloseColorPicker=setTimeout(this.hide.bind(this),t)}},{key:"hide",value:function(){this.isColorPickerShow&&(this.destroy(),this.$root.hide(),this.$root.remove(),this.isColorPickerShow=!1)}},{key:"convertRGB",value:function(){return y.HSVtoRGB(this.currentH,this.currentS,this.currentV)}},{key:"convertHEX",value:function(){return y.format(this.convertRGB(),"hex")}},{key:"convertHSL",value:function(){return y.HSVtoHSL(this.currentH,this.currentS,this.currentV)}},{key:"getCurrentColor",value:function(){return this.information.getFormattedColor()}},{key:"getFormattedColor",value:function(t){if("rgb"==(t=t||"hex"))return(r=this.convertRGB()).a=this.currentA,y.format(r,"rgb");if("hsl"==t){var e=this.convertHSL();return e.a=this.currentA,y.format(e,"hsl")}var r=this.convertRGB();return y.format(r,"hex")}},{key:"setInputColor",value:function(t){this.information.setInputColor(t),this.control.setInputColor(t),this.callbackColorValue()}},{key:"changeInputColorAfterNextFormat",value:function(){this.control.setInputColor(),this.callbackColorValue()}},{key:"callbackColorValue",value:function(t){t=t||this.getCurrentColor(),"function"==typeof this.opt.onChange&&(isNaN(this.currentA)||this.opt.onChange.call(this,t)),"function"==typeof this.colorpickerCallback&&(isNaN(this.currentA)||this.colorpickerCallback(t))}},{key:"caculateHSV",value:function(){var t=this.palette.caculateSV(),e=this.control.caculateH(),r=t.s,i=t.v,o=e.h;0==t.width&&(o=0,r=0,i=0),this.currentH=o,this.currentS=r,this.currentV=i}},{key:"setColorUI",value:function(){this.control.setColorUI(),this.palette.setColorUI()}},{key:"setCurrentHSV",value:function(t,e,r,i){this.currentA=i,this.currentH=t,this.currentS=e,this.currentV=r}},{key:"setCurrentH",value:function(t){this.currentH=t}},{key:"setCurrentA",value:function(t){this.currentA=t}},{key:"setBackgroundColor",value:function(t){this.palette.setBackgroundColor(t)}},{key:"setCurrentFormat",value:function(t){this.format=t,this.information.setCurrentFormat(t)}},{key:"getHSV",value:function(t){return"hsl"==t.type?y.HSLtoHSV(t.h,t.s,t.l):y.RGBtoHSV(t)}},{key:"initColor",value:function(t,e){var r=t||"#FF0000",i=y.parse(r);e=e||i.type,this.setCurrentFormat(e);var o=this.getHSV(i);this.setCurrentHSV(o.h,o.s,o.v,i.a),this.setColorUI(),this.setHueColor(),this.setInputColor()}},{key:"changeInformationColor",value:function(t){var e=t||"#FF0000",r=y.parse(e),i=this.getHSV(r);this.setCurrentHSV(i.h,i.s,i.v,r.a),this.setColorUI(),this.setHueColor(),this.control.setInputColor(),this.callbackColorValue()}},{key:"setHueColor",value:function(){this.control.setOnlyHueColor()}},{key:"checkColorPickerClass",value:function(t){var e=new w(t).closest("codemirror-colorview"),r=new w(t).closest("codemirror-colorpicker"),i=new w(t).closest("CodeMirror");t.nodeName;return!!(r||e||i)}},{key:"checkInHtml",value:function(t){return"HTML"==t.nodeName}},{key:"mouseup document",value:function(t){this.palette.EventDocumentMouseUp(t),this.control.EventDocumentMouseUp(t),this.checkInHtml(t.target)||0==this.checkColorPickerClass(t.target)&&this.hide()}},{key:"mousemove document",value:function(t){this.palette.EventDocumentMouseMove(t),this.control.EventDocumentMouseMove(t)}},{key:"initializeEvent",value:function(){this.initializeEventMachin(),this.palette.initializeEvent(),this.control.initializeEvent(),this.information.initializeEvent(),this.currentColorSets.initializeEvent(),this.colorSetsChooser.initializeEvent(),this.contextMenu.initializeEvent()}},{key:"currentFormat",value:function(){this.information.currentFormat()}},{key:"toggleColorChooser",value:function(){this.colorSetsChooser.toggle()}},{key:"refreshColorSetsChooser",value:function(){this.colorSetsChooser.refresh()}},{key:"getColorSetsList",value:function(){return this.colorSetsList.getColorSetsList()}},{key:"setCurrentColorSets",value:function(t){this.colorSetsList.setCurrentColorSets(t),this.currentColorSets.refresh()}},{key:"setColorSets",value:function(t){this.colorSetsList.setUserList(t)}},{key:"destroy",value:function(){v(e.prototype.__proto__||Object.getPrototypeOf(e.prototype),"destroy",this).call(this),this.control.destroy(),this.palette.destroy(),this.information.destroy(),this.colorSetsChooser.destroy(),this.colorSetsList.destroy(),this.currentColorSets.destroy(),this.contextMenu.destroy(),this.colorpickerCallback=void 0}}]),e}(),D="codemirror-colorview",V="codemirror-colorview-background",T=["comment"];function j(t,e){"setValue"==e.origin?(t.state.colorpicker.close_color_picker(),t.state.colorpicker.init_color_update(),t.state.colorpicker.style_color_update()):t.state.colorpicker.style_color_update(t.getCursor().line)}function U(t,e){t.state.colorpicker.isUpdate||(t.state.colorpicker.isUpdate=!0,t.state.colorpicker.close_color_picker(),t.state.colorpicker.init_color_update(),t.state.colorpicker.style_color_update())}function z(t,e){j(t,{origin:"setValue"})}function q(t,e){t.state.colorpicker.keyup(e)}function K(t,e){t.state.colorpicker.is_edit_mode()&&t.state.colorpicker.check_mousedown(e)}function W(t,e){j(t,{origin:"setValue"})}function X(t){t.state.colorpicker.close_color_picker()}var Y=function(){function t(e,r){f(this,t),r="boolean"==typeof r?{mode:"edit"}:Object.assign({mode:"edit"},r||{}),this.opt=r,this.cm=e,this.markers={},this.excluded_token=this.opt.excluded_token||T,this.opt.colorpicker?this.colorpicker=this.opt.colorpicker(this.opt):this.colorpicker=new G(this.opt),this.init_event()}return d(t,[{key:"init_event",value:function(){var t,e,r,i,o;this.cm.on("mousedown",K),this.cm.on("keyup",q),this.cm.on("change",j),this.cm.on("update",U),this.cm.on("refresh",z),this.onPasteCallback=(t=this.cm,e=W,function(r){e.call(this,t,r)}),this.cm.getWrapperElement().addEventListener("paste",this.onPasteCallback),this.is_edit_mode()&&this.cm.on("scroll",(r=X,i=50,o=void 0,function(t,e){o&&clearTimeout(o),o=setTimeout(function(){r(t,e)},i||300)}))}},{key:"is_edit_mode",value:function(){return"edit"==this.opt.mode}},{key:"is_view_mode",value:function(){return"view"==this.opt.mode}},{key:"destroy",value:function(){this.cm.off("mousedown",K),this.cm.off("keyup",q),this.cm.off("change",j),this.cm.getWrapperElement().removeEventListener("paste",this.onPasteCallback),this.is_edit_mode()&&this.cm.off("scroll")}},{key:"hasClass",value:function(t,e){return!!t.className&&(" "+t.className+" ").indexOf(" "+e+" ")>-1}},{key:"check_mousedown",value:function(t){this.hasClass(t.target,V)?this.open_color_picker(t.target.parentNode):this.close_color_picker()}},{key:"popup_color_picker",value:function(t){var e=this.cm.getCursor(),r=this,i={lineNo:e.line,ch:e.ch,color:t||"#FFFFFF",isShortCut:!0};Object.keys(this.markers).forEach(function(t){if(("#"+t).indexOf("#"+i.lineNo+":")>-1){var e=r.markers[t];e.ch<=i.ch&&i.ch<=e.ch+e.color.length&&(i.ch=e.ch,i.color=e.color,i.nameColor=e.nameColor)}}),this.open_color_picker(i)}},{key:"open_color_picker",value:function(t){var e=t.lineNo,r=t.ch,i=t.nameColor,o=t.color;if(this.colorpicker){var n=this,s=o,a=this.cm.charCoords({line:e,ch:r});this.colorpicker.show({left:a.left,top:a.bottom,isShortCut:t.isShortCut||!1,hideDelay:n.opt.hideDelay||2e3},i||o,function(t){n.cm.replaceRange(t,{line:e,ch:r},{line:e,ch:r+s.length},"*colorpicker"),s=t})}}},{key:"close_color_picker",value:function(t){this.colorpicker&&this.colorpicker.hide()}},{key:"key",value:function(t,e){return[t,e].join(":")}},{key:"keyup",value:function(t){this.colorpicker&&("Escape"==t.key?this.colorpicker.hide():0==this.colorpicker.isShortCut&&this.colorpicker.hide())}},{key:"init_color_update",value:function(){this.markers={}}},{key:"style_color_update",value:function(t){if(t)this.match(t);else for(var e=this.cm.lineCount(),r=0;r-1)&&(delete this.markers[a],o[n].marker.clear())}}},{key:"match_result",value:function(t){return y.matches(t.text,!0)}},{key:"submatch",value:function(t,e){var r=this;this.empty_marker(t,e);var i={next:0};this.match_result(e).forEach(function(o){r.render(i,t,e,o.color,o.nameColor)})}},{key:"match",value:function(t){var e=this.cm.getLineHandle(t),r=this;this.cm.operation(function(){r.submatch(t,e)})}},{key:"make_element",value:function(){var t=document.createElement("div");return t.className=D,this.is_edit_mode()?t.title="open color picker":t.title="",t.back_element=this.make_background_element(),t.appendChild(t.back_element),t}},{key:"make_background_element",value:function(){var t=document.createElement("div");return t.className=V,t}},{key:"set_state",value:function(t,e,r,i){var o=this.create_marker(t,e);return o.lineNo=t,o.ch=e,o.color=r,o.nameColor=i,o}},{key:"create_marker",value:function(t,e){var r=this.key(t,e);return this.markers[r]||(this.markers[r]=this.make_element()),this.markers[r]}},{key:"has_marker",value:function(t,e){var r=this.key(t,e);return!!this.markers[r]}},{key:"update_element",value:function(t,e){t.back_element.style.backgroundColor=e}},{key:"set_mark",value:function(t,e,r){this.cm.setBookmark({line:t,ch:e},{widget:r,handleMouseEvents:!0})}},{key:"is_excluded_token",value:function(t,e){for(var r=this.cm.getTokenTypeAt({line:t,ch:e}),i=0,o=0,n=this.excluded_token.length;o0}},{key:"render",value:function(t,e,r,i,o){var n=r.text.indexOf(i,t.next);if(!0!==this.is_excluded_token(e,n)){if(t.next=n+i.length,this.has_marker(e,n))return this.update_element(this.create_marker(e,n),o||i),void this.set_state(e,n,i,o);var s=this.create_marker(e,n);this.update_element(s,o||i),this.set_state(e,n,i,o||i),this.set_mark(e,n,s)}}}]),t}();return t&&t.defineOption("colorpicker",!1,function(e,r,i){i&&i!=t.Init&&e.state.colorpicker&&(e.state.colorpicker.destroy(),e.state.colorpicker=null),r&&(e.state.colorpicker=new Y(e,r))}),{Color:y,ColorNames:r,HueColor:C,ColorPicker:G}}(CodeMirror); diff --git a/frontend/public/js/codemirror.js b/frontend/public/js/codemirror.js new file mode 100644 index 00000000..7f57e4b3 --- /dev/null +++ b/frontend/public/js/codemirror.js @@ -0,0 +1,9683 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// This is CodeMirror (http://codemirror.net), a code editor +// implemented in JavaScript on top of the browser's DOM. +// +// You can find some technical background for some of the code below +// at http://marijnhaverbeke.nl/blog/#cm-internals . + +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global.CodeMirror = factory()); +}(this, (function () { 'use strict'; + +// Kludges for bugs and behavior differences that can't be feature +// detected are enabled based on userAgent etc sniffing. +var userAgent = navigator.userAgent +var platform = navigator.platform + +var gecko = /gecko\/\d/i.test(userAgent) +var ie_upto10 = /MSIE \d/.test(userAgent) +var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(userAgent) +var edge = /Edge\/(\d+)/.exec(userAgent) +var ie = ie_upto10 || ie_11up || edge +var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : +(edge || ie_11up)[1]) +var webkit = !edge && /WebKit\//.test(userAgent) +var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(userAgent) +var chrome = !edge && /Chrome\//.test(userAgent) +var presto = /Opera\//.test(userAgent) +var safari = /Apple Computer/.test(navigator.vendor) +var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(userAgent) +var phantom = /PhantomJS/.test(userAgent) + +var ios = !edge && /AppleWebKit/.test(userAgent) && /Mobile\/\w+/.test(userAgent) +var android = /Android/.test(userAgent) +// This is woefully incomplete. Suggestions for alternative methods welcome. +var mobile = ios || android || /webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent) +var mac = ios || /Mac/.test(platform) +var chromeOS = /\bCrOS\b/.test(userAgent) +var windows = /win/i.test(platform) + +var presto_version = presto && userAgent.match(/Version\/(\d*\.\d*)/) +if (presto_version) { presto_version = Number(presto_version[1]) } +if (presto_version && presto_version >= 15) { presto = false; webkit = true } +// Some browsers use the wrong event properties to signal cmd/ctrl on OS X +var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11)) +var captureRightClick = gecko || (ie && ie_version >= 9) + +function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*") } + +var rmClass = function(node, cls) { + var current = node.className + var match = classTest(cls).exec(current) + if (match) { + var after = current.slice(match.index + match[0].length) + node.className = current.slice(0, match.index) + (after ? match[1] + after : "") + } +} + +function removeChildren(e) { + for (var count = e.childNodes.length; count > 0; --count) + { e.removeChild(e.firstChild) } + return e +} + +function removeChildrenAndAdd(parent, e) { + return removeChildren(parent).appendChild(e) +} + +function elt(tag, content, className, style) { + var e = document.createElement(tag) + if (className) { e.className = className } + if (style) { e.style.cssText = style } + if (typeof content == "string") { e.appendChild(document.createTextNode(content)) } + else if (content) { for (var i = 0; i < content.length; ++i) { e.appendChild(content[i]) } } + return e +} +// wrapper for elt, which removes the elt from the accessibility tree +function eltP(tag, content, className, style) { + var e = elt(tag, content, className, style) + e.setAttribute("role", "presentation") + return e +} + +var range +if (document.createRange) { range = function(node, start, end, endNode) { + var r = document.createRange() + r.setEnd(endNode || node, end) + r.setStart(node, start) + return r +} } +else { range = function(node, start, end) { + var r = document.body.createTextRange() + try { r.moveToElementText(node.parentNode) } + catch(e) { return r } + r.collapse(true) + r.moveEnd("character", end) + r.moveStart("character", start) + return r +} } + +function contains(parent, child) { + if (child.nodeType == 3) // Android browser always returns false when child is a textnode + { child = child.parentNode } + if (parent.contains) + { return parent.contains(child) } + do { + if (child.nodeType == 11) { child = child.host } + if (child == parent) { return true } + } while (child = child.parentNode) +} + +function activeElt() { + // IE and Edge may throw an "Unspecified Error" when accessing document.activeElement. + // IE < 10 will throw when accessed while the page is loading or in an iframe. + // IE > 9 and Edge will throw when accessed in an iframe if document.body is unavailable. + var activeElement + try { + activeElement = document.activeElement + } catch(e) { + activeElement = document.body || null + } + while (activeElement && activeElement.shadowRoot && activeElement.shadowRoot.activeElement) + { activeElement = activeElement.shadowRoot.activeElement } + return activeElement +} + +function addClass(node, cls) { + var current = node.className + if (!classTest(cls).test(current)) { node.className += (current ? " " : "") + cls } +} +function joinClasses(a, b) { + var as = a.split(" ") + for (var i = 0; i < as.length; i++) + { if (as[i] && !classTest(as[i]).test(b)) { b += " " + as[i] } } + return b +} + +var selectInput = function(node) { node.select() } +if (ios) // Mobile Safari apparently has a bug where select() is broken. + { selectInput = function(node) { node.selectionStart = 0; node.selectionEnd = node.value.length } } +else if (ie) // Suppress mysterious IE10 errors + { selectInput = function(node) { try { node.select() } catch(_e) {} } } + +function bind(f) { + var args = Array.prototype.slice.call(arguments, 1) + return function(){return f.apply(null, args)} +} + +function copyObj(obj, target, overwrite) { + if (!target) { target = {} } + for (var prop in obj) + { if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop))) + { target[prop] = obj[prop] } } + return target +} + +// Counts the column offset in a string, taking tabs into account. +// Used mostly to find indentation. +function countColumn(string, end, tabSize, startIndex, startValue) { + if (end == null) { + end = string.search(/[^\s\u00a0]/) + if (end == -1) { end = string.length } + } + for (var i = startIndex || 0, n = startValue || 0;;) { + var nextTab = string.indexOf("\t", i) + if (nextTab < 0 || nextTab >= end) + { return n + (end - i) } + n += nextTab - i + n += tabSize - (n % tabSize) + i = nextTab + 1 + } +} + +var Delayed = function() {this.id = null}; +Delayed.prototype.set = function (ms, f) { + clearTimeout(this.id) + this.id = setTimeout(f, ms) +}; + +function indexOf(array, elt) { + for (var i = 0; i < array.length; ++i) + { if (array[i] == elt) { return i } } + return -1 +} + +// Number of pixels added to scroller and sizer to hide scrollbar +var scrollerGap = 30 + +// Returned or thrown by various protocols to signal 'I'm not +// handling this'. +var Pass = {toString: function(){return "CodeMirror.Pass"}} + +// Reused option objects for setSelection & friends +var sel_dontScroll = {scroll: false}; +var sel_mouse = {origin: "*mouse"}; +var sel_move = {origin: "+move"}; +// The inverse of countColumn -- find the offset that corresponds to +// a particular column. +function findColumn(string, goal, tabSize) { + for (var pos = 0, col = 0;;) { + var nextTab = string.indexOf("\t", pos) + if (nextTab == -1) { nextTab = string.length } + var skipped = nextTab - pos + if (nextTab == string.length || col + skipped >= goal) + { return pos + Math.min(skipped, goal - col) } + col += nextTab - pos + col += tabSize - (col % tabSize) + pos = nextTab + 1 + if (col >= goal) { return pos } + } +} + +var spaceStrs = [""] +function spaceStr(n) { + while (spaceStrs.length <= n) + { spaceStrs.push(lst(spaceStrs) + " ") } + return spaceStrs[n] +} + +function lst(arr) { return arr[arr.length-1] } + +function map(array, f) { + var out = [] + for (var i = 0; i < array.length; i++) { out[i] = f(array[i], i) } + return out +} + +function insertSorted(array, value, score) { + var pos = 0, priority = score(value) + while (pos < array.length && score(array[pos]) <= priority) { pos++ } + array.splice(pos, 0, value) +} + +function nothing() {} + +function createObj(base, props) { + var inst + if (Object.create) { + inst = Object.create(base) + } else { + nothing.prototype = base + inst = new nothing() + } + if (props) { copyObj(props, inst) } + return inst +} + +var nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/ +function isWordCharBasic(ch) { + return /\w/.test(ch) || ch > "\x80" && + (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch)) +} +function isWordChar(ch, helper) { + if (!helper) { return isWordCharBasic(ch) } + if (helper.source.indexOf("\\w") > -1 && isWordCharBasic(ch)) { return true } + return helper.test(ch) +} + +function isEmpty(obj) { + for (var n in obj) { if (obj.hasOwnProperty(n) && obj[n]) { return false } } + return true +} + +// Extending unicode characters. A series of a non-extending char + +// any number of extending chars is treated as a single unit as far +// as editing and measuring is concerned. This is not fully correct, +// since some scripts/fonts/browsers also treat other configurations +// of code points as a group. +var extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/ +function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch) } + +// Returns a number from the range [`0`; `str.length`] unless `pos` is outside that range. +function skipExtendingChars(str, pos, dir) { + while ((dir < 0 ? pos > 0 : pos < str.length) && isExtendingChar(str.charAt(pos))) { pos += dir } + return pos +} + +// Returns the value from the range [`from`; `to`] that satisfies +// `pred` and is closest to `from`. Assumes that at least `to` +// satisfies `pred`. Supports `from` being greater than `to`. +function findFirst(pred, from, to) { + // At any point we are certain `to` satisfies `pred`, don't know + // whether `from` does. + var dir = from > to ? -1 : 1 + for (;;) { + if (from == to) { return from } + var midF = (from + to) / 2, mid = dir < 0 ? Math.ceil(midF) : Math.floor(midF) + if (mid == from) { return pred(mid) ? from : to } + if (pred(mid)) { to = mid } + else { from = mid + dir } + } +} + +// The display handles the DOM integration, both for input reading +// and content drawing. It holds references to DOM nodes and +// display-related state. + +function Display(place, doc, input) { + var d = this + this.input = input + + // Covers bottom-right square when both scrollbars are present. + d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler") + d.scrollbarFiller.setAttribute("cm-not-content", "true") + // Covers bottom of gutter when coverGutterNextToScrollbar is on + // and h scrollbar is present. + d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler") + d.gutterFiller.setAttribute("cm-not-content", "true") + // Will contain the actual code, positioned to cover the viewport. + d.lineDiv = eltP("div", null, "CodeMirror-code") + // Elements are added to these to represent selection and cursors. + d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1") + d.cursorDiv = elt("div", null, "CodeMirror-cursors") + // A visibility: hidden element used to find the size of things. + d.measure = elt("div", null, "CodeMirror-measure") + // When lines outside of the viewport are measured, they are drawn in this. + d.lineMeasure = elt("div", null, "CodeMirror-measure") + // Wraps everything that needs to exist inside the vertically-padded coordinate system + d.lineSpace = eltP("div", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv], + null, "position: relative; outline: none") + var lines = eltP("div", [d.lineSpace], "CodeMirror-lines") + // Moved around its parent to cover visible view. + d.mover = elt("div", [lines], null, "position: relative") + // Set to the height of the document, allowing scrolling. + d.sizer = elt("div", [d.mover], "CodeMirror-sizer") + d.sizerWidth = null + // Behavior of elts with overflow: auto and padding is + // inconsistent across browsers. This is used to ensure the + // scrollable area is big enough. + d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerGap + "px; width: 1px;") + // Will contain the gutters, if any. + d.gutters = elt("div", null, "CodeMirror-gutters") + d.lineGutter = null + // Actual scrollable element. + d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll") + d.scroller.setAttribute("tabIndex", "-1") + // The element in which the editor lives. + d.wrapper = elt("div", [d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror") + + // Work around IE7 z-index bug (not perfect, hence IE7 not really being supported) + if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0 } + if (!webkit && !(gecko && mobile)) { d.scroller.draggable = true } + + if (place) { + if (place.appendChild) { place.appendChild(d.wrapper) } + else { place(d.wrapper) } + } + + // Current rendered range (may be bigger than the view window). + d.viewFrom = d.viewTo = doc.first + d.reportedViewFrom = d.reportedViewTo = doc.first + // Information about the rendered lines. + d.view = [] + d.renderedView = null + // Holds info about a single rendered line when it was rendered + // for measurement, while not in view. + d.externalMeasured = null + // Empty space (in pixels) above the view + d.viewOffset = 0 + d.lastWrapHeight = d.lastWrapWidth = 0 + d.updateLineNumbers = null + + d.nativeBarWidth = d.barHeight = d.barWidth = 0 + d.scrollbarsClipped = false + + // Used to only resize the line number gutter when necessary (when + // the amount of lines crosses a boundary that makes its width change) + d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null + // Set to true when a non-horizontal-scrolling line widget is + // added. As an optimization, line widget aligning is skipped when + // this is false. + d.alignWidgets = false + + d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null + + // Tracks the maximum line length so that the horizontal scrollbar + // can be kept static when scrolling. + d.maxLine = null + d.maxLineLength = 0 + d.maxLineChanged = false + + // Used for measuring wheel scrolling granularity + d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null + + // True when shift is held down. + d.shift = false + + // Used to track whether anything happened since the context menu + // was opened. + d.selForContextMenu = null + + d.activeTouch = null + + input.init(d) +} + +// Find the line object corresponding to the given line number. +function getLine(doc, n) { + n -= doc.first + if (n < 0 || n >= doc.size) { throw new Error("There is no line " + (n + doc.first) + " in the document.") } + var chunk = doc + while (!chunk.lines) { + for (var i = 0;; ++i) { + var child = chunk.children[i], sz = child.chunkSize() + if (n < sz) { chunk = child; break } + n -= sz + } + } + return chunk.lines[n] +} + +// Get the part of a document between two positions, as an array of +// strings. +function getBetween(doc, start, end) { + var out = [], n = start.line + doc.iter(start.line, end.line + 1, function (line) { + var text = line.text + if (n == end.line) { text = text.slice(0, end.ch) } + if (n == start.line) { text = text.slice(start.ch) } + out.push(text) + ++n + }) + return out +} +// Get the lines between from and to, as array of strings. +function getLines(doc, from, to) { + var out = [] + doc.iter(from, to, function (line) { out.push(line.text) }) // iter aborts when callback returns truthy value + return out +} + +// Update the height of a line, propagating the height change +// upwards to parent nodes. +function updateLineHeight(line, height) { + var diff = height - line.height + if (diff) { for (var n = line; n; n = n.parent) { n.height += diff } } +} + +// Given a line object, find its line number by walking up through +// its parent links. +function lineNo(line) { + if (line.parent == null) { return null } + var cur = line.parent, no = indexOf(cur.lines, line) + for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) { + for (var i = 0;; ++i) { + if (chunk.children[i] == cur) { break } + no += chunk.children[i].chunkSize() + } + } + return no + cur.first +} + +// Find the line at the given vertical position, using the height +// information in the document tree. +function lineAtHeight(chunk, h) { + var n = chunk.first + outer: do { + for (var i$1 = 0; i$1 < chunk.children.length; ++i$1) { + var child = chunk.children[i$1], ch = child.height + if (h < ch) { chunk = child; continue outer } + h -= ch + n += child.chunkSize() + } + return n + } while (!chunk.lines) + var i = 0 + for (; i < chunk.lines.length; ++i) { + var line = chunk.lines[i], lh = line.height + if (h < lh) { break } + h -= lh + } + return n + i +} + +function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size} + +function lineNumberFor(options, i) { + return String(options.lineNumberFormatter(i + options.firstLineNumber)) +} + +// A Pos instance represents a position within the text. +function Pos(line, ch, sticky) { + if ( sticky === void 0 ) sticky = null; + + if (!(this instanceof Pos)) { return new Pos(line, ch, sticky) } + this.line = line + this.ch = ch + this.sticky = sticky +} + +// Compare two positions, return 0 if they are the same, a negative +// number when a is less, and a positive number otherwise. +function cmp(a, b) { return a.line - b.line || a.ch - b.ch } + +function equalCursorPos(a, b) { return a.sticky == b.sticky && cmp(a, b) == 0 } + +function copyPos(x) {return Pos(x.line, x.ch)} +function maxPos(a, b) { return cmp(a, b) < 0 ? b : a } +function minPos(a, b) { return cmp(a, b) < 0 ? a : b } + +// Most of the external API clips given positions to make sure they +// actually exist within the document. +function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1))} +function clipPos(doc, pos) { + if (pos.line < doc.first) { return Pos(doc.first, 0) } + var last = doc.first + doc.size - 1 + if (pos.line > last) { return Pos(last, getLine(doc, last).text.length) } + return clipToLen(pos, getLine(doc, pos.line).text.length) +} +function clipToLen(pos, linelen) { + var ch = pos.ch + if (ch == null || ch > linelen) { return Pos(pos.line, linelen) } + else if (ch < 0) { return Pos(pos.line, 0) } + else { return pos } +} +function clipPosArray(doc, array) { + var out = [] + for (var i = 0; i < array.length; i++) { out[i] = clipPos(doc, array[i]) } + return out +} + +// Optimize some code when these features are not used. +var sawReadOnlySpans = false; +var sawCollapsedSpans = false; +function seeReadOnlySpans() { + sawReadOnlySpans = true +} + +function seeCollapsedSpans() { + sawCollapsedSpans = true +} + +// TEXTMARKER SPANS + +function MarkedSpan(marker, from, to) { + this.marker = marker + this.from = from; this.to = to +} + +// Search an array of spans for a span matching the given marker. +function getMarkedSpanFor(spans, marker) { + if (spans) { for (var i = 0; i < spans.length; ++i) { + var span = spans[i] + if (span.marker == marker) { return span } + } } +} +// Remove a span from an array, returning undefined if no spans are +// left (we don't store arrays for lines without spans). +function removeMarkedSpan(spans, span) { + var r + for (var i = 0; i < spans.length; ++i) + { if (spans[i] != span) { (r || (r = [])).push(spans[i]) } } + return r +} +// Add a span to a line. +function addMarkedSpan(line, span) { + line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span] + span.marker.attachLine(line) +} + +// Used for the algorithm that adjusts markers for a change in the +// document. These functions cut an array of spans at a given +// character position, returning an array of remaining chunks (or +// undefined if nothing remains). +function markedSpansBefore(old, startCh, isInsert) { + var nw + if (old) { for (var i = 0; i < old.length; ++i) { + var span = old[i], marker = span.marker + var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh) + if (startsBefore || span.from == startCh && marker.type == "bookmark" && (!isInsert || !span.marker.insertLeft)) { + var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh) + ;(nw || (nw = [])).push(new MarkedSpan(marker, span.from, endsAfter ? null : span.to)) + } + } } + return nw +} +function markedSpansAfter(old, endCh, isInsert) { + var nw + if (old) { for (var i = 0; i < old.length; ++i) { + var span = old[i], marker = span.marker + var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh) + if (endsAfter || span.from == endCh && marker.type == "bookmark" && (!isInsert || span.marker.insertLeft)) { + var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh) + ;(nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh, + span.to == null ? null : span.to - endCh)) + } + } } + return nw +} + +// Given a change object, compute the new set of marker spans that +// cover the line in which the change took place. Removes spans +// entirely within the change, reconnects spans belonging to the +// same marker that appear on both sides of the change, and cuts off +// spans partially within the change. Returns an array of span +// arrays with one element for each line in (after) the change. +function stretchSpansOverChange(doc, change) { + if (change.full) { return null } + var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans + var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans + if (!oldFirst && !oldLast) { return null } + + var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0 + // Get the spans that 'stick out' on both sides + var first = markedSpansBefore(oldFirst, startCh, isInsert) + var last = markedSpansAfter(oldLast, endCh, isInsert) + + // Next, merge those two ends + var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0) + if (first) { + // Fix up .to properties of first + for (var i = 0; i < first.length; ++i) { + var span = first[i] + if (span.to == null) { + var found = getMarkedSpanFor(last, span.marker) + if (!found) { span.to = startCh } + else if (sameLine) { span.to = found.to == null ? null : found.to + offset } + } + } + } + if (last) { + // Fix up .from in last (or move them into first in case of sameLine) + for (var i$1 = 0; i$1 < last.length; ++i$1) { + var span$1 = last[i$1] + if (span$1.to != null) { span$1.to += offset } + if (span$1.from == null) { + var found$1 = getMarkedSpanFor(first, span$1.marker) + if (!found$1) { + span$1.from = offset + if (sameLine) { (first || (first = [])).push(span$1) } + } + } else { + span$1.from += offset + if (sameLine) { (first || (first = [])).push(span$1) } + } + } + } + // Make sure we didn't create any zero-length spans + if (first) { first = clearEmptySpans(first) } + if (last && last != first) { last = clearEmptySpans(last) } + + var newMarkers = [first] + if (!sameLine) { + // Fill gap with whole-line-spans + var gap = change.text.length - 2, gapMarkers + if (gap > 0 && first) + { for (var i$2 = 0; i$2 < first.length; ++i$2) + { if (first[i$2].to == null) + { (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i$2].marker, null, null)) } } } + for (var i$3 = 0; i$3 < gap; ++i$3) + { newMarkers.push(gapMarkers) } + newMarkers.push(last) + } + return newMarkers +} + +// Remove spans that are empty and don't have a clearWhenEmpty +// option of false. +function clearEmptySpans(spans) { + for (var i = 0; i < spans.length; ++i) { + var span = spans[i] + if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false) + { spans.splice(i--, 1) } + } + if (!spans.length) { return null } + return spans +} + +// Used to 'clip' out readOnly ranges when making a change. +function removeReadOnlyRanges(doc, from, to) { + var markers = null + doc.iter(from.line, to.line + 1, function (line) { + if (line.markedSpans) { for (var i = 0; i < line.markedSpans.length; ++i) { + var mark = line.markedSpans[i].marker + if (mark.readOnly && (!markers || indexOf(markers, mark) == -1)) + { (markers || (markers = [])).push(mark) } + } } + }) + if (!markers) { return null } + var parts = [{from: from, to: to}] + for (var i = 0; i < markers.length; ++i) { + var mk = markers[i], m = mk.find(0) + for (var j = 0; j < parts.length; ++j) { + var p = parts[j] + if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) { continue } + var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to) + if (dfrom < 0 || !mk.inclusiveLeft && !dfrom) + { newParts.push({from: p.from, to: m.from}) } + if (dto > 0 || !mk.inclusiveRight && !dto) + { newParts.push({from: m.to, to: p.to}) } + parts.splice.apply(parts, newParts) + j += newParts.length - 3 + } + } + return parts +} + +// Connect or disconnect spans from a line. +function detachMarkedSpans(line) { + var spans = line.markedSpans + if (!spans) { return } + for (var i = 0; i < spans.length; ++i) + { spans[i].marker.detachLine(line) } + line.markedSpans = null +} +function attachMarkedSpans(line, spans) { + if (!spans) { return } + for (var i = 0; i < spans.length; ++i) + { spans[i].marker.attachLine(line) } + line.markedSpans = spans +} + +// Helpers used when computing which overlapping collapsed span +// counts as the larger one. +function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0 } +function extraRight(marker) { return marker.inclusiveRight ? 1 : 0 } + +// Returns a number indicating which of two overlapping collapsed +// spans is larger (and thus includes the other). Falls back to +// comparing ids when the spans cover exactly the same range. +function compareCollapsedMarkers(a, b) { + var lenDiff = a.lines.length - b.lines.length + if (lenDiff != 0) { return lenDiff } + var aPos = a.find(), bPos = b.find() + var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b) + if (fromCmp) { return -fromCmp } + var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b) + if (toCmp) { return toCmp } + return b.id - a.id +} + +// Find out whether a line ends or starts in a collapsed span. If +// so, return the marker for that span. +function collapsedSpanAtSide(line, start) { + var sps = sawCollapsedSpans && line.markedSpans, found + if (sps) { for (var sp = (void 0), i = 0; i < sps.length; ++i) { + sp = sps[i] + if (sp.marker.collapsed && (start ? sp.from : sp.to) == null && + (!found || compareCollapsedMarkers(found, sp.marker) < 0)) + { found = sp.marker } + } } + return found +} +function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true) } +function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false) } + +function collapsedSpanAround(line, ch) { + var sps = sawCollapsedSpans && line.markedSpans, found + if (sps) { for (var i = 0; i < sps.length; ++i) { + var sp = sps[i] + if (sp.marker.collapsed && (sp.from == null || sp.from < ch) && (sp.to == null || sp.to > ch) && + (!found || compareCollapsedMarkers(found, sp.marker) < 0)) { found = sp.marker } + } } + return found +} + +// Test whether there exists a collapsed span that partially +// overlaps (covers the start or end, but not both) of a new span. +// Such overlap is not allowed. +function conflictingCollapsedRange(doc, lineNo, from, to, marker) { + var line = getLine(doc, lineNo) + var sps = sawCollapsedSpans && line.markedSpans + if (sps) { for (var i = 0; i < sps.length; ++i) { + var sp = sps[i] + if (!sp.marker.collapsed) { continue } + var found = sp.marker.find(0) + var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker) + var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker) + if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) { continue } + if (fromCmp <= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.to, from) >= 0 : cmp(found.to, from) > 0) || + fromCmp >= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.from, to) <= 0 : cmp(found.from, to) < 0)) + { return true } + } } +} + +// A visual line is a line as drawn on the screen. Folding, for +// example, can cause multiple logical lines to appear on the same +// visual line. This finds the start of the visual line that the +// given line is part of (usually that is the line itself). +function visualLine(line) { + var merged + while (merged = collapsedSpanAtStart(line)) + { line = merged.find(-1, true).line } + return line +} + +function visualLineEnd(line) { + var merged + while (merged = collapsedSpanAtEnd(line)) + { line = merged.find(1, true).line } + return line +} + +// Returns an array of logical lines that continue the visual line +// started by the argument, or undefined if there are no such lines. +function visualLineContinued(line) { + var merged, lines + while (merged = collapsedSpanAtEnd(line)) { + line = merged.find(1, true).line + ;(lines || (lines = [])).push(line) + } + return lines +} + +// Get the line number of the start of the visual line that the +// given line number is part of. +function visualLineNo(doc, lineN) { + var line = getLine(doc, lineN), vis = visualLine(line) + if (line == vis) { return lineN } + return lineNo(vis) +} + +// Get the line number of the start of the next visual line after +// the given line. +function visualLineEndNo(doc, lineN) { + if (lineN > doc.lastLine()) { return lineN } + var line = getLine(doc, lineN), merged + if (!lineIsHidden(doc, line)) { return lineN } + while (merged = collapsedSpanAtEnd(line)) + { line = merged.find(1, true).line } + return lineNo(line) + 1 +} + +// Compute whether a line is hidden. Lines count as hidden when they +// are part of a visual line that starts with another line, or when +// they are entirely covered by collapsed, non-widget span. +function lineIsHidden(doc, line) { + var sps = sawCollapsedSpans && line.markedSpans + if (sps) { for (var sp = (void 0), i = 0; i < sps.length; ++i) { + sp = sps[i] + if (!sp.marker.collapsed) { continue } + if (sp.from == null) { return true } + if (sp.marker.widgetNode) { continue } + if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp)) + { return true } + } } +} +function lineIsHiddenInner(doc, line, span) { + if (span.to == null) { + var end = span.marker.find(1, true) + return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker)) + } + if (span.marker.inclusiveRight && span.to == line.text.length) + { return true } + for (var sp = (void 0), i = 0; i < line.markedSpans.length; ++i) { + sp = line.markedSpans[i] + if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to && + (sp.to == null || sp.to != span.from) && + (sp.marker.inclusiveLeft || span.marker.inclusiveRight) && + lineIsHiddenInner(doc, line, sp)) { return true } + } +} + +// Find the height above the given line. +function heightAtLine(lineObj) { + lineObj = visualLine(lineObj) + + var h = 0, chunk = lineObj.parent + for (var i = 0; i < chunk.lines.length; ++i) { + var line = chunk.lines[i] + if (line == lineObj) { break } + else { h += line.height } + } + for (var p = chunk.parent; p; chunk = p, p = chunk.parent) { + for (var i$1 = 0; i$1 < p.children.length; ++i$1) { + var cur = p.children[i$1] + if (cur == chunk) { break } + else { h += cur.height } + } + } + return h +} + +// Compute the character length of a line, taking into account +// collapsed ranges (see markText) that might hide parts, and join +// other lines onto it. +function lineLength(line) { + if (line.height == 0) { return 0 } + var len = line.text.length, merged, cur = line + while (merged = collapsedSpanAtStart(cur)) { + var found = merged.find(0, true) + cur = found.from.line + len += found.from.ch - found.to.ch + } + cur = line + while (merged = collapsedSpanAtEnd(cur)) { + var found$1 = merged.find(0, true) + len -= cur.text.length - found$1.from.ch + cur = found$1.to.line + len += cur.text.length - found$1.to.ch + } + return len +} + +// Find the longest line in the document. +function findMaxLine(cm) { + var d = cm.display, doc = cm.doc + d.maxLine = getLine(doc, doc.first) + d.maxLineLength = lineLength(d.maxLine) + d.maxLineChanged = true + doc.iter(function (line) { + var len = lineLength(line) + if (len > d.maxLineLength) { + d.maxLineLength = len + d.maxLine = line + } + }) +} + +// BIDI HELPERS + +function iterateBidiSections(order, from, to, f) { + if (!order) { return f(from, to, "ltr", 0) } + var found = false + for (var i = 0; i < order.length; ++i) { + var part = order[i] + if (part.from < to && part.to > from || from == to && part.to == from) { + f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr", i) + found = true + } + } + if (!found) { f(from, to, "ltr") } +} + +var bidiOther = null +function getBidiPartAt(order, ch, sticky) { + var found + bidiOther = null + for (var i = 0; i < order.length; ++i) { + var cur = order[i] + if (cur.from < ch && cur.to > ch) { return i } + if (cur.to == ch) { + if (cur.from != cur.to && sticky == "before") { found = i } + else { bidiOther = i } + } + if (cur.from == ch) { + if (cur.from != cur.to && sticky != "before") { found = i } + else { bidiOther = i } + } + } + return found != null ? found : bidiOther +} + +// Bidirectional ordering algorithm +// See http://unicode.org/reports/tr9/tr9-13.html for the algorithm +// that this (partially) implements. + +// One-char codes used for character types: +// L (L): Left-to-Right +// R (R): Right-to-Left +// r (AL): Right-to-Left Arabic +// 1 (EN): European Number +// + (ES): European Number Separator +// % (ET): European Number Terminator +// n (AN): Arabic Number +// , (CS): Common Number Separator +// m (NSM): Non-Spacing Mark +// b (BN): Boundary Neutral +// s (B): Paragraph Separator +// t (S): Segment Separator +// w (WS): Whitespace +// N (ON): Other Neutrals + +// Returns null if characters are ordered as they appear +// (left-to-right), or an array of sections ({from, to, level} +// objects) in the order in which they occur visually. +var bidiOrdering = (function() { + // Character types for codepoints 0 to 0xff + var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN" + // Character types for codepoints 0x600 to 0x6f9 + var arabicTypes = "nnnnnnNNr%%r,rNNmmmmmmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmmmnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmnNmmmmmmrrmmNmmmmrr1111111111" + function charType(code) { + if (code <= 0xf7) { return lowTypes.charAt(code) } + else if (0x590 <= code && code <= 0x5f4) { return "R" } + else if (0x600 <= code && code <= 0x6f9) { return arabicTypes.charAt(code - 0x600) } + else if (0x6ee <= code && code <= 0x8ac) { return "r" } + else if (0x2000 <= code && code <= 0x200b) { return "w" } + else if (code == 0x200c) { return "b" } + else { return "L" } + } + + var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/ + var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/ + + function BidiSpan(level, from, to) { + this.level = level + this.from = from; this.to = to + } + + return function(str, direction) { + var outerType = direction == "ltr" ? "L" : "R" + + if (str.length == 0 || direction == "ltr" && !bidiRE.test(str)) { return false } + var len = str.length, types = [] + for (var i = 0; i < len; ++i) + { types.push(charType(str.charCodeAt(i))) } + + // W1. Examine each non-spacing mark (NSM) in the level run, and + // change the type of the NSM to the type of the previous + // character. If the NSM is at the start of the level run, it will + // get the type of sor. + for (var i$1 = 0, prev = outerType; i$1 < len; ++i$1) { + var type = types[i$1] + if (type == "m") { types[i$1] = prev } + else { prev = type } + } + + // W2. Search backwards from each instance of a European number + // until the first strong type (R, L, AL, or sor) is found. If an + // AL is found, change the type of the European number to Arabic + // number. + // W3. Change all ALs to R. + for (var i$2 = 0, cur = outerType; i$2 < len; ++i$2) { + var type$1 = types[i$2] + if (type$1 == "1" && cur == "r") { types[i$2] = "n" } + else if (isStrong.test(type$1)) { cur = type$1; if (type$1 == "r") { types[i$2] = "R" } } + } + + // W4. A single European separator between two European numbers + // changes to a European number. A single common separator between + // two numbers of the same type changes to that type. + for (var i$3 = 1, prev$1 = types[0]; i$3 < len - 1; ++i$3) { + var type$2 = types[i$3] + if (type$2 == "+" && prev$1 == "1" && types[i$3+1] == "1") { types[i$3] = "1" } + else if (type$2 == "," && prev$1 == types[i$3+1] && + (prev$1 == "1" || prev$1 == "n")) { types[i$3] = prev$1 } + prev$1 = type$2 + } + + // W5. A sequence of European terminators adjacent to European + // numbers changes to all European numbers. + // W6. Otherwise, separators and terminators change to Other + // Neutral. + for (var i$4 = 0; i$4 < len; ++i$4) { + var type$3 = types[i$4] + if (type$3 == ",") { types[i$4] = "N" } + else if (type$3 == "%") { + var end = (void 0) + for (end = i$4 + 1; end < len && types[end] == "%"; ++end) {} + var replace = (i$4 && types[i$4-1] == "!") || (end < len && types[end] == "1") ? "1" : "N" + for (var j = i$4; j < end; ++j) { types[j] = replace } + i$4 = end - 1 + } + } + + // W7. Search backwards from each instance of a European number + // until the first strong type (R, L, or sor) is found. If an L is + // found, then change the type of the European number to L. + for (var i$5 = 0, cur$1 = outerType; i$5 < len; ++i$5) { + var type$4 = types[i$5] + if (cur$1 == "L" && type$4 == "1") { types[i$5] = "L" } + else if (isStrong.test(type$4)) { cur$1 = type$4 } + } + + // N1. A sequence of neutrals takes the direction of the + // surrounding strong text if the text on both sides has the same + // direction. European and Arabic numbers act as if they were R in + // terms of their influence on neutrals. Start-of-level-run (sor) + // and end-of-level-run (eor) are used at level run boundaries. + // N2. Any remaining neutrals take the embedding direction. + for (var i$6 = 0; i$6 < len; ++i$6) { + if (isNeutral.test(types[i$6])) { + var end$1 = (void 0) + for (end$1 = i$6 + 1; end$1 < len && isNeutral.test(types[end$1]); ++end$1) {} + var before = (i$6 ? types[i$6-1] : outerType) == "L" + var after = (end$1 < len ? types[end$1] : outerType) == "L" + var replace$1 = before == after ? (before ? "L" : "R") : outerType + for (var j$1 = i$6; j$1 < end$1; ++j$1) { types[j$1] = replace$1 } + i$6 = end$1 - 1 + } + } + + // Here we depart from the documented algorithm, in order to avoid + // building up an actual levels array. Since there are only three + // levels (0, 1, 2) in an implementation that doesn't take + // explicit embedding into account, we can build up the order on + // the fly, without following the level-based algorithm. + var order = [], m + for (var i$7 = 0; i$7 < len;) { + if (countsAsLeft.test(types[i$7])) { + var start = i$7 + for (++i$7; i$7 < len && countsAsLeft.test(types[i$7]); ++i$7) {} + order.push(new BidiSpan(0, start, i$7)) + } else { + var pos = i$7, at = order.length + for (++i$7; i$7 < len && types[i$7] != "L"; ++i$7) {} + for (var j$2 = pos; j$2 < i$7;) { + if (countsAsNum.test(types[j$2])) { + if (pos < j$2) { order.splice(at, 0, new BidiSpan(1, pos, j$2)) } + var nstart = j$2 + for (++j$2; j$2 < i$7 && countsAsNum.test(types[j$2]); ++j$2) {} + order.splice(at, 0, new BidiSpan(2, nstart, j$2)) + pos = j$2 + } else { ++j$2 } + } + if (pos < i$7) { order.splice(at, 0, new BidiSpan(1, pos, i$7)) } + } + } + if (direction == "ltr") { + if (order[0].level == 1 && (m = str.match(/^\s+/))) { + order[0].from = m[0].length + order.unshift(new BidiSpan(0, 0, m[0].length)) + } + if (lst(order).level == 1 && (m = str.match(/\s+$/))) { + lst(order).to -= m[0].length + order.push(new BidiSpan(0, len - m[0].length, len)) + } + } + + return direction == "rtl" ? order.reverse() : order + } +})() + +// Get the bidi ordering for the given line (and cache it). Returns +// false for lines that are fully left-to-right, and an array of +// BidiSpan objects otherwise. +function getOrder(line, direction) { + var order = line.order + if (order == null) { order = line.order = bidiOrdering(line.text, direction) } + return order +} + +// EVENT HANDLING + +// Lightweight event framework. on/off also work on DOM nodes, +// registering native DOM handlers. + +var noHandlers = [] + +var on = function(emitter, type, f) { + if (emitter.addEventListener) { + emitter.addEventListener(type, f, false) + } else if (emitter.attachEvent) { + emitter.attachEvent("on" + type, f) + } else { + var map = emitter._handlers || (emitter._handlers = {}) + map[type] = (map[type] || noHandlers).concat(f) + } +} + +function getHandlers(emitter, type) { + return emitter._handlers && emitter._handlers[type] || noHandlers +} + +function off(emitter, type, f) { + if (emitter.removeEventListener) { + emitter.removeEventListener(type, f, false) + } else if (emitter.detachEvent) { + emitter.detachEvent("on" + type, f) + } else { + var map = emitter._handlers, arr = map && map[type] + if (arr) { + var index = indexOf(arr, f) + if (index > -1) + { map[type] = arr.slice(0, index).concat(arr.slice(index + 1)) } + } + } +} + +function signal(emitter, type /*, values...*/) { + var handlers = getHandlers(emitter, type) + if (!handlers.length) { return } + var args = Array.prototype.slice.call(arguments, 2) + for (var i = 0; i < handlers.length; ++i) { handlers[i].apply(null, args) } +} + +// The DOM events that CodeMirror handles can be overridden by +// registering a (non-DOM) handler on the editor for the event name, +// and preventDefault-ing the event in that handler. +function signalDOMEvent(cm, e, override) { + if (typeof e == "string") + { e = {type: e, preventDefault: function() { this.defaultPrevented = true }} } + signal(cm, override || e.type, cm, e) + return e_defaultPrevented(e) || e.codemirrorIgnore +} + +function signalCursorActivity(cm) { + var arr = cm._handlers && cm._handlers.cursorActivity + if (!arr) { return } + var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []) + for (var i = 0; i < arr.length; ++i) { if (indexOf(set, arr[i]) == -1) + { set.push(arr[i]) } } +} + +function hasHandler(emitter, type) { + return getHandlers(emitter, type).length > 0 +} + +// Add on and off methods to a constructor's prototype, to make +// registering events on such objects more convenient. +function eventMixin(ctor) { + ctor.prototype.on = function(type, f) {on(this, type, f)} + ctor.prototype.off = function(type, f) {off(this, type, f)} +} + +// Due to the fact that we still support jurassic IE versions, some +// compatibility wrappers are needed. + +function e_preventDefault(e) { + if (e.preventDefault) { e.preventDefault() } + else { e.returnValue = false } +} +function e_stopPropagation(e) { + if (e.stopPropagation) { e.stopPropagation() } + else { e.cancelBubble = true } +} +function e_defaultPrevented(e) { + return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false +} +function e_stop(e) {e_preventDefault(e); e_stopPropagation(e)} + +function e_target(e) {return e.target || e.srcElement} +function e_button(e) { + var b = e.which + if (b == null) { + if (e.button & 1) { b = 1 } + else if (e.button & 2) { b = 3 } + else if (e.button & 4) { b = 2 } + } + if (mac && e.ctrlKey && b == 1) { b = 3 } + return b +} + +// Detect drag-and-drop +var dragAndDrop = function() { + // There is *some* kind of drag-and-drop support in IE6-8, but I + // couldn't get it to work yet. + if (ie && ie_version < 9) { return false } + var div = elt('div') + return "draggable" in div || "dragDrop" in div +}() + +var zwspSupported +function zeroWidthElement(measure) { + if (zwspSupported == null) { + var test = elt("span", "\u200b") + removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")])) + if (measure.firstChild.offsetHeight != 0) + { zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8) } + } + var node = zwspSupported ? elt("span", "\u200b") : + elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px") + node.setAttribute("cm-text", "") + return node +} + +// Feature-detect IE's crummy client rect reporting for bidi text +var badBidiRects +function hasBadBidiRects(measure) { + if (badBidiRects != null) { return badBidiRects } + var txt = removeChildrenAndAdd(measure, document.createTextNode("A\u062eA")) + var r0 = range(txt, 0, 1).getBoundingClientRect() + var r1 = range(txt, 1, 2).getBoundingClientRect() + removeChildren(measure) + if (!r0 || r0.left == r0.right) { return false } // Safari returns null in some cases (#2780) + return badBidiRects = (r1.right - r0.right < 3) +} + +// See if "".split is the broken IE version, if so, provide an +// alternative way to split lines. +var splitLinesAuto = "\n\nb".split(/\n/).length != 3 ? function (string) { + var pos = 0, result = [], l = string.length + while (pos <= l) { + var nl = string.indexOf("\n", pos) + if (nl == -1) { nl = string.length } + var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl) + var rt = line.indexOf("\r") + if (rt != -1) { + result.push(line.slice(0, rt)) + pos += rt + 1 + } else { + result.push(line) + pos = nl + 1 + } + } + return result +} : function (string) { return string.split(/\r\n?|\n/); } + +var hasSelection = window.getSelection ? function (te) { + try { return te.selectionStart != te.selectionEnd } + catch(e) { return false } +} : function (te) { + var range + try {range = te.ownerDocument.selection.createRange()} + catch(e) {} + if (!range || range.parentElement() != te) { return false } + return range.compareEndPoints("StartToEnd", range) != 0 +} + +var hasCopyEvent = (function () { + var e = elt("div") + if ("oncopy" in e) { return true } + e.setAttribute("oncopy", "return;") + return typeof e.oncopy == "function" +})() + +var badZoomedRects = null +function hasBadZoomedRects(measure) { + if (badZoomedRects != null) { return badZoomedRects } + var node = removeChildrenAndAdd(measure, elt("span", "x")) + var normal = node.getBoundingClientRect() + var fromRange = range(node, 0, 1).getBoundingClientRect() + return badZoomedRects = Math.abs(normal.left - fromRange.left) > 1 +} + +var modes = {}; +var mimeModes = {}; +// Extra arguments are stored as the mode's dependencies, which is +// used by (legacy) mechanisms like loadmode.js to automatically +// load a mode. (Preferred mechanism is the require/define calls.) +function defineMode(name, mode) { + if (arguments.length > 2) + { mode.dependencies = Array.prototype.slice.call(arguments, 2) } + modes[name] = mode +} + +function defineMIME(mime, spec) { + mimeModes[mime] = spec +} + +// Given a MIME type, a {name, ...options} config object, or a name +// string, return a mode config object. +function resolveMode(spec) { + if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) { + spec = mimeModes[spec] + } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) { + var found = mimeModes[spec.name] + if (typeof found == "string") { found = {name: found} } + spec = createObj(found, spec) + spec.name = found.name + } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) { + return resolveMode("application/xml") + } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+json$/.test(spec)) { + return resolveMode("application/json") + } + if (typeof spec == "string") { return {name: spec} } + else { return spec || {name: "null"} } +} + +// Given a mode spec (anything that resolveMode accepts), find and +// initialize an actual mode object. +function getMode(options, spec) { + spec = resolveMode(spec) + var mfactory = modes[spec.name] + if (!mfactory) { return getMode(options, "text/plain") } + var modeObj = mfactory(options, spec) + if (modeExtensions.hasOwnProperty(spec.name)) { + var exts = modeExtensions[spec.name] + for (var prop in exts) { + if (!exts.hasOwnProperty(prop)) { continue } + if (modeObj.hasOwnProperty(prop)) { modeObj["_" + prop] = modeObj[prop] } + modeObj[prop] = exts[prop] + } + } + modeObj.name = spec.name + if (spec.helperType) { modeObj.helperType = spec.helperType } + if (spec.modeProps) { for (var prop$1 in spec.modeProps) + { modeObj[prop$1] = spec.modeProps[prop$1] } } + + return modeObj +} + +// This can be used to attach properties to mode objects from +// outside the actual mode definition. +var modeExtensions = {} +function extendMode(mode, properties) { + var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {}) + copyObj(properties, exts) +} + +function copyState(mode, state) { + if (state === true) { return state } + if (mode.copyState) { return mode.copyState(state) } + var nstate = {} + for (var n in state) { + var val = state[n] + if (val instanceof Array) { val = val.concat([]) } + nstate[n] = val + } + return nstate +} + +// Given a mode and a state (for that mode), find the inner mode and +// state at the position that the state refers to. +function innerMode(mode, state) { + var info + while (mode.innerMode) { + info = mode.innerMode(state) + if (!info || info.mode == mode) { break } + state = info.state + mode = info.mode + } + return info || {mode: mode, state: state} +} + +function startState(mode, a1, a2) { + return mode.startState ? mode.startState(a1, a2) : true +} + +// STRING STREAM + +// Fed to the mode parsers, provides helper functions to make +// parsers more succinct. + +var StringStream = function(string, tabSize, lineOracle) { + this.pos = this.start = 0 + this.string = string + this.tabSize = tabSize || 8 + this.lastColumnPos = this.lastColumnValue = 0 + this.lineStart = 0 + this.lineOracle = lineOracle +}; + +StringStream.prototype.eol = function () {return this.pos >= this.string.length}; +StringStream.prototype.sol = function () {return this.pos == this.lineStart}; +StringStream.prototype.peek = function () {return this.string.charAt(this.pos) || undefined}; +StringStream.prototype.next = function () { + if (this.pos < this.string.length) + { return this.string.charAt(this.pos++) } +}; +StringStream.prototype.eat = function (match) { + var ch = this.string.charAt(this.pos) + var ok + if (typeof match == "string") { ok = ch == match } + else { ok = ch && (match.test ? match.test(ch) : match(ch)) } + if (ok) {++this.pos; return ch} +}; +StringStream.prototype.eatWhile = function (match) { + var start = this.pos + while (this.eat(match)){} + return this.pos > start +}; +StringStream.prototype.eatSpace = function () { + var this$1 = this; + + var start = this.pos + while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) { ++this$1.pos } + return this.pos > start +}; +StringStream.prototype.skipToEnd = function () {this.pos = this.string.length}; +StringStream.prototype.skipTo = function (ch) { + var found = this.string.indexOf(ch, this.pos) + if (found > -1) {this.pos = found; return true} +}; +StringStream.prototype.backUp = function (n) {this.pos -= n}; +StringStream.prototype.column = function () { + if (this.lastColumnPos < this.start) { + this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue) + this.lastColumnPos = this.start + } + return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0) +}; +StringStream.prototype.indentation = function () { + return countColumn(this.string, null, this.tabSize) - + (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0) +}; +StringStream.prototype.match = function (pattern, consume, caseInsensitive) { + if (typeof pattern == "string") { + var cased = function (str) { return caseInsensitive ? str.toLowerCase() : str; } + var substr = this.string.substr(this.pos, pattern.length) + if (cased(substr) == cased(pattern)) { + if (consume !== false) { this.pos += pattern.length } + return true + } + } else { + var match = this.string.slice(this.pos).match(pattern) + if (match && match.index > 0) { return null } + if (match && consume !== false) { this.pos += match[0].length } + return match + } +}; +StringStream.prototype.current = function (){return this.string.slice(this.start, this.pos)}; +StringStream.prototype.hideFirstChars = function (n, inner) { + this.lineStart += n + try { return inner() } + finally { this.lineStart -= n } +}; +StringStream.prototype.lookAhead = function (n) { + var oracle = this.lineOracle + return oracle && oracle.lookAhead(n) +}; +StringStream.prototype.baseToken = function () { + var oracle = this.lineOracle + return oracle && oracle.baseToken(this.pos) +}; + +var SavedContext = function(state, lookAhead) { + this.state = state + this.lookAhead = lookAhead +}; + +var Context = function(doc, state, line, lookAhead) { + this.state = state + this.doc = doc + this.line = line + this.maxLookAhead = lookAhead || 0 + this.baseTokens = null + this.baseTokenPos = 1 +}; + +Context.prototype.lookAhead = function (n) { + var line = this.doc.getLine(this.line + n) + if (line != null && n > this.maxLookAhead) { this.maxLookAhead = n } + return line +}; + +Context.prototype.baseToken = function (n) { + var this$1 = this; + + if (!this.baseTokens) { return null } + while (this.baseTokens[this.baseTokenPos] <= n) + { this$1.baseTokenPos += 2 } + var type = this.baseTokens[this.baseTokenPos + 1] + return {type: type && type.replace(/( |^)overlay .*/, ""), + size: this.baseTokens[this.baseTokenPos] - n} +}; + +Context.prototype.nextLine = function () { + this.line++ + if (this.maxLookAhead > 0) { this.maxLookAhead-- } +}; + +Context.fromSaved = function (doc, saved, line) { + if (saved instanceof SavedContext) + { return new Context(doc, copyState(doc.mode, saved.state), line, saved.lookAhead) } + else + { return new Context(doc, copyState(doc.mode, saved), line) } +}; + +Context.prototype.save = function (copy) { + var state = copy !== false ? copyState(this.doc.mode, this.state) : this.state + return this.maxLookAhead > 0 ? new SavedContext(state, this.maxLookAhead) : state +}; + + +// Compute a style array (an array starting with a mode generation +// -- for invalidation -- followed by pairs of end positions and +// style strings), which is used to highlight the tokens on the +// line. +function highlightLine(cm, line, context, forceToEnd) { + // A styles array always starts with a number identifying the + // mode/overlays that it is based on (for easy invalidation). + var st = [cm.state.modeGen], lineClasses = {} + // Compute the base array of styles + runMode(cm, line.text, cm.doc.mode, context, function (end, style) { return st.push(end, style); }, + lineClasses, forceToEnd) + var state = context.state + + // Run overlays, adjust style array. + var loop = function ( o ) { + context.baseTokens = st + var overlay = cm.state.overlays[o], i = 1, at = 0 + context.state = true + runMode(cm, line.text, overlay.mode, context, function (end, style) { + var start = i + // Ensure there's a token end at the current position, and that i points at it + while (at < end) { + var i_end = st[i] + if (i_end > end) + { st.splice(i, 1, end, st[i+1], i_end) } + i += 2 + at = Math.min(end, i_end) + } + if (!style) { return } + if (overlay.opaque) { + st.splice(start, i - start, end, "overlay " + style) + i = start + 2 + } else { + for (; start < i; start += 2) { + var cur = st[start+1] + st[start+1] = (cur ? cur + " " : "") + "overlay " + style + } + } + }, lineClasses) + context.state = state + context.baseTokens = null + context.baseTokenPos = 1 + }; + + for (var o = 0; o < cm.state.overlays.length; ++o) loop( o ); + + return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null} +} + +function getLineStyles(cm, line, updateFrontier) { + if (!line.styles || line.styles[0] != cm.state.modeGen) { + var context = getContextBefore(cm, lineNo(line)) + var resetState = line.text.length > cm.options.maxHighlightLength && copyState(cm.doc.mode, context.state) + var result = highlightLine(cm, line, context) + if (resetState) { context.state = resetState } + line.stateAfter = context.save(!resetState) + line.styles = result.styles + if (result.classes) { line.styleClasses = result.classes } + else if (line.styleClasses) { line.styleClasses = null } + if (updateFrontier === cm.doc.highlightFrontier) + { cm.doc.modeFrontier = Math.max(cm.doc.modeFrontier, ++cm.doc.highlightFrontier) } + } + return line.styles +} + +function getContextBefore(cm, n, precise) { + var doc = cm.doc, display = cm.display + if (!doc.mode.startState) { return new Context(doc, true, n) } + var start = findStartLine(cm, n, precise) + var saved = start > doc.first && getLine(doc, start - 1).stateAfter + var context = saved ? Context.fromSaved(doc, saved, start) : new Context(doc, startState(doc.mode), start) + + doc.iter(start, n, function (line) { + processLine(cm, line.text, context) + var pos = context.line + line.stateAfter = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo ? context.save() : null + context.nextLine() + }) + if (precise) { doc.modeFrontier = context.line } + return context +} + +// Lightweight form of highlight -- proceed over this line and +// update state, but don't save a style array. Used for lines that +// aren't currently visible. +function processLine(cm, text, context, startAt) { + var mode = cm.doc.mode + var stream = new StringStream(text, cm.options.tabSize, context) + stream.start = stream.pos = startAt || 0 + if (text == "") { callBlankLine(mode, context.state) } + while (!stream.eol()) { + readToken(mode, stream, context.state) + stream.start = stream.pos + } +} + +function callBlankLine(mode, state) { + if (mode.blankLine) { return mode.blankLine(state) } + if (!mode.innerMode) { return } + var inner = innerMode(mode, state) + if (inner.mode.blankLine) { return inner.mode.blankLine(inner.state) } +} + +function readToken(mode, stream, state, inner) { + for (var i = 0; i < 10; i++) { + if (inner) { inner[0] = innerMode(mode, state).mode } + var style = mode.token(stream, state) + if (stream.pos > stream.start) { return style } + } + throw new Error("Mode " + mode.name + " failed to advance stream.") +} + +var Token = function(stream, type, state) { + this.start = stream.start; this.end = stream.pos + this.string = stream.current() + this.type = type || null + this.state = state +}; + +// Utility for getTokenAt and getLineTokens +function takeToken(cm, pos, precise, asArray) { + var doc = cm.doc, mode = doc.mode, style + pos = clipPos(doc, pos) + var line = getLine(doc, pos.line), context = getContextBefore(cm, pos.line, precise) + var stream = new StringStream(line.text, cm.options.tabSize, context), tokens + if (asArray) { tokens = [] } + while ((asArray || stream.pos < pos.ch) && !stream.eol()) { + stream.start = stream.pos + style = readToken(mode, stream, context.state) + if (asArray) { tokens.push(new Token(stream, style, copyState(doc.mode, context.state))) } + } + return asArray ? tokens : new Token(stream, style, context.state) +} + +function extractLineClasses(type, output) { + if (type) { for (;;) { + var lineClass = type.match(/(?:^|\s+)line-(background-)?(\S+)/) + if (!lineClass) { break } + type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length) + var prop = lineClass[1] ? "bgClass" : "textClass" + if (output[prop] == null) + { output[prop] = lineClass[2] } + else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(output[prop])) + { output[prop] += " " + lineClass[2] } + } } + return type +} + +// Run the given mode's parser over a line, calling f for each token. +function runMode(cm, text, mode, context, f, lineClasses, forceToEnd) { + var flattenSpans = mode.flattenSpans + if (flattenSpans == null) { flattenSpans = cm.options.flattenSpans } + var curStart = 0, curStyle = null + var stream = new StringStream(text, cm.options.tabSize, context), style + var inner = cm.options.addModeClass && [null] + if (text == "") { extractLineClasses(callBlankLine(mode, context.state), lineClasses) } + while (!stream.eol()) { + if (stream.pos > cm.options.maxHighlightLength) { + flattenSpans = false + if (forceToEnd) { processLine(cm, text, context, stream.pos) } + stream.pos = text.length + style = null + } else { + style = extractLineClasses(readToken(mode, stream, context.state, inner), lineClasses) + } + if (inner) { + var mName = inner[0].name + if (mName) { style = "m-" + (style ? mName + " " + style : mName) } + } + if (!flattenSpans || curStyle != style) { + while (curStart < stream.start) { + curStart = Math.min(stream.start, curStart + 5000) + f(curStart, curStyle) + } + curStyle = style + } + stream.start = stream.pos + } + while (curStart < stream.pos) { + // Webkit seems to refuse to render text nodes longer than 57444 + // characters, and returns inaccurate measurements in nodes + // starting around 5000 chars. + var pos = Math.min(stream.pos, curStart + 5000) + f(pos, curStyle) + curStart = pos + } +} + +// Finds the line to start with when starting a parse. Tries to +// find a line with a stateAfter, so that it can start with a +// valid state. If that fails, it returns the line with the +// smallest indentation, which tends to need the least context to +// parse correctly. +function findStartLine(cm, n, precise) { + var minindent, minline, doc = cm.doc + var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100) + for (var search = n; search > lim; --search) { + if (search <= doc.first) { return doc.first } + var line = getLine(doc, search - 1), after = line.stateAfter + if (after && (!precise || search + (after instanceof SavedContext ? after.lookAhead : 0) <= doc.modeFrontier)) + { return search } + var indented = countColumn(line.text, null, cm.options.tabSize) + if (minline == null || minindent > indented) { + minline = search - 1 + minindent = indented + } + } + return minline +} + +function retreatFrontier(doc, n) { + doc.modeFrontier = Math.min(doc.modeFrontier, n) + if (doc.highlightFrontier < n - 10) { return } + var start = doc.first + for (var line = n - 1; line > start; line--) { + var saved = getLine(doc, line).stateAfter + // change is on 3 + // state on line 1 looked ahead 2 -- so saw 3 + // test 1 + 2 < 3 should cover this + if (saved && (!(saved instanceof SavedContext) || line + saved.lookAhead < n)) { + start = line + 1 + break + } + } + doc.highlightFrontier = Math.min(doc.highlightFrontier, start) +} + +// LINE DATA STRUCTURE + +// Line objects. These hold state related to a line, including +// highlighting info (the styles array). +var Line = function(text, markedSpans, estimateHeight) { + this.text = text + attachMarkedSpans(this, markedSpans) + this.height = estimateHeight ? estimateHeight(this) : 1 +}; + +Line.prototype.lineNo = function () { return lineNo(this) }; +eventMixin(Line) + +// Change the content (text, markers) of a line. Automatically +// invalidates cached information and tries to re-estimate the +// line's height. +function updateLine(line, text, markedSpans, estimateHeight) { + line.text = text + if (line.stateAfter) { line.stateAfter = null } + if (line.styles) { line.styles = null } + if (line.order != null) { line.order = null } + detachMarkedSpans(line) + attachMarkedSpans(line, markedSpans) + var estHeight = estimateHeight ? estimateHeight(line) : 1 + if (estHeight != line.height) { updateLineHeight(line, estHeight) } +} + +// Detach a line from the document tree and its markers. +function cleanUpLine(line) { + line.parent = null + detachMarkedSpans(line) +} + +// Convert a style as returned by a mode (either null, or a string +// containing one or more styles) to a CSS style. This is cached, +// and also looks for line-wide styles. +var styleToClassCache = {}; +var styleToClassCacheWithMode = {}; +function interpretTokenStyle(style, options) { + if (!style || /^\s*$/.test(style)) { return null } + var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache + return cache[style] || + (cache[style] = style.replace(/\S+/g, "cm-$&")) +} + +// Render the DOM representation of the text of a line. Also builds +// up a 'line map', which points at the DOM nodes that represent +// specific stretches of text, and is used by the measuring code. +// The returned object contains the DOM node, this map, and +// information about line-wide styles that were set by the mode. +function buildLineContent(cm, lineView) { + // The padding-right forces the element to have a 'border', which + // is needed on Webkit to be able to get line-level bounding + // rectangles for it (in measureChar). + var content = eltP("span", null, null, webkit ? "padding-right: .1px" : null) + var builder = {pre: eltP("pre", [content], "CodeMirror-line"), content: content, + col: 0, pos: 0, cm: cm, + trailingSpace: false, + splitSpaces: (ie || webkit) && cm.getOption("lineWrapping")} + lineView.measure = {} + + // Iterate over the logical lines that make up this visual line. + for (var i = 0; i <= (lineView.rest ? lineView.rest.length : 0); i++) { + var line = i ? lineView.rest[i - 1] : lineView.line, order = (void 0) + builder.pos = 0 + builder.addToken = buildToken + // Optionally wire in some hacks into the token-rendering + // algorithm, to deal with browser quirks. + if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line, cm.doc.direction))) + { builder.addToken = buildTokenBadBidi(builder.addToken, order) } + builder.map = [] + var allowFrontierUpdate = lineView != cm.display.externalMeasured && lineNo(line) + insertLineContent(line, builder, getLineStyles(cm, line, allowFrontierUpdate)) + if (line.styleClasses) { + if (line.styleClasses.bgClass) + { builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || "") } + if (line.styleClasses.textClass) + { builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || "") } + } + + // Ensure at least a single node is present, for measuring. + if (builder.map.length == 0) + { builder.map.push(0, 0, builder.content.appendChild(zeroWidthElement(cm.display.measure))) } + + // Store the map and a cache object for the current logical line + if (i == 0) { + lineView.measure.map = builder.map + lineView.measure.cache = {} + } else { + ;(lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map) + ;(lineView.measure.caches || (lineView.measure.caches = [])).push({}) + } + } + + // See issue #2901 + if (webkit) { + var last = builder.content.lastChild + if (/\bcm-tab\b/.test(last.className) || (last.querySelector && last.querySelector(".cm-tab"))) + { builder.content.className = "cm-tab-wrap-hack" } + } + + signal(cm, "renderLine", cm, lineView.line, builder.pre) + if (builder.pre.className) + { builder.textClass = joinClasses(builder.pre.className, builder.textClass || "") } + + return builder +} + +function defaultSpecialCharPlaceholder(ch) { + var token = elt("span", "\u2022", "cm-invalidchar") + token.title = "\\u" + ch.charCodeAt(0).toString(16) + token.setAttribute("aria-label", token.title) + return token +} + +// Build up the DOM representation for a single token, and add it to +// the line map. Takes care to render special characters separately. +function buildToken(builder, text, style, startStyle, endStyle, title, css) { + if (!text) { return } + var displayText = builder.splitSpaces ? splitSpaces(text, builder.trailingSpace) : text + var special = builder.cm.state.specialChars, mustWrap = false + var content + if (!special.test(text)) { + builder.col += text.length + content = document.createTextNode(displayText) + builder.map.push(builder.pos, builder.pos + text.length, content) + if (ie && ie_version < 9) { mustWrap = true } + builder.pos += text.length + } else { + content = document.createDocumentFragment() + var pos = 0 + while (true) { + special.lastIndex = pos + var m = special.exec(text) + var skipped = m ? m.index - pos : text.length - pos + if (skipped) { + var txt = document.createTextNode(displayText.slice(pos, pos + skipped)) + if (ie && ie_version < 9) { content.appendChild(elt("span", [txt])) } + else { content.appendChild(txt) } + builder.map.push(builder.pos, builder.pos + skipped, txt) + builder.col += skipped + builder.pos += skipped + } + if (!m) { break } + pos += skipped + 1 + var txt$1 = (void 0) + if (m[0] == "\t") { + var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize + txt$1 = content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab")) + txt$1.setAttribute("role", "presentation") + txt$1.setAttribute("cm-text", "\t") + builder.col += tabWidth + } else if (m[0] == "\r" || m[0] == "\n") { + txt$1 = content.appendChild(elt("span", m[0] == "\r" ? "\u240d" : "\u2424", "cm-invalidchar")) + txt$1.setAttribute("cm-text", m[0]) + builder.col += 1 + } else { + txt$1 = builder.cm.options.specialCharPlaceholder(m[0]) + txt$1.setAttribute("cm-text", m[0]) + if (ie && ie_version < 9) { content.appendChild(elt("span", [txt$1])) } + else { content.appendChild(txt$1) } + builder.col += 1 + } + builder.map.push(builder.pos, builder.pos + 1, txt$1) + builder.pos++ + } + } + builder.trailingSpace = displayText.charCodeAt(text.length - 1) == 32 + if (style || startStyle || endStyle || mustWrap || css) { + var fullStyle = style || "" + if (startStyle) { fullStyle += startStyle } + if (endStyle) { fullStyle += endStyle } + var token = elt("span", [content], fullStyle, css) + if (title) { token.title = title } + return builder.content.appendChild(token) + } + builder.content.appendChild(content) +} + +function splitSpaces(text, trailingBefore) { + if (text.length > 1 && !/ /.test(text)) { return text } + var spaceBefore = trailingBefore, result = "" + for (var i = 0; i < text.length; i++) { + var ch = text.charAt(i) + if (ch == " " && spaceBefore && (i == text.length - 1 || text.charCodeAt(i + 1) == 32)) + { ch = "\u00a0" } + result += ch + spaceBefore = ch == " " + } + return result +} + +// Work around nonsense dimensions being reported for stretches of +// right-to-left text. +function buildTokenBadBidi(inner, order) { + return function (builder, text, style, startStyle, endStyle, title, css) { + style = style ? style + " cm-force-border" : "cm-force-border" + var start = builder.pos, end = start + text.length + for (;;) { + // Find the part that overlaps with the start of this text + var part = (void 0) + for (var i = 0; i < order.length; i++) { + part = order[i] + if (part.to > start && part.from <= start) { break } + } + if (part.to >= end) { return inner(builder, text, style, startStyle, endStyle, title, css) } + inner(builder, text.slice(0, part.to - start), style, startStyle, null, title, css) + startStyle = null + text = text.slice(part.to - start) + start = part.to + } + } +} + +function buildCollapsedSpan(builder, size, marker, ignoreWidget) { + var widget = !ignoreWidget && marker.widgetNode + if (widget) { builder.map.push(builder.pos, builder.pos + size, widget) } + if (!ignoreWidget && builder.cm.display.input.needsContentAttribute) { + if (!widget) + { widget = builder.content.appendChild(document.createElement("span")) } + widget.setAttribute("cm-marker", marker.id) + } + if (widget) { + builder.cm.display.input.setUneditable(widget) + builder.content.appendChild(widget) + } + builder.pos += size + builder.trailingSpace = false +} + +// Outputs a number of spans to make up a line, taking highlighting +// and marked text into account. +function insertLineContent(line, builder, styles) { + var spans = line.markedSpans, allText = line.text, at = 0 + if (!spans) { + for (var i$1 = 1; i$1 < styles.length; i$1+=2) + { builder.addToken(builder, allText.slice(at, at = styles[i$1]), interpretTokenStyle(styles[i$1+1], builder.cm.options)) } + return + } + + var len = allText.length, pos = 0, i = 1, text = "", style, css + var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed + for (;;) { + if (nextChange == pos) { // Update current marker set + spanStyle = spanEndStyle = spanStartStyle = title = css = "" + collapsed = null; nextChange = Infinity + var foundBookmarks = [], endStyles = (void 0) + for (var j = 0; j < spans.length; ++j) { + var sp = spans[j], m = sp.marker + if (m.type == "bookmark" && sp.from == pos && m.widgetNode) { + foundBookmarks.push(m) + } else if (sp.from <= pos && (sp.to == null || sp.to > pos || m.collapsed && sp.to == pos && sp.from == pos)) { + if (sp.to != null && sp.to != pos && nextChange > sp.to) { + nextChange = sp.to + spanEndStyle = "" + } + if (m.className) { spanStyle += " " + m.className } + if (m.css) { css = (css ? css + ";" : "") + m.css } + if (m.startStyle && sp.from == pos) { spanStartStyle += " " + m.startStyle } + if (m.endStyle && sp.to == nextChange) { (endStyles || (endStyles = [])).push(m.endStyle, sp.to) } + if (m.title && !title) { title = m.title } + if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0)) + { collapsed = sp } + } else if (sp.from > pos && nextChange > sp.from) { + nextChange = sp.from + } + } + if (endStyles) { for (var j$1 = 0; j$1 < endStyles.length; j$1 += 2) + { if (endStyles[j$1 + 1] == nextChange) { spanEndStyle += " " + endStyles[j$1] } } } + + if (!collapsed || collapsed.from == pos) { for (var j$2 = 0; j$2 < foundBookmarks.length; ++j$2) + { buildCollapsedSpan(builder, 0, foundBookmarks[j$2]) } } + if (collapsed && (collapsed.from || 0) == pos) { + buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos, + collapsed.marker, collapsed.from == null) + if (collapsed.to == null) { return } + if (collapsed.to == pos) { collapsed = false } + } + } + if (pos >= len) { break } + + var upto = Math.min(len, nextChange) + while (true) { + if (text) { + var end = pos + text.length + if (!collapsed) { + var tokenText = end > upto ? text.slice(0, upto - pos) : text + builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle, + spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title, css) + } + if (end >= upto) {text = text.slice(upto - pos); pos = upto; break} + pos = end + spanStartStyle = "" + } + text = allText.slice(at, at = styles[i++]) + style = interpretTokenStyle(styles[i++], builder.cm.options) + } + } +} + + +// These objects are used to represent the visible (currently drawn) +// part of the document. A LineView may correspond to multiple +// logical lines, if those are connected by collapsed ranges. +function LineView(doc, line, lineN) { + // The starting line + this.line = line + // Continuing lines, if any + this.rest = visualLineContinued(line) + // Number of logical lines in this visual line + this.size = this.rest ? lineNo(lst(this.rest)) - lineN + 1 : 1 + this.node = this.text = null + this.hidden = lineIsHidden(doc, line) +} + +// Create a range of LineView objects for the given lines. +function buildViewArray(cm, from, to) { + var array = [], nextPos + for (var pos = from; pos < to; pos = nextPos) { + var view = new LineView(cm.doc, getLine(cm.doc, pos), pos) + nextPos = pos + view.size + array.push(view) + } + return array +} + +var operationGroup = null + +function pushOperation(op) { + if (operationGroup) { + operationGroup.ops.push(op) + } else { + op.ownsGroup = operationGroup = { + ops: [op], + delayedCallbacks: [] + } + } +} + +function fireCallbacksForOps(group) { + // Calls delayed callbacks and cursorActivity handlers until no + // new ones appear + var callbacks = group.delayedCallbacks, i = 0 + do { + for (; i < callbacks.length; i++) + { callbacks[i].call(null) } + for (var j = 0; j < group.ops.length; j++) { + var op = group.ops[j] + if (op.cursorActivityHandlers) + { while (op.cursorActivityCalled < op.cursorActivityHandlers.length) + { op.cursorActivityHandlers[op.cursorActivityCalled++].call(null, op.cm) } } + } + } while (i < callbacks.length) +} + +function finishOperation(op, endCb) { + var group = op.ownsGroup + if (!group) { return } + + try { fireCallbacksForOps(group) } + finally { + operationGroup = null + endCb(group) + } +} + +var orphanDelayedCallbacks = null + +// Often, we want to signal events at a point where we are in the +// middle of some work, but don't want the handler to start calling +// other methods on the editor, which might be in an inconsistent +// state or simply not expect any other events to happen. +// signalLater looks whether there are any handlers, and schedules +// them to be executed when the last operation ends, or, if no +// operation is active, when a timeout fires. +function signalLater(emitter, type /*, values...*/) { + var arr = getHandlers(emitter, type) + if (!arr.length) { return } + var args = Array.prototype.slice.call(arguments, 2), list + if (operationGroup) { + list = operationGroup.delayedCallbacks + } else if (orphanDelayedCallbacks) { + list = orphanDelayedCallbacks + } else { + list = orphanDelayedCallbacks = [] + setTimeout(fireOrphanDelayed, 0) + } + var loop = function ( i ) { + list.push(function () { return arr[i].apply(null, args); }) + }; + + for (var i = 0; i < arr.length; ++i) + loop( i ); +} + +function fireOrphanDelayed() { + var delayed = orphanDelayedCallbacks + orphanDelayedCallbacks = null + for (var i = 0; i < delayed.length; ++i) { delayed[i]() } +} + +// When an aspect of a line changes, a string is added to +// lineView.changes. This updates the relevant part of the line's +// DOM structure. +function updateLineForChanges(cm, lineView, lineN, dims) { + for (var j = 0; j < lineView.changes.length; j++) { + var type = lineView.changes[j] + if (type == "text") { updateLineText(cm, lineView) } + else if (type == "gutter") { updateLineGutter(cm, lineView, lineN, dims) } + else if (type == "class") { updateLineClasses(cm, lineView) } + else if (type == "widget") { updateLineWidgets(cm, lineView, dims) } + } + lineView.changes = null +} + +// Lines with gutter elements, widgets or a background class need to +// be wrapped, and have the extra elements added to the wrapper div +function ensureLineWrapped(lineView) { + if (lineView.node == lineView.text) { + lineView.node = elt("div", null, null, "position: relative") + if (lineView.text.parentNode) + { lineView.text.parentNode.replaceChild(lineView.node, lineView.text) } + lineView.node.appendChild(lineView.text) + if (ie && ie_version < 8) { lineView.node.style.zIndex = 2 } + } + return lineView.node +} + +function updateLineBackground(cm, lineView) { + var cls = lineView.bgClass ? lineView.bgClass + " " + (lineView.line.bgClass || "") : lineView.line.bgClass + if (cls) { cls += " CodeMirror-linebackground" } + if (lineView.background) { + if (cls) { lineView.background.className = cls } + else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null } + } else if (cls) { + var wrap = ensureLineWrapped(lineView) + lineView.background = wrap.insertBefore(elt("div", null, cls), wrap.firstChild) + cm.display.input.setUneditable(lineView.background) + } +} + +// Wrapper around buildLineContent which will reuse the structure +// in display.externalMeasured when possible. +function getLineContent(cm, lineView) { + var ext = cm.display.externalMeasured + if (ext && ext.line == lineView.line) { + cm.display.externalMeasured = null + lineView.measure = ext.measure + return ext.built + } + return buildLineContent(cm, lineView) +} + +// Redraw the line's text. Interacts with the background and text +// classes because the mode may output tokens that influence these +// classes. +function updateLineText(cm, lineView) { + var cls = lineView.text.className + var built = getLineContent(cm, lineView) + if (lineView.text == lineView.node) { lineView.node = built.pre } + lineView.text.parentNode.replaceChild(built.pre, lineView.text) + lineView.text = built.pre + if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) { + lineView.bgClass = built.bgClass + lineView.textClass = built.textClass + updateLineClasses(cm, lineView) + } else if (cls) { + lineView.text.className = cls + } +} + +function updateLineClasses(cm, lineView) { + updateLineBackground(cm, lineView) + if (lineView.line.wrapClass) + { ensureLineWrapped(lineView).className = lineView.line.wrapClass } + else if (lineView.node != lineView.text) + { lineView.node.className = "" } + var textClass = lineView.textClass ? lineView.textClass + " " + (lineView.line.textClass || "") : lineView.line.textClass + lineView.text.className = textClass || "" +} + +function updateLineGutter(cm, lineView, lineN, dims) { + if (lineView.gutter) { + lineView.node.removeChild(lineView.gutter) + lineView.gutter = null + } + if (lineView.gutterBackground) { + lineView.node.removeChild(lineView.gutterBackground) + lineView.gutterBackground = null + } + if (lineView.line.gutterClass) { + var wrap = ensureLineWrapped(lineView) + lineView.gutterBackground = elt("div", null, "CodeMirror-gutter-background " + lineView.line.gutterClass, + ("left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px; width: " + (dims.gutterTotalWidth) + "px")) + cm.display.input.setUneditable(lineView.gutterBackground) + wrap.insertBefore(lineView.gutterBackground, lineView.text) + } + var markers = lineView.line.gutterMarkers + if (cm.options.lineNumbers || markers) { + var wrap$1 = ensureLineWrapped(lineView) + var gutterWrap = lineView.gutter = elt("div", null, "CodeMirror-gutter-wrapper", ("left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px")) + cm.display.input.setUneditable(gutterWrap) + wrap$1.insertBefore(gutterWrap, lineView.text) + if (lineView.line.gutterClass) + { gutterWrap.className += " " + lineView.line.gutterClass } + if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"])) + { lineView.lineNumber = gutterWrap.appendChild( + elt("div", lineNumberFor(cm.options, lineN), + "CodeMirror-linenumber CodeMirror-gutter-elt", + ("left: " + (dims.gutterLeft["CodeMirror-linenumbers"]) + "px; width: " + (cm.display.lineNumInnerWidth) + "px"))) } + if (markers) { for (var k = 0; k < cm.options.gutters.length; ++k) { + var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id] + if (found) + { gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt", + ("left: " + (dims.gutterLeft[id]) + "px; width: " + (dims.gutterWidth[id]) + "px"))) } + } } + } +} + +function updateLineWidgets(cm, lineView, dims) { + if (lineView.alignable) { lineView.alignable = null } + for (var node = lineView.node.firstChild, next = (void 0); node; node = next) { + next = node.nextSibling + if (node.className == "CodeMirror-linewidget") + { lineView.node.removeChild(node) } + } + insertLineWidgets(cm, lineView, dims) +} + +// Build a line's DOM representation from scratch +function buildLineElement(cm, lineView, lineN, dims) { + var built = getLineContent(cm, lineView) + lineView.text = lineView.node = built.pre + if (built.bgClass) { lineView.bgClass = built.bgClass } + if (built.textClass) { lineView.textClass = built.textClass } + + updateLineClasses(cm, lineView) + updateLineGutter(cm, lineView, lineN, dims) + insertLineWidgets(cm, lineView, dims) + return lineView.node +} + +// A lineView may contain multiple logical lines (when merged by +// collapsed spans). The widgets for all of them need to be drawn. +function insertLineWidgets(cm, lineView, dims) { + insertLineWidgetsFor(cm, lineView.line, lineView, dims, true) + if (lineView.rest) { for (var i = 0; i < lineView.rest.length; i++) + { insertLineWidgetsFor(cm, lineView.rest[i], lineView, dims, false) } } +} + +function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) { + if (!line.widgets) { return } + var wrap = ensureLineWrapped(lineView) + for (var i = 0, ws = line.widgets; i < ws.length; ++i) { + var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget") + if (!widget.handleMouseEvents) { node.setAttribute("cm-ignore-events", "true") } + positionLineWidget(widget, node, lineView, dims) + cm.display.input.setUneditable(node) + if (allowAbove && widget.above) + { wrap.insertBefore(node, lineView.gutter || lineView.text) } + else + { wrap.appendChild(node) } + signalLater(widget, "redraw") + } +} + +function positionLineWidget(widget, node, lineView, dims) { + if (widget.noHScroll) { + ;(lineView.alignable || (lineView.alignable = [])).push(node) + var width = dims.wrapperWidth + node.style.left = dims.fixedPos + "px" + if (!widget.coverGutter) { + width -= dims.gutterTotalWidth + node.style.paddingLeft = dims.gutterTotalWidth + "px" + } + node.style.width = width + "px" + } + if (widget.coverGutter) { + node.style.zIndex = 5 + node.style.position = "relative" + if (!widget.noHScroll) { node.style.marginLeft = -dims.gutterTotalWidth + "px" } + } +} + +function widgetHeight(widget) { + if (widget.height != null) { return widget.height } + var cm = widget.doc.cm + if (!cm) { return 0 } + if (!contains(document.body, widget.node)) { + var parentStyle = "position: relative;" + if (widget.coverGutter) + { parentStyle += "margin-left: -" + cm.display.gutters.offsetWidth + "px;" } + if (widget.noHScroll) + { parentStyle += "width: " + cm.display.wrapper.clientWidth + "px;" } + removeChildrenAndAdd(cm.display.measure, elt("div", [widget.node], null, parentStyle)) + } + return widget.height = widget.node.parentNode.offsetHeight +} + +// Return true when the given mouse event happened in a widget +function eventInWidget(display, e) { + for (var n = e_target(e); n != display.wrapper; n = n.parentNode) { + if (!n || (n.nodeType == 1 && n.getAttribute("cm-ignore-events") == "true") || + (n.parentNode == display.sizer && n != display.mover)) + { return true } + } +} + +// POSITION MEASUREMENT + +function paddingTop(display) {return display.lineSpace.offsetTop} +function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight} +function paddingH(display) { + if (display.cachedPaddingH) { return display.cachedPaddingH } + var e = removeChildrenAndAdd(display.measure, elt("pre", "x")) + var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle + var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)} + if (!isNaN(data.left) && !isNaN(data.right)) { display.cachedPaddingH = data } + return data +} + +function scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth } +function displayWidth(cm) { + return cm.display.scroller.clientWidth - scrollGap(cm) - cm.display.barWidth +} +function displayHeight(cm) { + return cm.display.scroller.clientHeight - scrollGap(cm) - cm.display.barHeight +} + +// Ensure the lineView.wrapping.heights array is populated. This is +// an array of bottom offsets for the lines that make up a drawn +// line. When lineWrapping is on, there might be more than one +// height. +function ensureLineHeights(cm, lineView, rect) { + var wrapping = cm.options.lineWrapping + var curWidth = wrapping && displayWidth(cm) + if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) { + var heights = lineView.measure.heights = [] + if (wrapping) { + lineView.measure.width = curWidth + var rects = lineView.text.firstChild.getClientRects() + for (var i = 0; i < rects.length - 1; i++) { + var cur = rects[i], next = rects[i + 1] + if (Math.abs(cur.bottom - next.bottom) > 2) + { heights.push((cur.bottom + next.top) / 2 - rect.top) } + } + } + heights.push(rect.bottom - rect.top) + } +} + +// Find a line map (mapping character offsets to text nodes) and a +// measurement cache for the given line number. (A line view might +// contain multiple lines when collapsed ranges are present.) +function mapFromLineView(lineView, line, lineN) { + if (lineView.line == line) + { return {map: lineView.measure.map, cache: lineView.measure.cache} } + for (var i = 0; i < lineView.rest.length; i++) + { if (lineView.rest[i] == line) + { return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]} } } + for (var i$1 = 0; i$1 < lineView.rest.length; i$1++) + { if (lineNo(lineView.rest[i$1]) > lineN) + { return {map: lineView.measure.maps[i$1], cache: lineView.measure.caches[i$1], before: true} } } +} + +// Render a line into the hidden node display.externalMeasured. Used +// when measurement is needed for a line that's not in the viewport. +function updateExternalMeasurement(cm, line) { + line = visualLine(line) + var lineN = lineNo(line) + var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN) + view.lineN = lineN + var built = view.built = buildLineContent(cm, view) + view.text = built.pre + removeChildrenAndAdd(cm.display.lineMeasure, built.pre) + return view +} + +// Get a {top, bottom, left, right} box (in line-local coordinates) +// for a given character. +function measureChar(cm, line, ch, bias) { + return measureCharPrepared(cm, prepareMeasureForLine(cm, line), ch, bias) +} + +// Find a line view that corresponds to the given line number. +function findViewForLine(cm, lineN) { + if (lineN >= cm.display.viewFrom && lineN < cm.display.viewTo) + { return cm.display.view[findViewIndex(cm, lineN)] } + var ext = cm.display.externalMeasured + if (ext && lineN >= ext.lineN && lineN < ext.lineN + ext.size) + { return ext } +} + +// Measurement can be split in two steps, the set-up work that +// applies to the whole line, and the measurement of the actual +// character. Functions like coordsChar, that need to do a lot of +// measurements in a row, can thus ensure that the set-up work is +// only done once. +function prepareMeasureForLine(cm, line) { + var lineN = lineNo(line) + var view = findViewForLine(cm, lineN) + if (view && !view.text) { + view = null + } else if (view && view.changes) { + updateLineForChanges(cm, view, lineN, getDimensions(cm)) + cm.curOp.forceUpdate = true + } + if (!view) + { view = updateExternalMeasurement(cm, line) } + + var info = mapFromLineView(view, line, lineN) + return { + line: line, view: view, rect: null, + map: info.map, cache: info.cache, before: info.before, + hasHeights: false + } +} + +// Given a prepared measurement object, measures the position of an +// actual character (or fetches it from the cache). +function measureCharPrepared(cm, prepared, ch, bias, varHeight) { + if (prepared.before) { ch = -1 } + var key = ch + (bias || ""), found + if (prepared.cache.hasOwnProperty(key)) { + found = prepared.cache[key] + } else { + if (!prepared.rect) + { prepared.rect = prepared.view.text.getBoundingClientRect() } + if (!prepared.hasHeights) { + ensureLineHeights(cm, prepared.view, prepared.rect) + prepared.hasHeights = true + } + found = measureCharInner(cm, prepared, ch, bias) + if (!found.bogus) { prepared.cache[key] = found } + } + return {left: found.left, right: found.right, + top: varHeight ? found.rtop : found.top, + bottom: varHeight ? found.rbottom : found.bottom} +} + +var nullRect = {left: 0, right: 0, top: 0, bottom: 0} + +function nodeAndOffsetInLineMap(map, ch, bias) { + var node, start, end, collapse, mStart, mEnd + // First, search the line map for the text node corresponding to, + // or closest to, the target character. + for (var i = 0; i < map.length; i += 3) { + mStart = map[i] + mEnd = map[i + 1] + if (ch < mStart) { + start = 0; end = 1 + collapse = "left" + } else if (ch < mEnd) { + start = ch - mStart + end = start + 1 + } else if (i == map.length - 3 || ch == mEnd && map[i + 3] > ch) { + end = mEnd - mStart + start = end - 1 + if (ch >= mEnd) { collapse = "right" } + } + if (start != null) { + node = map[i + 2] + if (mStart == mEnd && bias == (node.insertLeft ? "left" : "right")) + { collapse = bias } + if (bias == "left" && start == 0) + { while (i && map[i - 2] == map[i - 3] && map[i - 1].insertLeft) { + node = map[(i -= 3) + 2] + collapse = "left" + } } + if (bias == "right" && start == mEnd - mStart) + { while (i < map.length - 3 && map[i + 3] == map[i + 4] && !map[i + 5].insertLeft) { + node = map[(i += 3) + 2] + collapse = "right" + } } + break + } + } + return {node: node, start: start, end: end, collapse: collapse, coverStart: mStart, coverEnd: mEnd} +} + +function getUsefulRect(rects, bias) { + var rect = nullRect + if (bias == "left") { for (var i = 0; i < rects.length; i++) { + if ((rect = rects[i]).left != rect.right) { break } + } } else { for (var i$1 = rects.length - 1; i$1 >= 0; i$1--) { + if ((rect = rects[i$1]).left != rect.right) { break } + } } + return rect +} + +function measureCharInner(cm, prepared, ch, bias) { + var place = nodeAndOffsetInLineMap(prepared.map, ch, bias) + var node = place.node, start = place.start, end = place.end, collapse = place.collapse + + var rect + if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates. + for (var i$1 = 0; i$1 < 4; i$1++) { // Retry a maximum of 4 times when nonsense rectangles are returned + while (start && isExtendingChar(prepared.line.text.charAt(place.coverStart + start))) { --start } + while (place.coverStart + end < place.coverEnd && isExtendingChar(prepared.line.text.charAt(place.coverStart + end))) { ++end } + if (ie && ie_version < 9 && start == 0 && end == place.coverEnd - place.coverStart) + { rect = node.parentNode.getBoundingClientRect() } + else + { rect = getUsefulRect(range(node, start, end).getClientRects(), bias) } + if (rect.left || rect.right || start == 0) { break } + end = start + start = start - 1 + collapse = "right" + } + if (ie && ie_version < 11) { rect = maybeUpdateRectForZooming(cm.display.measure, rect) } + } else { // If it is a widget, simply get the box for the whole widget. + if (start > 0) { collapse = bias = "right" } + var rects + if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1) + { rect = rects[bias == "right" ? rects.length - 1 : 0] } + else + { rect = node.getBoundingClientRect() } + } + if (ie && ie_version < 9 && !start && (!rect || !rect.left && !rect.right)) { + var rSpan = node.parentNode.getClientRects()[0] + if (rSpan) + { rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom} } + else + { rect = nullRect } + } + + var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top + var mid = (rtop + rbot) / 2 + var heights = prepared.view.measure.heights + var i = 0 + for (; i < heights.length - 1; i++) + { if (mid < heights[i]) { break } } + var top = i ? heights[i - 1] : 0, bot = heights[i] + var result = {left: (collapse == "right" ? rect.right : rect.left) - prepared.rect.left, + right: (collapse == "left" ? rect.left : rect.right) - prepared.rect.left, + top: top, bottom: bot} + if (!rect.left && !rect.right) { result.bogus = true } + if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot } + + return result +} + +// Work around problem with bounding client rects on ranges being +// returned incorrectly when zoomed on IE10 and below. +function maybeUpdateRectForZooming(measure, rect) { + if (!window.screen || screen.logicalXDPI == null || + screen.logicalXDPI == screen.deviceXDPI || !hasBadZoomedRects(measure)) + { return rect } + var scaleX = screen.logicalXDPI / screen.deviceXDPI + var scaleY = screen.logicalYDPI / screen.deviceYDPI + return {left: rect.left * scaleX, right: rect.right * scaleX, + top: rect.top * scaleY, bottom: rect.bottom * scaleY} +} + +function clearLineMeasurementCacheFor(lineView) { + if (lineView.measure) { + lineView.measure.cache = {} + lineView.measure.heights = null + if (lineView.rest) { for (var i = 0; i < lineView.rest.length; i++) + { lineView.measure.caches[i] = {} } } + } +} + +function clearLineMeasurementCache(cm) { + cm.display.externalMeasure = null + removeChildren(cm.display.lineMeasure) + for (var i = 0; i < cm.display.view.length; i++) + { clearLineMeasurementCacheFor(cm.display.view[i]) } +} + +function clearCaches(cm) { + clearLineMeasurementCache(cm) + cm.display.cachedCharWidth = cm.display.cachedTextHeight = cm.display.cachedPaddingH = null + if (!cm.options.lineWrapping) { cm.display.maxLineChanged = true } + cm.display.lineNumChars = null +} + +function pageScrollX() { + // Work around https://bugs.chromium.org/p/chromium/issues/detail?id=489206 + // which causes page_Offset and bounding client rects to use + // different reference viewports and invalidate our calculations. + if (chrome && android) { return -(document.body.getBoundingClientRect().left - parseInt(getComputedStyle(document.body).marginLeft)) } + return window.pageXOffset || (document.documentElement || document.body).scrollLeft +} +function pageScrollY() { + if (chrome && android) { return -(document.body.getBoundingClientRect().top - parseInt(getComputedStyle(document.body).marginTop)) } + return window.pageYOffset || (document.documentElement || document.body).scrollTop +} + +function widgetTopHeight(lineObj) { + var height = 0 + if (lineObj.widgets) { for (var i = 0; i < lineObj.widgets.length; ++i) { if (lineObj.widgets[i].above) + { height += widgetHeight(lineObj.widgets[i]) } } } + return height +} + +// Converts a {top, bottom, left, right} box from line-local +// coordinates into another coordinate system. Context may be one of +// "line", "div" (display.lineDiv), "local"./null (editor), "window", +// or "page". +function intoCoordSystem(cm, lineObj, rect, context, includeWidgets) { + if (!includeWidgets) { + var height = widgetTopHeight(lineObj) + rect.top += height; rect.bottom += height + } + if (context == "line") { return rect } + if (!context) { context = "local" } + var yOff = heightAtLine(lineObj) + if (context == "local") { yOff += paddingTop(cm.display) } + else { yOff -= cm.display.viewOffset } + if (context == "page" || context == "window") { + var lOff = cm.display.lineSpace.getBoundingClientRect() + yOff += lOff.top + (context == "window" ? 0 : pageScrollY()) + var xOff = lOff.left + (context == "window" ? 0 : pageScrollX()) + rect.left += xOff; rect.right += xOff + } + rect.top += yOff; rect.bottom += yOff + return rect +} + +// Coverts a box from "div" coords to another coordinate system. +// Context may be "window", "page", "div", or "local"./null. +function fromCoordSystem(cm, coords, context) { + if (context == "div") { return coords } + var left = coords.left, top = coords.top + // First move into "page" coordinate system + if (context == "page") { + left -= pageScrollX() + top -= pageScrollY() + } else if (context == "local" || !context) { + var localBox = cm.display.sizer.getBoundingClientRect() + left += localBox.left + top += localBox.top + } + + var lineSpaceBox = cm.display.lineSpace.getBoundingClientRect() + return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top} +} + +function charCoords(cm, pos, context, lineObj, bias) { + if (!lineObj) { lineObj = getLine(cm.doc, pos.line) } + return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context) +} + +// Returns a box for a given cursor position, which may have an +// 'other' property containing the position of the secondary cursor +// on a bidi boundary. +// A cursor Pos(line, char, "before") is on the same visual line as `char - 1` +// and after `char - 1` in writing order of `char - 1` +// A cursor Pos(line, char, "after") is on the same visual line as `char` +// and before `char` in writing order of `char` +// Examples (upper-case letters are RTL, lower-case are LTR): +// Pos(0, 1, ...) +// before after +// ab a|b a|b +// aB a|B aB| +// Ab |Ab A|b +// AB B|A B|A +// Every position after the last character on a line is considered to stick +// to the last character on the line. +function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeight) { + lineObj = lineObj || getLine(cm.doc, pos.line) + if (!preparedMeasure) { preparedMeasure = prepareMeasureForLine(cm, lineObj) } + function get(ch, right) { + var m = measureCharPrepared(cm, preparedMeasure, ch, right ? "right" : "left", varHeight) + if (right) { m.left = m.right; } else { m.right = m.left } + return intoCoordSystem(cm, lineObj, m, context) + } + var order = getOrder(lineObj, cm.doc.direction), ch = pos.ch, sticky = pos.sticky + if (ch >= lineObj.text.length) { + ch = lineObj.text.length + sticky = "before" + } else if (ch <= 0) { + ch = 0 + sticky = "after" + } + if (!order) { return get(sticky == "before" ? ch - 1 : ch, sticky == "before") } + + function getBidi(ch, partPos, invert) { + var part = order[partPos], right = part.level == 1 + return get(invert ? ch - 1 : ch, right != invert) + } + var partPos = getBidiPartAt(order, ch, sticky) + var other = bidiOther + var val = getBidi(ch, partPos, sticky == "before") + if (other != null) { val.other = getBidi(ch, other, sticky != "before") } + return val +} + +// Used to cheaply estimate the coordinates for a position. Used for +// intermediate scroll updates. +function estimateCoords(cm, pos) { + var left = 0 + pos = clipPos(cm.doc, pos) + if (!cm.options.lineWrapping) { left = charWidth(cm.display) * pos.ch } + var lineObj = getLine(cm.doc, pos.line) + var top = heightAtLine(lineObj) + paddingTop(cm.display) + return {left: left, right: left, top: top, bottom: top + lineObj.height} +} + +// Positions returned by coordsChar contain some extra information. +// xRel is the relative x position of the input coordinates compared +// to the found position (so xRel > 0 means the coordinates are to +// the right of the character position, for example). When outside +// is true, that means the coordinates lie outside the line's +// vertical range. +function PosWithInfo(line, ch, sticky, outside, xRel) { + var pos = Pos(line, ch, sticky) + pos.xRel = xRel + if (outside) { pos.outside = true } + return pos +} + +// Compute the character position closest to the given coordinates. +// Input must be lineSpace-local ("div" coordinate system). +function coordsChar(cm, x, y) { + var doc = cm.doc + y += cm.display.viewOffset + if (y < 0) { return PosWithInfo(doc.first, 0, null, true, -1) } + var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1 + if (lineN > last) + { return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, null, true, 1) } + if (x < 0) { x = 0 } + + var lineObj = getLine(doc, lineN) + for (;;) { + var found = coordsCharInner(cm, lineObj, lineN, x, y) + var collapsed = collapsedSpanAround(lineObj, found.ch + (found.xRel > 0 ? 1 : 0)) + if (!collapsed) { return found } + var rangeEnd = collapsed.find(1) + if (rangeEnd.line == lineN) { return rangeEnd } + lineObj = getLine(doc, lineN = rangeEnd.line) + } +} + +function wrappedLineExtent(cm, lineObj, preparedMeasure, y) { + y -= widgetTopHeight(lineObj) + var end = lineObj.text.length + var begin = findFirst(function (ch) { return measureCharPrepared(cm, preparedMeasure, ch - 1).bottom <= y; }, end, 0) + end = findFirst(function (ch) { return measureCharPrepared(cm, preparedMeasure, ch).top > y; }, begin, end) + return {begin: begin, end: end} +} + +function wrappedLineExtentChar(cm, lineObj, preparedMeasure, target) { + if (!preparedMeasure) { preparedMeasure = prepareMeasureForLine(cm, lineObj) } + var targetTop = intoCoordSystem(cm, lineObj, measureCharPrepared(cm, preparedMeasure, target), "line").top + return wrappedLineExtent(cm, lineObj, preparedMeasure, targetTop) +} + +// Returns true if the given side of a box is after the given +// coordinates, in top-to-bottom, left-to-right order. +function boxIsAfter(box, x, y, left) { + return box.bottom <= y ? false : box.top > y ? true : (left ? box.left : box.right) > x +} + +function coordsCharInner(cm, lineObj, lineNo, x, y) { + // Move y into line-local coordinate space + y -= heightAtLine(lineObj) + var preparedMeasure = prepareMeasureForLine(cm, lineObj) + // When directly calling `measureCharPrepared`, we have to adjust + // for the widgets at this line. + var widgetHeight = widgetTopHeight(lineObj) + var begin = 0, end = lineObj.text.length, ltr = true + + var order = getOrder(lineObj, cm.doc.direction) + // If the line isn't plain left-to-right text, first figure out + // which bidi section the coordinates fall into. + if (order) { + var part = (cm.options.lineWrapping ? coordsBidiPartWrapped : coordsBidiPart) + (cm, lineObj, lineNo, preparedMeasure, order, x, y) + ltr = part.level != 1 + // The awkward -1 offsets are needed because findFirst (called + // on these below) will treat its first bound as inclusive, + // second as exclusive, but we want to actually address the + // characters in the part's range + begin = ltr ? part.from : part.to - 1 + end = ltr ? part.to : part.from - 1 + } + + // A binary search to find the first character whose bounding box + // starts after the coordinates. If we run across any whose box wrap + // the coordinates, store that. + var chAround = null, boxAround = null + var ch = findFirst(function (ch) { + var box = measureCharPrepared(cm, preparedMeasure, ch) + box.top += widgetHeight; box.bottom += widgetHeight + if (!boxIsAfter(box, x, y, false)) { return false } + if (box.top <= y && box.left <= x) { + chAround = ch + boxAround = box + } + return true + }, begin, end) + + var baseX, sticky, outside = false + // If a box around the coordinates was found, use that + if (boxAround) { + // Distinguish coordinates nearer to the left or right side of the box + var atLeft = x - boxAround.left < boxAround.right - x, atStart = atLeft == ltr + ch = chAround + (atStart ? 0 : 1) + sticky = atStart ? "after" : "before" + baseX = atLeft ? boxAround.left : boxAround.right + } else { + // (Adjust for extended bound, if necessary.) + if (!ltr && (ch == end || ch == begin)) { ch++ } + // To determine which side to associate with, get the box to the + // left of the character and compare it's vertical position to the + // coordinates + sticky = ch == 0 ? "after" : ch == lineObj.text.length ? "before" : + (measureCharPrepared(cm, preparedMeasure, ch - (ltr ? 1 : 0)).bottom + widgetHeight <= y) == ltr ? + "after" : "before" + // Now get accurate coordinates for this place, in order to get a + // base X position + var coords = cursorCoords(cm, Pos(lineNo, ch, sticky), "line", lineObj, preparedMeasure) + baseX = coords.left + outside = y < coords.top || y >= coords.bottom + } + + ch = skipExtendingChars(lineObj.text, ch, 1) + return PosWithInfo(lineNo, ch, sticky, outside, x - baseX) +} + +function coordsBidiPart(cm, lineObj, lineNo, preparedMeasure, order, x, y) { + // Bidi parts are sorted left-to-right, and in a non-line-wrapping + // situation, we can take this ordering to correspond to the visual + // ordering. This finds the first part whose end is after the given + // coordinates. + var index = findFirst(function (i) { + var part = order[i], ltr = part.level != 1 + return boxIsAfter(cursorCoords(cm, Pos(lineNo, ltr ? part.to : part.from, ltr ? "before" : "after"), + "line", lineObj, preparedMeasure), x, y, true) + }, 0, order.length - 1) + var part = order[index] + // If this isn't the first part, the part's start is also after + // the coordinates, and the coordinates aren't on the same line as + // that start, move one part back. + if (index > 0) { + var ltr = part.level != 1 + var start = cursorCoords(cm, Pos(lineNo, ltr ? part.from : part.to, ltr ? "after" : "before"), + "line", lineObj, preparedMeasure) + if (boxIsAfter(start, x, y, true) && start.top > y) + { part = order[index - 1] } + } + return part +} + +function coordsBidiPartWrapped(cm, lineObj, _lineNo, preparedMeasure, order, x, y) { + // In a wrapped line, rtl text on wrapping boundaries can do things + // that don't correspond to the ordering in our `order` array at + // all, so a binary search doesn't work, and we want to return a + // part that only spans one line so that the binary search in + // coordsCharInner is safe. As such, we first find the extent of the + // wrapped line, and then do a flat search in which we discard any + // spans that aren't on the line. + var ref = wrappedLineExtent(cm, lineObj, preparedMeasure, y); + var begin = ref.begin; + var end = ref.end; + if (/\s/.test(lineObj.text.charAt(end - 1))) { end-- } + var part = null, closestDist = null + for (var i = 0; i < order.length; i++) { + var p = order[i] + if (p.from >= end || p.to <= begin) { continue } + var ltr = p.level != 1 + var endX = measureCharPrepared(cm, preparedMeasure, ltr ? Math.min(end, p.to) - 1 : Math.max(begin, p.from)).right + // Weigh against spans ending before this, so that they are only + // picked if nothing ends after + var dist = endX < x ? x - endX + 1e9 : endX - x + if (!part || closestDist > dist) { + part = p + closestDist = dist + } + } + if (!part) { part = order[order.length - 1] } + // Clip the part to the wrapped line. + if (part.from < begin) { part = {from: begin, to: part.to, level: part.level} } + if (part.to > end) { part = {from: part.from, to: end, level: part.level} } + return part +} + +var measureText +// Compute the default text height. +function textHeight(display) { + if (display.cachedTextHeight != null) { return display.cachedTextHeight } + if (measureText == null) { + measureText = elt("pre") + // Measure a bunch of lines, for browsers that compute + // fractional heights. + for (var i = 0; i < 49; ++i) { + measureText.appendChild(document.createTextNode("x")) + measureText.appendChild(elt("br")) + } + measureText.appendChild(document.createTextNode("x")) + } + removeChildrenAndAdd(display.measure, measureText) + var height = measureText.offsetHeight / 50 + if (height > 3) { display.cachedTextHeight = height } + removeChildren(display.measure) + return height || 1 +} + +// Compute the default character width. +function charWidth(display) { + if (display.cachedCharWidth != null) { return display.cachedCharWidth } + var anchor = elt("span", "xxxxxxxxxx") + var pre = elt("pre", [anchor]) + removeChildrenAndAdd(display.measure, pre) + var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10 + if (width > 2) { display.cachedCharWidth = width } + return width || 10 +} + +// Do a bulk-read of the DOM positions and sizes needed to draw the +// view, so that we don't interleave reading and writing to the DOM. +function getDimensions(cm) { + var d = cm.display, left = {}, width = {} + var gutterLeft = d.gutters.clientLeft + for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) { + left[cm.options.gutters[i]] = n.offsetLeft + n.clientLeft + gutterLeft + width[cm.options.gutters[i]] = n.clientWidth + } + return {fixedPos: compensateForHScroll(d), + gutterTotalWidth: d.gutters.offsetWidth, + gutterLeft: left, + gutterWidth: width, + wrapperWidth: d.wrapper.clientWidth} +} + +// Computes display.scroller.scrollLeft + display.gutters.offsetWidth, +// but using getBoundingClientRect to get a sub-pixel-accurate +// result. +function compensateForHScroll(display) { + return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left +} + +// Returns a function that estimates the height of a line, to use as +// first approximation until the line becomes visible (and is thus +// properly measurable). +function estimateHeight(cm) { + var th = textHeight(cm.display), wrapping = cm.options.lineWrapping + var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3) + return function (line) { + if (lineIsHidden(cm.doc, line)) { return 0 } + + var widgetsHeight = 0 + if (line.widgets) { for (var i = 0; i < line.widgets.length; i++) { + if (line.widgets[i].height) { widgetsHeight += line.widgets[i].height } + } } + + if (wrapping) + { return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * th } + else + { return widgetsHeight + th } + } +} + +function estimateLineHeights(cm) { + var doc = cm.doc, est = estimateHeight(cm) + doc.iter(function (line) { + var estHeight = est(line) + if (estHeight != line.height) { updateLineHeight(line, estHeight) } + }) +} + +// Given a mouse event, find the corresponding position. If liberal +// is false, it checks whether a gutter or scrollbar was clicked, +// and returns null if it was. forRect is used by rectangular +// selections, and tries to estimate a character position even for +// coordinates beyond the right of the text. +function posFromMouse(cm, e, liberal, forRect) { + var display = cm.display + if (!liberal && e_target(e).getAttribute("cm-not-content") == "true") { return null } + + var x, y, space = display.lineSpace.getBoundingClientRect() + // Fails unpredictably on IE[67] when mouse is dragged around quickly. + try { x = e.clientX - space.left; y = e.clientY - space.top } + catch (e) { return null } + var coords = coordsChar(cm, x, y), line + if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) { + var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length + coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff)) + } + return coords +} + +// Find the view element corresponding to a given line. Return null +// when the line isn't visible. +function findViewIndex(cm, n) { + if (n >= cm.display.viewTo) { return null } + n -= cm.display.viewFrom + if (n < 0) { return null } + var view = cm.display.view + for (var i = 0; i < view.length; i++) { + n -= view[i].size + if (n < 0) { return i } + } +} + +function updateSelection(cm) { + cm.display.input.showSelection(cm.display.input.prepareSelection()) +} + +function prepareSelection(cm, primary) { + if ( primary === void 0 ) primary = true; + + var doc = cm.doc, result = {} + var curFragment = result.cursors = document.createDocumentFragment() + var selFragment = result.selection = document.createDocumentFragment() + + for (var i = 0; i < doc.sel.ranges.length; i++) { + if (!primary && i == doc.sel.primIndex) { continue } + var range = doc.sel.ranges[i] + if (range.from().line >= cm.display.viewTo || range.to().line < cm.display.viewFrom) { continue } + var collapsed = range.empty() + if (collapsed || cm.options.showCursorWhenSelecting) + { drawSelectionCursor(cm, range.head, curFragment) } + if (!collapsed) + { drawSelectionRange(cm, range, selFragment) } + } + return result +} + +// Draws a cursor for the given range +function drawSelectionCursor(cm, head, output) { + var pos = cursorCoords(cm, head, "div", null, null, !cm.options.singleCursorHeightPerLine) + + var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor")) + cursor.style.left = pos.left + "px" + cursor.style.top = pos.top + "px" + cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px" + + if (pos.other) { + // Secondary cursor, shown when on a 'jump' in bi-directional text + var otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor")) + otherCursor.style.display = "" + otherCursor.style.left = pos.other.left + "px" + otherCursor.style.top = pos.other.top + "px" + otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + "px" + } +} + +function cmpCoords(a, b) { return a.top - b.top || a.left - b.left } + +// Draws the given range as a highlighted selection +function drawSelectionRange(cm, range, output) { + var display = cm.display, doc = cm.doc + var fragment = document.createDocumentFragment() + var padding = paddingH(cm.display), leftSide = padding.left + var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right + var docLTR = doc.direction == "ltr" + + function add(left, top, width, bottom) { + if (top < 0) { top = 0 } + top = Math.round(top) + bottom = Math.round(bottom) + fragment.appendChild(elt("div", null, "CodeMirror-selected", ("position: absolute; left: " + left + "px;\n top: " + top + "px; width: " + (width == null ? rightSide - left : width) + "px;\n height: " + (bottom - top) + "px"))) + } + + function drawForLine(line, fromArg, toArg) { + var lineObj = getLine(doc, line) + var lineLen = lineObj.text.length + var start, end + function coords(ch, bias) { + return charCoords(cm, Pos(line, ch), "div", lineObj, bias) + } + + function wrapX(pos, dir, side) { + var extent = wrappedLineExtentChar(cm, lineObj, null, pos) + var prop = (dir == "ltr") == (side == "after") ? "left" : "right" + var ch = side == "after" ? extent.begin : extent.end - (/\s/.test(lineObj.text.charAt(extent.end - 1)) ? 2 : 1) + return coords(ch, prop)[prop] + } + + var order = getOrder(lineObj, doc.direction) + iterateBidiSections(order, fromArg || 0, toArg == null ? lineLen : toArg, function (from, to, dir, i) { + var ltr = dir == "ltr" + var fromPos = coords(from, ltr ? "left" : "right") + var toPos = coords(to - 1, ltr ? "right" : "left") + + var openStart = fromArg == null && from == 0, openEnd = toArg == null && to == lineLen + var first = i == 0, last = !order || i == order.length - 1 + if (toPos.top - fromPos.top <= 3) { // Single line + var openLeft = (docLTR ? openStart : openEnd) && first + var openRight = (docLTR ? openEnd : openStart) && last + var left = openLeft ? leftSide : (ltr ? fromPos : toPos).left + var right = openRight ? rightSide : (ltr ? toPos : fromPos).right + add(left, fromPos.top, right - left, fromPos.bottom) + } else { // Multiple lines + var topLeft, topRight, botLeft, botRight + if (ltr) { + topLeft = docLTR && openStart && first ? leftSide : fromPos.left + topRight = docLTR ? rightSide : wrapX(from, dir, "before") + botLeft = docLTR ? leftSide : wrapX(to, dir, "after") + botRight = docLTR && openEnd && last ? rightSide : toPos.right + } else { + topLeft = !docLTR ? leftSide : wrapX(from, dir, "before") + topRight = !docLTR && openStart && first ? rightSide : fromPos.right + botLeft = !docLTR && openEnd && last ? leftSide : toPos.left + botRight = !docLTR ? rightSide : wrapX(to, dir, "after") + } + add(topLeft, fromPos.top, topRight - topLeft, fromPos.bottom) + if (fromPos.bottom < toPos.top) { add(leftSide, fromPos.bottom, null, toPos.top) } + add(botLeft, toPos.top, botRight - botLeft, toPos.bottom) + } + + if (!start || cmpCoords(fromPos, start) < 0) { start = fromPos } + if (cmpCoords(toPos, start) < 0) { start = toPos } + if (!end || cmpCoords(fromPos, end) < 0) { end = fromPos } + if (cmpCoords(toPos, end) < 0) { end = toPos } + }) + return {start: start, end: end} + } + + var sFrom = range.from(), sTo = range.to() + if (sFrom.line == sTo.line) { + drawForLine(sFrom.line, sFrom.ch, sTo.ch) + } else { + var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line) + var singleVLine = visualLine(fromLine) == visualLine(toLine) + var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end + var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start + if (singleVLine) { + if (leftEnd.top < rightStart.top - 2) { + add(leftEnd.right, leftEnd.top, null, leftEnd.bottom) + add(leftSide, rightStart.top, rightStart.left, rightStart.bottom) + } else { + add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom) + } + } + if (leftEnd.bottom < rightStart.top) + { add(leftSide, leftEnd.bottom, null, rightStart.top) } + } + + output.appendChild(fragment) +} + +// Cursor-blinking +function restartBlink(cm) { + if (!cm.state.focused) { return } + var display = cm.display + clearInterval(display.blinker) + var on = true + display.cursorDiv.style.visibility = "" + if (cm.options.cursorBlinkRate > 0) + { display.blinker = setInterval(function () { return display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden"; }, + cm.options.cursorBlinkRate) } + else if (cm.options.cursorBlinkRate < 0) + { display.cursorDiv.style.visibility = "hidden" } +} + +function ensureFocus(cm) { + if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm) } +} + +function delayBlurEvent(cm) { + cm.state.delayingBlurEvent = true + setTimeout(function () { if (cm.state.delayingBlurEvent) { + cm.state.delayingBlurEvent = false + onBlur(cm) + } }, 100) +} + +function onFocus(cm, e) { + if (cm.state.delayingBlurEvent) { cm.state.delayingBlurEvent = false } + + if (cm.options.readOnly == "nocursor") { return } + if (!cm.state.focused) { + signal(cm, "focus", cm, e) + cm.state.focused = true + addClass(cm.display.wrapper, "CodeMirror-focused") + // This test prevents this from firing when a context + // menu is closed (since the input reset would kill the + // select-all detection hack) + if (!cm.curOp && cm.display.selForContextMenu != cm.doc.sel) { + cm.display.input.reset() + if (webkit) { setTimeout(function () { return cm.display.input.reset(true); }, 20) } // Issue #1730 + } + cm.display.input.receivedFocus() + } + restartBlink(cm) +} +function onBlur(cm, e) { + if (cm.state.delayingBlurEvent) { return } + + if (cm.state.focused) { + signal(cm, "blur", cm, e) + cm.state.focused = false + rmClass(cm.display.wrapper, "CodeMirror-focused") + } + clearInterval(cm.display.blinker) + setTimeout(function () { if (!cm.state.focused) { cm.display.shift = false } }, 150) +} + +// Read the actual heights of the rendered lines, and update their +// stored heights to match. +function updateHeightsInViewport(cm) { + var display = cm.display + var prevBottom = display.lineDiv.offsetTop + for (var i = 0; i < display.view.length; i++) { + var cur = display.view[i], height = (void 0) + if (cur.hidden) { continue } + if (ie && ie_version < 8) { + var bot = cur.node.offsetTop + cur.node.offsetHeight + height = bot - prevBottom + prevBottom = bot + } else { + var box = cur.node.getBoundingClientRect() + height = box.bottom - box.top + } + var diff = cur.line.height - height + if (height < 2) { height = textHeight(display) } + if (diff > .005 || diff < -.005) { + updateLineHeight(cur.line, height) + updateWidgetHeight(cur.line) + if (cur.rest) { for (var j = 0; j < cur.rest.length; j++) + { updateWidgetHeight(cur.rest[j]) } } + } + } +} + +// Read and store the height of line widgets associated with the +// given line. +function updateWidgetHeight(line) { + if (line.widgets) { for (var i = 0; i < line.widgets.length; ++i) { + var w = line.widgets[i], parent = w.node.parentNode + if (parent) { w.height = parent.offsetHeight } + } } +} + +// Compute the lines that are visible in a given viewport (defaults +// the the current scroll position). viewport may contain top, +// height, and ensure (see op.scrollToPos) properties. +function visibleLines(display, doc, viewport) { + var top = viewport && viewport.top != null ? Math.max(0, viewport.top) : display.scroller.scrollTop + top = Math.floor(top - paddingTop(display)) + var bottom = viewport && viewport.bottom != null ? viewport.bottom : top + display.wrapper.clientHeight + + var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom) + // Ensure is a {from: {line, ch}, to: {line, ch}} object, and + // forces those lines into the viewport (if possible). + if (viewport && viewport.ensure) { + var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line + if (ensureFrom < from) { + from = ensureFrom + to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight) + } else if (Math.min(ensureTo, doc.lastLine()) >= to) { + from = lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight) + to = ensureTo + } + } + return {from: from, to: Math.max(to, from + 1)} +} + +// Re-align line numbers and gutter marks to compensate for +// horizontal scrolling. +function alignHorizontally(cm) { + var display = cm.display, view = display.view + if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) { return } + var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft + var gutterW = display.gutters.offsetWidth, left = comp + "px" + for (var i = 0; i < view.length; i++) { if (!view[i].hidden) { + if (cm.options.fixedGutter) { + if (view[i].gutter) + { view[i].gutter.style.left = left } + if (view[i].gutterBackground) + { view[i].gutterBackground.style.left = left } + } + var align = view[i].alignable + if (align) { for (var j = 0; j < align.length; j++) + { align[j].style.left = left } } + } } + if (cm.options.fixedGutter) + { display.gutters.style.left = (comp + gutterW) + "px" } +} + +// Used to ensure that the line number gutter is still the right +// size for the current document size. Returns true when an update +// is needed. +function maybeUpdateLineNumberWidth(cm) { + if (!cm.options.lineNumbers) { return false } + var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display + if (last.length != display.lineNumChars) { + var test = display.measure.appendChild(elt("div", [elt("div", last)], + "CodeMirror-linenumber CodeMirror-gutter-elt")) + var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW + display.lineGutter.style.width = "" + display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding) + 1 + display.lineNumWidth = display.lineNumInnerWidth + padding + display.lineNumChars = display.lineNumInnerWidth ? last.length : -1 + display.lineGutter.style.width = display.lineNumWidth + "px" + updateGutterSpace(cm) + return true + } + return false +} + +// SCROLLING THINGS INTO VIEW + +// If an editor sits on the top or bottom of the window, partially +// scrolled out of view, this ensures that the cursor is visible. +function maybeScrollWindow(cm, rect) { + if (signalDOMEvent(cm, "scrollCursorIntoView")) { return } + + var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null + if (rect.top + box.top < 0) { doScroll = true } + else if (rect.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) { doScroll = false } + if (doScroll != null && !phantom) { + var scrollNode = elt("div", "\u200b", null, ("position: absolute;\n top: " + (rect.top - display.viewOffset - paddingTop(cm.display)) + "px;\n height: " + (rect.bottom - rect.top + scrollGap(cm) + display.barHeight) + "px;\n left: " + (rect.left) + "px; width: " + (Math.max(2, rect.right - rect.left)) + "px;")) + cm.display.lineSpace.appendChild(scrollNode) + scrollNode.scrollIntoView(doScroll) + cm.display.lineSpace.removeChild(scrollNode) + } +} + +// Scroll a given position into view (immediately), verifying that +// it actually became visible (as line heights are accurately +// measured, the position of something may 'drift' during drawing). +function scrollPosIntoView(cm, pos, end, margin) { + if (margin == null) { margin = 0 } + var rect + if (!cm.options.lineWrapping && pos == end) { + // Set pos and end to the cursor positions around the character pos sticks to + // If pos.sticky == "before", that is around pos.ch - 1, otherwise around pos.ch + // If pos == Pos(_, 0, "before"), pos and end are unchanged + pos = pos.ch ? Pos(pos.line, pos.sticky == "before" ? pos.ch - 1 : pos.ch, "after") : pos + end = pos.sticky == "before" ? Pos(pos.line, pos.ch + 1, "before") : pos + } + for (var limit = 0; limit < 5; limit++) { + var changed = false + var coords = cursorCoords(cm, pos) + var endCoords = !end || end == pos ? coords : cursorCoords(cm, end) + rect = {left: Math.min(coords.left, endCoords.left), + top: Math.min(coords.top, endCoords.top) - margin, + right: Math.max(coords.left, endCoords.left), + bottom: Math.max(coords.bottom, endCoords.bottom) + margin} + var scrollPos = calculateScrollPos(cm, rect) + var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft + if (scrollPos.scrollTop != null) { + updateScrollTop(cm, scrollPos.scrollTop) + if (Math.abs(cm.doc.scrollTop - startTop) > 1) { changed = true } + } + if (scrollPos.scrollLeft != null) { + setScrollLeft(cm, scrollPos.scrollLeft) + if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) { changed = true } + } + if (!changed) { break } + } + return rect +} + +// Scroll a given set of coordinates into view (immediately). +function scrollIntoView(cm, rect) { + var scrollPos = calculateScrollPos(cm, rect) + if (scrollPos.scrollTop != null) { updateScrollTop(cm, scrollPos.scrollTop) } + if (scrollPos.scrollLeft != null) { setScrollLeft(cm, scrollPos.scrollLeft) } +} + +// Calculate a new scroll position needed to scroll the given +// rectangle into view. Returns an object with scrollTop and +// scrollLeft properties. When these are undefined, the +// vertical/horizontal position does not need to be adjusted. +function calculateScrollPos(cm, rect) { + var display = cm.display, snapMargin = textHeight(cm.display) + if (rect.top < 0) { rect.top = 0 } + var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop + var screen = displayHeight(cm), result = {} + if (rect.bottom - rect.top > screen) { rect.bottom = rect.top + screen } + var docBottom = cm.doc.height + paddingVert(display) + var atTop = rect.top < snapMargin, atBottom = rect.bottom > docBottom - snapMargin + if (rect.top < screentop) { + result.scrollTop = atTop ? 0 : rect.top + } else if (rect.bottom > screentop + screen) { + var newTop = Math.min(rect.top, (atBottom ? docBottom : rect.bottom) - screen) + if (newTop != screentop) { result.scrollTop = newTop } + } + + var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft + var screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0) + var tooWide = rect.right - rect.left > screenw + if (tooWide) { rect.right = rect.left + screenw } + if (rect.left < 10) + { result.scrollLeft = 0 } + else if (rect.left < screenleft) + { result.scrollLeft = Math.max(0, rect.left - (tooWide ? 0 : 10)) } + else if (rect.right > screenw + screenleft - 3) + { result.scrollLeft = rect.right + (tooWide ? 0 : 10) - screenw } + return result +} + +// Store a relative adjustment to the scroll position in the current +// operation (to be applied when the operation finishes). +function addToScrollTop(cm, top) { + if (top == null) { return } + resolveScrollToPos(cm) + cm.curOp.scrollTop = (cm.curOp.scrollTop == null ? cm.doc.scrollTop : cm.curOp.scrollTop) + top +} + +// Make sure that at the end of the operation the current cursor is +// shown. +function ensureCursorVisible(cm) { + resolveScrollToPos(cm) + var cur = cm.getCursor() + cm.curOp.scrollToPos = {from: cur, to: cur, margin: cm.options.cursorScrollMargin} +} + +function scrollToCoords(cm, x, y) { + if (x != null || y != null) { resolveScrollToPos(cm) } + if (x != null) { cm.curOp.scrollLeft = x } + if (y != null) { cm.curOp.scrollTop = y } +} + +function scrollToRange(cm, range) { + resolveScrollToPos(cm) + cm.curOp.scrollToPos = range +} + +// When an operation has its scrollToPos property set, and another +// scroll action is applied before the end of the operation, this +// 'simulates' scrolling that position into view in a cheap way, so +// that the effect of intermediate scroll commands is not ignored. +function resolveScrollToPos(cm) { + var range = cm.curOp.scrollToPos + if (range) { + cm.curOp.scrollToPos = null + var from = estimateCoords(cm, range.from), to = estimateCoords(cm, range.to) + scrollToCoordsRange(cm, from, to, range.margin) + } +} + +function scrollToCoordsRange(cm, from, to, margin) { + var sPos = calculateScrollPos(cm, { + left: Math.min(from.left, to.left), + top: Math.min(from.top, to.top) - margin, + right: Math.max(from.right, to.right), + bottom: Math.max(from.bottom, to.bottom) + margin + }) + scrollToCoords(cm, sPos.scrollLeft, sPos.scrollTop) +} + +// Sync the scrollable area and scrollbars, ensure the viewport +// covers the visible area. +function updateScrollTop(cm, val) { + if (Math.abs(cm.doc.scrollTop - val) < 2) { return } + if (!gecko) { updateDisplaySimple(cm, {top: val}) } + setScrollTop(cm, val, true) + if (gecko) { updateDisplaySimple(cm) } + startWorker(cm, 100) +} + +function setScrollTop(cm, val, forceScroll) { + val = Math.min(cm.display.scroller.scrollHeight - cm.display.scroller.clientHeight, val) + if (cm.display.scroller.scrollTop == val && !forceScroll) { return } + cm.doc.scrollTop = val + cm.display.scrollbars.setScrollTop(val) + if (cm.display.scroller.scrollTop != val) { cm.display.scroller.scrollTop = val } +} + +// Sync scroller and scrollbar, ensure the gutter elements are +// aligned. +function setScrollLeft(cm, val, isScroller, forceScroll) { + val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth) + if ((isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) && !forceScroll) { return } + cm.doc.scrollLeft = val + alignHorizontally(cm) + if (cm.display.scroller.scrollLeft != val) { cm.display.scroller.scrollLeft = val } + cm.display.scrollbars.setScrollLeft(val) +} + +// SCROLLBARS + +// Prepare DOM reads needed to update the scrollbars. Done in one +// shot to minimize update/measure roundtrips. +function measureForScrollbars(cm) { + var d = cm.display, gutterW = d.gutters.offsetWidth + var docH = Math.round(cm.doc.height + paddingVert(cm.display)) + return { + clientHeight: d.scroller.clientHeight, + viewHeight: d.wrapper.clientHeight, + scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth, + viewWidth: d.wrapper.clientWidth, + barLeft: cm.options.fixedGutter ? gutterW : 0, + docHeight: docH, + scrollHeight: docH + scrollGap(cm) + d.barHeight, + nativeBarWidth: d.nativeBarWidth, + gutterWidth: gutterW + } +} + +var NativeScrollbars = function(place, scroll, cm) { + this.cm = cm + var vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar") + var horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar") + vert.tabIndex = horiz.tabIndex = -1 + place(vert); place(horiz) + + on(vert, "scroll", function () { + if (vert.clientHeight) { scroll(vert.scrollTop, "vertical") } + }) + on(horiz, "scroll", function () { + if (horiz.clientWidth) { scroll(horiz.scrollLeft, "horizontal") } + }) + + this.checkedZeroWidth = false + // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8). + if (ie && ie_version < 8) { this.horiz.style.minHeight = this.vert.style.minWidth = "18px" } +}; + +NativeScrollbars.prototype.update = function (measure) { + var needsH = measure.scrollWidth > measure.clientWidth + 1 + var needsV = measure.scrollHeight > measure.clientHeight + 1 + var sWidth = measure.nativeBarWidth + + if (needsV) { + this.vert.style.display = "block" + this.vert.style.bottom = needsH ? sWidth + "px" : "0" + var totalHeight = measure.viewHeight - (needsH ? sWidth : 0) + // A bug in IE8 can cause this value to be negative, so guard it. + this.vert.firstChild.style.height = + Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + "px" + } else { + this.vert.style.display = "" + this.vert.firstChild.style.height = "0" + } + + if (needsH) { + this.horiz.style.display = "block" + this.horiz.style.right = needsV ? sWidth + "px" : "0" + this.horiz.style.left = measure.barLeft + "px" + var totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0) + this.horiz.firstChild.style.width = + Math.max(0, measure.scrollWidth - measure.clientWidth + totalWidth) + "px" + } else { + this.horiz.style.display = "" + this.horiz.firstChild.style.width = "0" + } + + if (!this.checkedZeroWidth && measure.clientHeight > 0) { + if (sWidth == 0) { this.zeroWidthHack() } + this.checkedZeroWidth = true + } + + return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0} +}; + +NativeScrollbars.prototype.setScrollLeft = function (pos) { + if (this.horiz.scrollLeft != pos) { this.horiz.scrollLeft = pos } + if (this.disableHoriz) { this.enableZeroWidthBar(this.horiz, this.disableHoriz, "horiz") } +}; + +NativeScrollbars.prototype.setScrollTop = function (pos) { + if (this.vert.scrollTop != pos) { this.vert.scrollTop = pos } + if (this.disableVert) { this.enableZeroWidthBar(this.vert, this.disableVert, "vert") } +}; + +NativeScrollbars.prototype.zeroWidthHack = function () { + var w = mac && !mac_geMountainLion ? "12px" : "18px" + this.horiz.style.height = this.vert.style.width = w + this.horiz.style.pointerEvents = this.vert.style.pointerEvents = "none" + this.disableHoriz = new Delayed + this.disableVert = new Delayed +}; + +NativeScrollbars.prototype.enableZeroWidthBar = function (bar, delay, type) { + bar.style.pointerEvents = "auto" + function maybeDisable() { + // To find out whether the scrollbar is still visible, we + // check whether the element under the pixel in the bottom + // right corner of the scrollbar box is the scrollbar box + // itself (when the bar is still visible) or its filler child + // (when the bar is hidden). If it is still visible, we keep + // it enabled, if it's hidden, we disable pointer events. + var box = bar.getBoundingClientRect() + var elt = type == "vert" ? document.elementFromPoint(box.right - 1, (box.top + box.bottom) / 2) + : document.elementFromPoint((box.right + box.left) / 2, box.bottom - 1) + if (elt != bar) { bar.style.pointerEvents = "none" } + else { delay.set(1000, maybeDisable) } + } + delay.set(1000, maybeDisable) +}; + +NativeScrollbars.prototype.clear = function () { + var parent = this.horiz.parentNode + parent.removeChild(this.horiz) + parent.removeChild(this.vert) +}; + +var NullScrollbars = function () {}; + +NullScrollbars.prototype.update = function () { return {bottom: 0, right: 0} }; +NullScrollbars.prototype.setScrollLeft = function () {}; +NullScrollbars.prototype.setScrollTop = function () {}; +NullScrollbars.prototype.clear = function () {}; + +function updateScrollbars(cm, measure) { + if (!measure) { measure = measureForScrollbars(cm) } + var startWidth = cm.display.barWidth, startHeight = cm.display.barHeight + updateScrollbarsInner(cm, measure) + for (var i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) { + if (startWidth != cm.display.barWidth && cm.options.lineWrapping) + { updateHeightsInViewport(cm) } + updateScrollbarsInner(cm, measureForScrollbars(cm)) + startWidth = cm.display.barWidth; startHeight = cm.display.barHeight + } +} + +// Re-synchronize the fake scrollbars with the actual size of the +// content. +function updateScrollbarsInner(cm, measure) { + var d = cm.display + var sizes = d.scrollbars.update(measure) + + d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px" + d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px" + d.heightForcer.style.borderBottom = sizes.bottom + "px solid transparent" + + if (sizes.right && sizes.bottom) { + d.scrollbarFiller.style.display = "block" + d.scrollbarFiller.style.height = sizes.bottom + "px" + d.scrollbarFiller.style.width = sizes.right + "px" + } else { d.scrollbarFiller.style.display = "" } + if (sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) { + d.gutterFiller.style.display = "block" + d.gutterFiller.style.height = sizes.bottom + "px" + d.gutterFiller.style.width = measure.gutterWidth + "px" + } else { d.gutterFiller.style.display = "" } +} + +var scrollbarModel = {"native": NativeScrollbars, "null": NullScrollbars} + +function initScrollbars(cm) { + if (cm.display.scrollbars) { + cm.display.scrollbars.clear() + if (cm.display.scrollbars.addClass) + { rmClass(cm.display.wrapper, cm.display.scrollbars.addClass) } + } + + cm.display.scrollbars = new scrollbarModel[cm.options.scrollbarStyle](function (node) { + cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller) + // Prevent clicks in the scrollbars from killing focus + on(node, "mousedown", function () { + if (cm.state.focused) { setTimeout(function () { return cm.display.input.focus(); }, 0) } + }) + node.setAttribute("cm-not-content", "true") + }, function (pos, axis) { + if (axis == "horizontal") { setScrollLeft(cm, pos) } + else { updateScrollTop(cm, pos) } + }, cm) + if (cm.display.scrollbars.addClass) + { addClass(cm.display.wrapper, cm.display.scrollbars.addClass) } +} + +// Operations are used to wrap a series of changes to the editor +// state in such a way that each change won't have to update the +// cursor and display (which would be awkward, slow, and +// error-prone). Instead, display updates are batched and then all +// combined and executed at once. + +var nextOpId = 0 +// Start a new operation. +function startOperation(cm) { + cm.curOp = { + cm: cm, + viewChanged: false, // Flag that indicates that lines might need to be redrawn + startHeight: cm.doc.height, // Used to detect need to update scrollbar + forceUpdate: false, // Used to force a redraw + updateInput: null, // Whether to reset the input textarea + typing: false, // Whether this reset should be careful to leave existing text (for compositing) + changeObjs: null, // Accumulated changes, for firing change events + cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on + cursorActivityCalled: 0, // Tracks which cursorActivity handlers have been called already + selectionChanged: false, // Whether the selection needs to be redrawn + updateMaxLine: false, // Set when the widest line needs to be determined anew + scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet + scrollToPos: null, // Used to scroll to a specific position + focus: false, + id: ++nextOpId // Unique ID + } + pushOperation(cm.curOp) +} + +// Finish an operation, updating the display and signalling delayed events +function endOperation(cm) { + var op = cm.curOp + finishOperation(op, function (group) { + for (var i = 0; i < group.ops.length; i++) + { group.ops[i].cm.curOp = null } + endOperations(group) + }) +} + +// The DOM updates done when an operation finishes are batched so +// that the minimum number of relayouts are required. +function endOperations(group) { + var ops = group.ops + for (var i = 0; i < ops.length; i++) // Read DOM + { endOperation_R1(ops[i]) } + for (var i$1 = 0; i$1 < ops.length; i$1++) // Write DOM (maybe) + { endOperation_W1(ops[i$1]) } + for (var i$2 = 0; i$2 < ops.length; i$2++) // Read DOM + { endOperation_R2(ops[i$2]) } + for (var i$3 = 0; i$3 < ops.length; i$3++) // Write DOM (maybe) + { endOperation_W2(ops[i$3]) } + for (var i$4 = 0; i$4 < ops.length; i$4++) // Read DOM + { endOperation_finish(ops[i$4]) } +} + +function endOperation_R1(op) { + var cm = op.cm, display = cm.display + maybeClipScrollbars(cm) + if (op.updateMaxLine) { findMaxLine(cm) } + + op.mustUpdate = op.viewChanged || op.forceUpdate || op.scrollTop != null || + op.scrollToPos && (op.scrollToPos.from.line < display.viewFrom || + op.scrollToPos.to.line >= display.viewTo) || + display.maxLineChanged && cm.options.lineWrapping + op.update = op.mustUpdate && + new DisplayUpdate(cm, op.mustUpdate && {top: op.scrollTop, ensure: op.scrollToPos}, op.forceUpdate) +} + +function endOperation_W1(op) { + op.updatedDisplay = op.mustUpdate && updateDisplayIfNeeded(op.cm, op.update) +} + +function endOperation_R2(op) { + var cm = op.cm, display = cm.display + if (op.updatedDisplay) { updateHeightsInViewport(cm) } + + op.barMeasure = measureForScrollbars(cm) + + // If the max line changed since it was last measured, measure it, + // and ensure the document's width matches it. + // updateDisplay_W2 will use these properties to do the actual resizing + if (display.maxLineChanged && !cm.options.lineWrapping) { + op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3 + cm.display.sizerWidth = op.adjustWidthTo + op.barMeasure.scrollWidth = + Math.max(display.scroller.clientWidth, display.sizer.offsetLeft + op.adjustWidthTo + scrollGap(cm) + cm.display.barWidth) + op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo - displayWidth(cm)) + } + + if (op.updatedDisplay || op.selectionChanged) + { op.preparedSelection = display.input.prepareSelection() } +} + +function endOperation_W2(op) { + var cm = op.cm + + if (op.adjustWidthTo != null) { + cm.display.sizer.style.minWidth = op.adjustWidthTo + "px" + if (op.maxScrollLeft < cm.doc.scrollLeft) + { setScrollLeft(cm, Math.min(cm.display.scroller.scrollLeft, op.maxScrollLeft), true) } + cm.display.maxLineChanged = false + } + + var takeFocus = op.focus && op.focus == activeElt() + if (op.preparedSelection) + { cm.display.input.showSelection(op.preparedSelection, takeFocus) } + if (op.updatedDisplay || op.startHeight != cm.doc.height) + { updateScrollbars(cm, op.barMeasure) } + if (op.updatedDisplay) + { setDocumentHeight(cm, op.barMeasure) } + + if (op.selectionChanged) { restartBlink(cm) } + + if (cm.state.focused && op.updateInput) + { cm.display.input.reset(op.typing) } + if (takeFocus) { ensureFocus(op.cm) } +} + +function endOperation_finish(op) { + var cm = op.cm, display = cm.display, doc = cm.doc + + if (op.updatedDisplay) { postUpdateDisplay(cm, op.update) } + + // Abort mouse wheel delta measurement, when scrolling explicitly + if (display.wheelStartX != null && (op.scrollTop != null || op.scrollLeft != null || op.scrollToPos)) + { display.wheelStartX = display.wheelStartY = null } + + // Propagate the scroll position to the actual DOM scroller + if (op.scrollTop != null) { setScrollTop(cm, op.scrollTop, op.forceScroll) } + + if (op.scrollLeft != null) { setScrollLeft(cm, op.scrollLeft, true, true) } + // If we need to scroll a specific position into view, do so. + if (op.scrollToPos) { + var rect = scrollPosIntoView(cm, clipPos(doc, op.scrollToPos.from), + clipPos(doc, op.scrollToPos.to), op.scrollToPos.margin) + maybeScrollWindow(cm, rect) + } + + // Fire events for markers that are hidden/unidden by editing or + // undoing + var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers + if (hidden) { for (var i = 0; i < hidden.length; ++i) + { if (!hidden[i].lines.length) { signal(hidden[i], "hide") } } } + if (unhidden) { for (var i$1 = 0; i$1 < unhidden.length; ++i$1) + { if (unhidden[i$1].lines.length) { signal(unhidden[i$1], "unhide") } } } + + if (display.wrapper.offsetHeight) + { doc.scrollTop = cm.display.scroller.scrollTop } + + // Fire change events, and delayed event handlers + if (op.changeObjs) + { signal(cm, "changes", cm, op.changeObjs) } + if (op.update) + { op.update.finish() } +} + +// Run the given function in an operation +function runInOp(cm, f) { + if (cm.curOp) { return f() } + startOperation(cm) + try { return f() } + finally { endOperation(cm) } +} +// Wraps a function in an operation. Returns the wrapped function. +function operation(cm, f) { + return function() { + if (cm.curOp) { return f.apply(cm, arguments) } + startOperation(cm) + try { return f.apply(cm, arguments) } + finally { endOperation(cm) } + } +} +// Used to add methods to editor and doc instances, wrapping them in +// operations. +function methodOp(f) { + return function() { + if (this.curOp) { return f.apply(this, arguments) } + startOperation(this) + try { return f.apply(this, arguments) } + finally { endOperation(this) } + } +} +function docMethodOp(f) { + return function() { + var cm = this.cm + if (!cm || cm.curOp) { return f.apply(this, arguments) } + startOperation(cm) + try { return f.apply(this, arguments) } + finally { endOperation(cm) } + } +} + +// Updates the display.view data structure for a given change to the +// document. From and to are in pre-change coordinates. Lendiff is +// the amount of lines added or subtracted by the change. This is +// used for changes that span multiple lines, or change the way +// lines are divided into visual lines. regLineChange (below) +// registers single-line changes. +function regChange(cm, from, to, lendiff) { + if (from == null) { from = cm.doc.first } + if (to == null) { to = cm.doc.first + cm.doc.size } + if (!lendiff) { lendiff = 0 } + + var display = cm.display + if (lendiff && to < display.viewTo && + (display.updateLineNumbers == null || display.updateLineNumbers > from)) + { display.updateLineNumbers = from } + + cm.curOp.viewChanged = true + + if (from >= display.viewTo) { // Change after + if (sawCollapsedSpans && visualLineNo(cm.doc, from) < display.viewTo) + { resetView(cm) } + } else if (to <= display.viewFrom) { // Change before + if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + lendiff) > display.viewFrom) { + resetView(cm) + } else { + display.viewFrom += lendiff + display.viewTo += lendiff + } + } else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap + resetView(cm) + } else if (from <= display.viewFrom) { // Top overlap + var cut = viewCuttingPoint(cm, to, to + lendiff, 1) + if (cut) { + display.view = display.view.slice(cut.index) + display.viewFrom = cut.lineN + display.viewTo += lendiff + } else { + resetView(cm) + } + } else if (to >= display.viewTo) { // Bottom overlap + var cut$1 = viewCuttingPoint(cm, from, from, -1) + if (cut$1) { + display.view = display.view.slice(0, cut$1.index) + display.viewTo = cut$1.lineN + } else { + resetView(cm) + } + } else { // Gap in the middle + var cutTop = viewCuttingPoint(cm, from, from, -1) + var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1) + if (cutTop && cutBot) { + display.view = display.view.slice(0, cutTop.index) + .concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN)) + .concat(display.view.slice(cutBot.index)) + display.viewTo += lendiff + } else { + resetView(cm) + } + } + + var ext = display.externalMeasured + if (ext) { + if (to < ext.lineN) + { ext.lineN += lendiff } + else if (from < ext.lineN + ext.size) + { display.externalMeasured = null } + } +} + +// Register a change to a single line. Type must be one of "text", +// "gutter", "class", "widget" +function regLineChange(cm, line, type) { + cm.curOp.viewChanged = true + var display = cm.display, ext = cm.display.externalMeasured + if (ext && line >= ext.lineN && line < ext.lineN + ext.size) + { display.externalMeasured = null } + + if (line < display.viewFrom || line >= display.viewTo) { return } + var lineView = display.view[findViewIndex(cm, line)] + if (lineView.node == null) { return } + var arr = lineView.changes || (lineView.changes = []) + if (indexOf(arr, type) == -1) { arr.push(type) } +} + +// Clear the view. +function resetView(cm) { + cm.display.viewFrom = cm.display.viewTo = cm.doc.first + cm.display.view = [] + cm.display.viewOffset = 0 +} + +function viewCuttingPoint(cm, oldN, newN, dir) { + var index = findViewIndex(cm, oldN), diff, view = cm.display.view + if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size) + { return {index: index, lineN: newN} } + var n = cm.display.viewFrom + for (var i = 0; i < index; i++) + { n += view[i].size } + if (n != oldN) { + if (dir > 0) { + if (index == view.length - 1) { return null } + diff = (n + view[index].size) - oldN + index++ + } else { + diff = n - oldN + } + oldN += diff; newN += diff + } + while (visualLineNo(cm.doc, newN) != newN) { + if (index == (dir < 0 ? 0 : view.length - 1)) { return null } + newN += dir * view[index - (dir < 0 ? 1 : 0)].size + index += dir + } + return {index: index, lineN: newN} +} + +// Force the view to cover a given range, adding empty view element +// or clipping off existing ones as needed. +function adjustView(cm, from, to) { + var display = cm.display, view = display.view + if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) { + display.view = buildViewArray(cm, from, to) + display.viewFrom = from + } else { + if (display.viewFrom > from) + { display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view) } + else if (display.viewFrom < from) + { display.view = display.view.slice(findViewIndex(cm, from)) } + display.viewFrom = from + if (display.viewTo < to) + { display.view = display.view.concat(buildViewArray(cm, display.viewTo, to)) } + else if (display.viewTo > to) + { display.view = display.view.slice(0, findViewIndex(cm, to)) } + } + display.viewTo = to +} + +// Count the number of lines in the view whose DOM representation is +// out of date (or nonexistent). +function countDirtyView(cm) { + var view = cm.display.view, dirty = 0 + for (var i = 0; i < view.length; i++) { + var lineView = view[i] + if (!lineView.hidden && (!lineView.node || lineView.changes)) { ++dirty } + } + return dirty +} + +// HIGHLIGHT WORKER + +function startWorker(cm, time) { + if (cm.doc.highlightFrontier < cm.display.viewTo) + { cm.state.highlight.set(time, bind(highlightWorker, cm)) } +} + +function highlightWorker(cm) { + var doc = cm.doc + if (doc.highlightFrontier >= cm.display.viewTo) { return } + var end = +new Date + cm.options.workTime + var context = getContextBefore(cm, doc.highlightFrontier) + var changedLines = [] + + doc.iter(context.line, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function (line) { + if (context.line >= cm.display.viewFrom) { // Visible + var oldStyles = line.styles + var resetState = line.text.length > cm.options.maxHighlightLength ? copyState(doc.mode, context.state) : null + var highlighted = highlightLine(cm, line, context, true) + if (resetState) { context.state = resetState } + line.styles = highlighted.styles + var oldCls = line.styleClasses, newCls = highlighted.classes + if (newCls) { line.styleClasses = newCls } + else if (oldCls) { line.styleClasses = null } + var ischange = !oldStyles || oldStyles.length != line.styles.length || + oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass) + for (var i = 0; !ischange && i < oldStyles.length; ++i) { ischange = oldStyles[i] != line.styles[i] } + if (ischange) { changedLines.push(context.line) } + line.stateAfter = context.save() + context.nextLine() + } else { + if (line.text.length <= cm.options.maxHighlightLength) + { processLine(cm, line.text, context) } + line.stateAfter = context.line % 5 == 0 ? context.save() : null + context.nextLine() + } + if (+new Date > end) { + startWorker(cm, cm.options.workDelay) + return true + } + }) + doc.highlightFrontier = context.line + doc.modeFrontier = Math.max(doc.modeFrontier, context.line) + if (changedLines.length) { runInOp(cm, function () { + for (var i = 0; i < changedLines.length; i++) + { regLineChange(cm, changedLines[i], "text") } + }) } +} + +// DISPLAY DRAWING + +var DisplayUpdate = function(cm, viewport, force) { + var display = cm.display + + this.viewport = viewport + // Store some values that we'll need later (but don't want to force a relayout for) + this.visible = visibleLines(display, cm.doc, viewport) + this.editorIsHidden = !display.wrapper.offsetWidth + this.wrapperHeight = display.wrapper.clientHeight + this.wrapperWidth = display.wrapper.clientWidth + this.oldDisplayWidth = displayWidth(cm) + this.force = force + this.dims = getDimensions(cm) + this.events = [] +}; + +DisplayUpdate.prototype.signal = function (emitter, type) { + if (hasHandler(emitter, type)) + { this.events.push(arguments) } +}; +DisplayUpdate.prototype.finish = function () { + var this$1 = this; + + for (var i = 0; i < this.events.length; i++) + { signal.apply(null, this$1.events[i]) } +}; + +function maybeClipScrollbars(cm) { + var display = cm.display + if (!display.scrollbarsClipped && display.scroller.offsetWidth) { + display.nativeBarWidth = display.scroller.offsetWidth - display.scroller.clientWidth + display.heightForcer.style.height = scrollGap(cm) + "px" + display.sizer.style.marginBottom = -display.nativeBarWidth + "px" + display.sizer.style.borderRightWidth = scrollGap(cm) + "px" + display.scrollbarsClipped = true + } +} + +function selectionSnapshot(cm) { + if (cm.hasFocus()) { return null } + var active = activeElt() + if (!active || !contains(cm.display.lineDiv, active)) { return null } + var result = {activeElt: active} + if (window.getSelection) { + var sel = window.getSelection() + if (sel.anchorNode && sel.extend && contains(cm.display.lineDiv, sel.anchorNode)) { + result.anchorNode = sel.anchorNode + result.anchorOffset = sel.anchorOffset + result.focusNode = sel.focusNode + result.focusOffset = sel.focusOffset + } + } + return result +} + +function restoreSelection(snapshot) { + if (!snapshot || !snapshot.activeElt || snapshot.activeElt == activeElt()) { return } + snapshot.activeElt.focus() + if (snapshot.anchorNode && contains(document.body, snapshot.anchorNode) && contains(document.body, snapshot.focusNode)) { + var sel = window.getSelection(), range = document.createRange() + range.setEnd(snapshot.anchorNode, snapshot.anchorOffset) + range.collapse(false) + sel.removeAllRanges() + sel.addRange(range) + sel.extend(snapshot.focusNode, snapshot.focusOffset) + } +} + +// Does the actual updating of the line display. Bails out +// (returning false) when there is nothing to be done and forced is +// false. +function updateDisplayIfNeeded(cm, update) { + var display = cm.display, doc = cm.doc + + if (update.editorIsHidden) { + resetView(cm) + return false + } + + // Bail out if the visible area is already rendered and nothing changed. + if (!update.force && + update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo && + (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) && + display.renderedView == display.view && countDirtyView(cm) == 0) + { return false } + + if (maybeUpdateLineNumberWidth(cm)) { + resetView(cm) + update.dims = getDimensions(cm) + } + + // Compute a suitable new viewport (from & to) + var end = doc.first + doc.size + var from = Math.max(update.visible.from - cm.options.viewportMargin, doc.first) + var to = Math.min(end, update.visible.to + cm.options.viewportMargin) + if (display.viewFrom < from && from - display.viewFrom < 20) { from = Math.max(doc.first, display.viewFrom) } + if (display.viewTo > to && display.viewTo - to < 20) { to = Math.min(end, display.viewTo) } + if (sawCollapsedSpans) { + from = visualLineNo(cm.doc, from) + to = visualLineEndNo(cm.doc, to) + } + + var different = from != display.viewFrom || to != display.viewTo || + display.lastWrapHeight != update.wrapperHeight || display.lastWrapWidth != update.wrapperWidth + adjustView(cm, from, to) + + display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom)) + // Position the mover div to align with the current scroll position + cm.display.mover.style.top = display.viewOffset + "px" + + var toUpdate = countDirtyView(cm) + if (!different && toUpdate == 0 && !update.force && display.renderedView == display.view && + (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo)) + { return false } + + // For big changes, we hide the enclosing element during the + // update, since that speeds up the operations on most browsers. + var selSnapshot = selectionSnapshot(cm) + if (toUpdate > 4) { display.lineDiv.style.display = "none" } + patchDisplay(cm, display.updateLineNumbers, update.dims) + if (toUpdate > 4) { display.lineDiv.style.display = "" } + display.renderedView = display.view + // There might have been a widget with a focused element that got + // hidden or updated, if so re-focus it. + restoreSelection(selSnapshot) + + // Prevent selection and cursors from interfering with the scroll + // width and height. + removeChildren(display.cursorDiv) + removeChildren(display.selectionDiv) + display.gutters.style.height = display.sizer.style.minHeight = 0 + + if (different) { + display.lastWrapHeight = update.wrapperHeight + display.lastWrapWidth = update.wrapperWidth + startWorker(cm, 400) + } + + display.updateLineNumbers = null + + return true +} + +function postUpdateDisplay(cm, update) { + var viewport = update.viewport + + for (var first = true;; first = false) { + if (!first || !cm.options.lineWrapping || update.oldDisplayWidth == displayWidth(cm)) { + // Clip forced viewport to actual scrollable area. + if (viewport && viewport.top != null) + { viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - displayHeight(cm), viewport.top)} } + // Updated line heights might result in the drawn area not + // actually covering the viewport. Keep looping until it does. + update.visible = visibleLines(cm.display, cm.doc, viewport) + if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo) + { break } + } + if (!updateDisplayIfNeeded(cm, update)) { break } + updateHeightsInViewport(cm) + var barMeasure = measureForScrollbars(cm) + updateSelection(cm) + updateScrollbars(cm, barMeasure) + setDocumentHeight(cm, barMeasure) + update.force = false + } + + update.signal(cm, "update", cm) + if (cm.display.viewFrom != cm.display.reportedViewFrom || cm.display.viewTo != cm.display.reportedViewTo) { + update.signal(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo) + cm.display.reportedViewFrom = cm.display.viewFrom; cm.display.reportedViewTo = cm.display.viewTo + } +} + +function updateDisplaySimple(cm, viewport) { + var update = new DisplayUpdate(cm, viewport) + if (updateDisplayIfNeeded(cm, update)) { + updateHeightsInViewport(cm) + postUpdateDisplay(cm, update) + var barMeasure = measureForScrollbars(cm) + updateSelection(cm) + updateScrollbars(cm, barMeasure) + setDocumentHeight(cm, barMeasure) + update.finish() + } +} + +// Sync the actual display DOM structure with display.view, removing +// nodes for lines that are no longer in view, and creating the ones +// that are not there yet, and updating the ones that are out of +// date. +function patchDisplay(cm, updateNumbersFrom, dims) { + var display = cm.display, lineNumbers = cm.options.lineNumbers + var container = display.lineDiv, cur = container.firstChild + + function rm(node) { + var next = node.nextSibling + // Works around a throw-scroll bug in OS X Webkit + if (webkit && mac && cm.display.currentWheelTarget == node) + { node.style.display = "none" } + else + { node.parentNode.removeChild(node) } + return next + } + + var view = display.view, lineN = display.viewFrom + // Loop over the elements in the view, syncing cur (the DOM nodes + // in display.lineDiv) with the view as we go. + for (var i = 0; i < view.length; i++) { + var lineView = view[i] + if (lineView.hidden) { + } else if (!lineView.node || lineView.node.parentNode != container) { // Not drawn yet + var node = buildLineElement(cm, lineView, lineN, dims) + container.insertBefore(node, cur) + } else { // Already drawn + while (cur != lineView.node) { cur = rm(cur) } + var updateNumber = lineNumbers && updateNumbersFrom != null && + updateNumbersFrom <= lineN && lineView.lineNumber + if (lineView.changes) { + if (indexOf(lineView.changes, "gutter") > -1) { updateNumber = false } + updateLineForChanges(cm, lineView, lineN, dims) + } + if (updateNumber) { + removeChildren(lineView.lineNumber) + lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options, lineN))) + } + cur = lineView.node.nextSibling + } + lineN += lineView.size + } + while (cur) { cur = rm(cur) } +} + +function updateGutterSpace(cm) { + var width = cm.display.gutters.offsetWidth + cm.display.sizer.style.marginLeft = width + "px" +} + +function setDocumentHeight(cm, measure) { + cm.display.sizer.style.minHeight = measure.docHeight + "px" + cm.display.heightForcer.style.top = measure.docHeight + "px" + cm.display.gutters.style.height = (measure.docHeight + cm.display.barHeight + scrollGap(cm)) + "px" +} + +// Rebuild the gutter elements, ensure the margin to the left of the +// code matches their width. +function updateGutters(cm) { + var gutters = cm.display.gutters, specs = cm.options.gutters + removeChildren(gutters) + var i = 0 + for (; i < specs.length; ++i) { + var gutterClass = specs[i] + var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gutterClass)) + if (gutterClass == "CodeMirror-linenumbers") { + cm.display.lineGutter = gElt + gElt.style.width = (cm.display.lineNumWidth || 1) + "px" + } + } + gutters.style.display = i ? "" : "none" + updateGutterSpace(cm) +} + +// Make sure the gutters options contains the element +// "CodeMirror-linenumbers" when the lineNumbers option is true. +function setGuttersForLineNumbers(options) { + var found = indexOf(options.gutters, "CodeMirror-linenumbers") + if (found == -1 && options.lineNumbers) { + options.gutters = options.gutters.concat(["CodeMirror-linenumbers"]) + } else if (found > -1 && !options.lineNumbers) { + options.gutters = options.gutters.slice(0) + options.gutters.splice(found, 1) + } +} + +var wheelSamples = 0; +var wheelPixelsPerUnit = null; +// Fill in a browser-detected starting value on browsers where we +// know one. These don't have to be accurate -- the result of them +// being wrong would just be a slight flicker on the first wheel +// scroll (if it is large enough). +if (ie) { wheelPixelsPerUnit = -.53 } +else if (gecko) { wheelPixelsPerUnit = 15 } +else if (chrome) { wheelPixelsPerUnit = -.7 } +else if (safari) { wheelPixelsPerUnit = -1/3 } + +function wheelEventDelta(e) { + var dx = e.wheelDeltaX, dy = e.wheelDeltaY + if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) { dx = e.detail } + if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) { dy = e.detail } + else if (dy == null) { dy = e.wheelDelta } + return {x: dx, y: dy} +} +function wheelEventPixels(e) { + var delta = wheelEventDelta(e) + delta.x *= wheelPixelsPerUnit + delta.y *= wheelPixelsPerUnit + return delta +} + +function onScrollWheel(cm, e) { + var delta = wheelEventDelta(e), dx = delta.x, dy = delta.y + + var display = cm.display, scroll = display.scroller + // Quit if there's nothing to scroll here + var canScrollX = scroll.scrollWidth > scroll.clientWidth + var canScrollY = scroll.scrollHeight > scroll.clientHeight + if (!(dx && canScrollX || dy && canScrollY)) { return } + + // Webkit browsers on OS X abort momentum scrolls when the target + // of the scroll event is removed from the scrollable element. + // This hack (see related code in patchDisplay) makes sure the + // element is kept around. + if (dy && mac && webkit) { + outer: for (var cur = e.target, view = display.view; cur != scroll; cur = cur.parentNode) { + for (var i = 0; i < view.length; i++) { + if (view[i].node == cur) { + cm.display.currentWheelTarget = cur + break outer + } + } + } + } + + // On some browsers, horizontal scrolling will cause redraws to + // happen before the gutter has been realigned, causing it to + // wriggle around in a most unseemly way. When we have an + // estimated pixels/delta value, we just handle horizontal + // scrolling entirely here. It'll be slightly off from native, but + // better than glitching out. + if (dx && !gecko && !presto && wheelPixelsPerUnit != null) { + if (dy && canScrollY) + { updateScrollTop(cm, Math.max(0, scroll.scrollTop + dy * wheelPixelsPerUnit)) } + setScrollLeft(cm, Math.max(0, scroll.scrollLeft + dx * wheelPixelsPerUnit)) + // Only prevent default scrolling if vertical scrolling is + // actually possible. Otherwise, it causes vertical scroll + // jitter on OSX trackpads when deltaX is small and deltaY + // is large (issue #3579) + if (!dy || (dy && canScrollY)) + { e_preventDefault(e) } + display.wheelStartX = null // Abort measurement, if in progress + return + } + + // 'Project' the visible viewport to cover the area that is being + // scrolled into view (if we know enough to estimate it). + if (dy && wheelPixelsPerUnit != null) { + var pixels = dy * wheelPixelsPerUnit + var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight + if (pixels < 0) { top = Math.max(0, top + pixels - 50) } + else { bot = Math.min(cm.doc.height, bot + pixels + 50) } + updateDisplaySimple(cm, {top: top, bottom: bot}) + } + + if (wheelSamples < 20) { + if (display.wheelStartX == null) { + display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop + display.wheelDX = dx; display.wheelDY = dy + setTimeout(function () { + if (display.wheelStartX == null) { return } + var movedX = scroll.scrollLeft - display.wheelStartX + var movedY = scroll.scrollTop - display.wheelStartY + var sample = (movedY && display.wheelDY && movedY / display.wheelDY) || + (movedX && display.wheelDX && movedX / display.wheelDX) + display.wheelStartX = display.wheelStartY = null + if (!sample) { return } + wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1) + ++wheelSamples + }, 200) + } else { + display.wheelDX += dx; display.wheelDY += dy + } + } +} + +// Selection objects are immutable. A new one is created every time +// the selection changes. A selection is one or more non-overlapping +// (and non-touching) ranges, sorted, and an integer that indicates +// which one is the primary selection (the one that's scrolled into +// view, that getCursor returns, etc). +var Selection = function(ranges, primIndex) { + this.ranges = ranges + this.primIndex = primIndex +}; + +Selection.prototype.primary = function () { return this.ranges[this.primIndex] }; + +Selection.prototype.equals = function (other) { + var this$1 = this; + + if (other == this) { return true } + if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) { return false } + for (var i = 0; i < this.ranges.length; i++) { + var here = this$1.ranges[i], there = other.ranges[i] + if (!equalCursorPos(here.anchor, there.anchor) || !equalCursorPos(here.head, there.head)) { return false } + } + return true +}; + +Selection.prototype.deepCopy = function () { + var this$1 = this; + + var out = [] + for (var i = 0; i < this.ranges.length; i++) + { out[i] = new Range(copyPos(this$1.ranges[i].anchor), copyPos(this$1.ranges[i].head)) } + return new Selection(out, this.primIndex) +}; + +Selection.prototype.somethingSelected = function () { + var this$1 = this; + + for (var i = 0; i < this.ranges.length; i++) + { if (!this$1.ranges[i].empty()) { return true } } + return false +}; + +Selection.prototype.contains = function (pos, end) { + var this$1 = this; + + if (!end) { end = pos } + for (var i = 0; i < this.ranges.length; i++) { + var range = this$1.ranges[i] + if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0) + { return i } + } + return -1 +}; + +var Range = function(anchor, head) { + this.anchor = anchor; this.head = head +}; + +Range.prototype.from = function () { return minPos(this.anchor, this.head) }; +Range.prototype.to = function () { return maxPos(this.anchor, this.head) }; +Range.prototype.empty = function () { return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch }; + +// Take an unsorted, potentially overlapping set of ranges, and +// build a selection out of it. 'Consumes' ranges array (modifying +// it). +function normalizeSelection(ranges, primIndex) { + var prim = ranges[primIndex] + ranges.sort(function (a, b) { return cmp(a.from(), b.from()); }) + primIndex = indexOf(ranges, prim) + for (var i = 1; i < ranges.length; i++) { + var cur = ranges[i], prev = ranges[i - 1] + if (cmp(prev.to(), cur.from()) >= 0) { + var from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to()) + var inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head + if (i <= primIndex) { --primIndex } + ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to)) + } + } + return new Selection(ranges, primIndex) +} + +function simpleSelection(anchor, head) { + return new Selection([new Range(anchor, head || anchor)], 0) +} + +// Compute the position of the end of a change (its 'to' property +// refers to the pre-change end). +function changeEnd(change) { + if (!change.text) { return change.to } + return Pos(change.from.line + change.text.length - 1, + lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0)) +} + +// Adjust a position to refer to the post-change position of the +// same text, or the end of the change if the change covers it. +function adjustForChange(pos, change) { + if (cmp(pos, change.from) < 0) { return pos } + if (cmp(pos, change.to) <= 0) { return changeEnd(change) } + + var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch + if (pos.line == change.to.line) { ch += changeEnd(change).ch - change.to.ch } + return Pos(line, ch) +} + +function computeSelAfterChange(doc, change) { + var out = [] + for (var i = 0; i < doc.sel.ranges.length; i++) { + var range = doc.sel.ranges[i] + out.push(new Range(adjustForChange(range.anchor, change), + adjustForChange(range.head, change))) + } + return normalizeSelection(out, doc.sel.primIndex) +} + +function offsetPos(pos, old, nw) { + if (pos.line == old.line) + { return Pos(nw.line, pos.ch - old.ch + nw.ch) } + else + { return Pos(nw.line + (pos.line - old.line), pos.ch) } +} + +// Used by replaceSelections to allow moving the selection to the +// start or around the replaced test. Hint may be "start" or "around". +function computeReplacedSel(doc, changes, hint) { + var out = [] + var oldPrev = Pos(doc.first, 0), newPrev = oldPrev + for (var i = 0; i < changes.length; i++) { + var change = changes[i] + var from = offsetPos(change.from, oldPrev, newPrev) + var to = offsetPos(changeEnd(change), oldPrev, newPrev) + oldPrev = change.to + newPrev = to + if (hint == "around") { + var range = doc.sel.ranges[i], inv = cmp(range.head, range.anchor) < 0 + out[i] = new Range(inv ? to : from, inv ? from : to) + } else { + out[i] = new Range(from, from) + } + } + return new Selection(out, doc.sel.primIndex) +} + +// Used to get the editor into a consistent state again when options change. + +function loadMode(cm) { + cm.doc.mode = getMode(cm.options, cm.doc.modeOption) + resetModeState(cm) +} + +function resetModeState(cm) { + cm.doc.iter(function (line) { + if (line.stateAfter) { line.stateAfter = null } + if (line.styles) { line.styles = null } + }) + cm.doc.modeFrontier = cm.doc.highlightFrontier = cm.doc.first + startWorker(cm, 100) + cm.state.modeGen++ + if (cm.curOp) { regChange(cm) } +} + +// DOCUMENT DATA STRUCTURE + +// By default, updates that start and end at the beginning of a line +// are treated specially, in order to make the association of line +// widgets and marker elements with the text behave more intuitive. +function isWholeLineUpdate(doc, change) { + return change.from.ch == 0 && change.to.ch == 0 && lst(change.text) == "" && + (!doc.cm || doc.cm.options.wholeLineUpdateBefore) +} + +// Perform a change on the document data structure. +function updateDoc(doc, change, markedSpans, estimateHeight) { + function spansFor(n) {return markedSpans ? markedSpans[n] : null} + function update(line, text, spans) { + updateLine(line, text, spans, estimateHeight) + signalLater(line, "change", line, change) + } + function linesFor(start, end) { + var result = [] + for (var i = start; i < end; ++i) + { result.push(new Line(text[i], spansFor(i), estimateHeight)) } + return result + } + + var from = change.from, to = change.to, text = change.text + var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line) + var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line + + // Adjust the line structure + if (change.full) { + doc.insert(0, linesFor(0, text.length)) + doc.remove(text.length, doc.size - text.length) + } else if (isWholeLineUpdate(doc, change)) { + // This is a whole-line replace. Treated specially to make + // sure line objects move the way they are supposed to. + var added = linesFor(0, text.length - 1) + update(lastLine, lastLine.text, lastSpans) + if (nlines) { doc.remove(from.line, nlines) } + if (added.length) { doc.insert(from.line, added) } + } else if (firstLine == lastLine) { + if (text.length == 1) { + update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans) + } else { + var added$1 = linesFor(1, text.length - 1) + added$1.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight)) + update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0)) + doc.insert(from.line + 1, added$1) + } + } else if (text.length == 1) { + update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0)) + doc.remove(from.line + 1, nlines) + } else { + update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0)) + update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans) + var added$2 = linesFor(1, text.length - 1) + if (nlines > 1) { doc.remove(from.line + 1, nlines - 1) } + doc.insert(from.line + 1, added$2) + } + + signalLater(doc, "change", doc, change) +} + +// Call f for all linked documents. +function linkedDocs(doc, f, sharedHistOnly) { + function propagate(doc, skip, sharedHist) { + if (doc.linked) { for (var i = 0; i < doc.linked.length; ++i) { + var rel = doc.linked[i] + if (rel.doc == skip) { continue } + var shared = sharedHist && rel.sharedHist + if (sharedHistOnly && !shared) { continue } + f(rel.doc, shared) + propagate(rel.doc, doc, shared) + } } + } + propagate(doc, null, true) +} + +// Attach a document to an editor. +function attachDoc(cm, doc) { + if (doc.cm) { throw new Error("This document is already in use.") } + cm.doc = doc + doc.cm = cm + estimateLineHeights(cm) + loadMode(cm) + setDirectionClass(cm) + if (!cm.options.lineWrapping) { findMaxLine(cm) } + cm.options.mode = doc.modeOption + regChange(cm) +} + +function setDirectionClass(cm) { + ;(cm.doc.direction == "rtl" ? addClass : rmClass)(cm.display.lineDiv, "CodeMirror-rtl") +} + +function directionChanged(cm) { + runInOp(cm, function () { + setDirectionClass(cm) + regChange(cm) + }) +} + +function History(startGen) { + // Arrays of change events and selections. Doing something adds an + // event to done and clears undo. Undoing moves events from done + // to undone, redoing moves them in the other direction. + this.done = []; this.undone = [] + this.undoDepth = Infinity + // Used to track when changes can be merged into a single undo + // event + this.lastModTime = this.lastSelTime = 0 + this.lastOp = this.lastSelOp = null + this.lastOrigin = this.lastSelOrigin = null + // Used by the isClean() method + this.generation = this.maxGeneration = startGen || 1 +} + +// Create a history change event from an updateDoc-style change +// object. +function historyChangeFromChange(doc, change) { + var histChange = {from: copyPos(change.from), to: changeEnd(change), text: getBetween(doc, change.from, change.to)} + attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1) + linkedDocs(doc, function (doc) { return attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1); }, true) + return histChange +} + +// Pop all selection events off the end of a history array. Stop at +// a change event. +function clearSelectionEvents(array) { + while (array.length) { + var last = lst(array) + if (last.ranges) { array.pop() } + else { break } + } +} + +// Find the top change event in the history. Pop off selection +// events that are in the way. +function lastChangeEvent(hist, force) { + if (force) { + clearSelectionEvents(hist.done) + return lst(hist.done) + } else if (hist.done.length && !lst(hist.done).ranges) { + return lst(hist.done) + } else if (hist.done.length > 1 && !hist.done[hist.done.length - 2].ranges) { + hist.done.pop() + return lst(hist.done) + } +} + +// Register a change in the history. Merges changes that are within +// a single operation, or are close together with an origin that +// allows merging (starting with "+") into a single event. +function addChangeToHistory(doc, change, selAfter, opId) { + var hist = doc.history + hist.undone.length = 0 + var time = +new Date, cur + var last + + if ((hist.lastOp == opId || + hist.lastOrigin == change.origin && change.origin && + ((change.origin.charAt(0) == "+" && hist.lastModTime > time - (doc.cm ? doc.cm.options.historyEventDelay : 500)) || + change.origin.charAt(0) == "*")) && + (cur = lastChangeEvent(hist, hist.lastOp == opId))) { + // Merge this change into the last event + last = lst(cur.changes) + if (cmp(change.from, change.to) == 0 && cmp(change.from, last.to) == 0) { + // Optimized case for simple insertion -- don't want to add + // new changesets for every character typed + last.to = changeEnd(change) + } else { + // Add new sub-event + cur.changes.push(historyChangeFromChange(doc, change)) + } + } else { + // Can not be merged, start a new event. + var before = lst(hist.done) + if (!before || !before.ranges) + { pushSelectionToHistory(doc.sel, hist.done) } + cur = {changes: [historyChangeFromChange(doc, change)], + generation: hist.generation} + hist.done.push(cur) + while (hist.done.length > hist.undoDepth) { + hist.done.shift() + if (!hist.done[0].ranges) { hist.done.shift() } + } + } + hist.done.push(selAfter) + hist.generation = ++hist.maxGeneration + hist.lastModTime = hist.lastSelTime = time + hist.lastOp = hist.lastSelOp = opId + hist.lastOrigin = hist.lastSelOrigin = change.origin + + if (!last) { signal(doc, "historyAdded") } +} + +function selectionEventCanBeMerged(doc, origin, prev, sel) { + var ch = origin.charAt(0) + return ch == "*" || + ch == "+" && + prev.ranges.length == sel.ranges.length && + prev.somethingSelected() == sel.somethingSelected() && + new Date - doc.history.lastSelTime <= (doc.cm ? doc.cm.options.historyEventDelay : 500) +} + +// Called whenever the selection changes, sets the new selection as +// the pending selection in the history, and pushes the old pending +// selection into the 'done' array when it was significantly +// different (in number of selected ranges, emptiness, or time). +function addSelectionToHistory(doc, sel, opId, options) { + var hist = doc.history, origin = options && options.origin + + // A new event is started when the previous origin does not match + // the current, or the origins don't allow matching. Origins + // starting with * are always merged, those starting with + are + // merged when similar and close together in time. + if (opId == hist.lastSelOp || + (origin && hist.lastSelOrigin == origin && + (hist.lastModTime == hist.lastSelTime && hist.lastOrigin == origin || + selectionEventCanBeMerged(doc, origin, lst(hist.done), sel)))) + { hist.done[hist.done.length - 1] = sel } + else + { pushSelectionToHistory(sel, hist.done) } + + hist.lastSelTime = +new Date + hist.lastSelOrigin = origin + hist.lastSelOp = opId + if (options && options.clearRedo !== false) + { clearSelectionEvents(hist.undone) } +} + +function pushSelectionToHistory(sel, dest) { + var top = lst(dest) + if (!(top && top.ranges && top.equals(sel))) + { dest.push(sel) } +} + +// Used to store marked span information in the history. +function attachLocalSpans(doc, change, from, to) { + var existing = change["spans_" + doc.id], n = 0 + doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function (line) { + if (line.markedSpans) + { (existing || (existing = change["spans_" + doc.id] = {}))[n] = line.markedSpans } + ++n + }) +} + +// When un/re-doing restores text containing marked spans, those +// that have been explicitly cleared should not be restored. +function removeClearedSpans(spans) { + if (!spans) { return null } + var out + for (var i = 0; i < spans.length; ++i) { + if (spans[i].marker.explicitlyCleared) { if (!out) { out = spans.slice(0, i) } } + else if (out) { out.push(spans[i]) } + } + return !out ? spans : out.length ? out : null +} + +// Retrieve and filter the old marked spans stored in a change event. +function getOldSpans(doc, change) { + var found = change["spans_" + doc.id] + if (!found) { return null } + var nw = [] + for (var i = 0; i < change.text.length; ++i) + { nw.push(removeClearedSpans(found[i])) } + return nw +} + +// Used for un/re-doing changes from the history. Combines the +// result of computing the existing spans with the set of spans that +// existed in the history (so that deleting around a span and then +// undoing brings back the span). +function mergeOldSpans(doc, change) { + var old = getOldSpans(doc, change) + var stretched = stretchSpansOverChange(doc, change) + if (!old) { return stretched } + if (!stretched) { return old } + + for (var i = 0; i < old.length; ++i) { + var oldCur = old[i], stretchCur = stretched[i] + if (oldCur && stretchCur) { + spans: for (var j = 0; j < stretchCur.length; ++j) { + var span = stretchCur[j] + for (var k = 0; k < oldCur.length; ++k) + { if (oldCur[k].marker == span.marker) { continue spans } } + oldCur.push(span) + } + } else if (stretchCur) { + old[i] = stretchCur + } + } + return old +} + +// Used both to provide a JSON-safe object in .getHistory, and, when +// detaching a document, to split the history in two +function copyHistoryArray(events, newGroup, instantiateSel) { + var copy = [] + for (var i = 0; i < events.length; ++i) { + var event = events[i] + if (event.ranges) { + copy.push(instantiateSel ? Selection.prototype.deepCopy.call(event) : event) + continue + } + var changes = event.changes, newChanges = [] + copy.push({changes: newChanges}) + for (var j = 0; j < changes.length; ++j) { + var change = changes[j], m = (void 0) + newChanges.push({from: change.from, to: change.to, text: change.text}) + if (newGroup) { for (var prop in change) { if (m = prop.match(/^spans_(\d+)$/)) { + if (indexOf(newGroup, Number(m[1])) > -1) { + lst(newChanges)[prop] = change[prop] + delete change[prop] + } + } } } + } + } + return copy +} + +// The 'scroll' parameter given to many of these indicated whether +// the new cursor position should be scrolled into view after +// modifying the selection. + +// If shift is held or the extend flag is set, extends a range to +// include a given position (and optionally a second position). +// Otherwise, simply returns the range between the given positions. +// Used for cursor motion and such. +function extendRange(range, head, other, extend) { + if (extend) { + var anchor = range.anchor + if (other) { + var posBefore = cmp(head, anchor) < 0 + if (posBefore != (cmp(other, anchor) < 0)) { + anchor = head + head = other + } else if (posBefore != (cmp(head, other) < 0)) { + head = other + } + } + return new Range(anchor, head) + } else { + return new Range(other || head, head) + } +} + +// Extend the primary selection range, discard the rest. +function extendSelection(doc, head, other, options, extend) { + if (extend == null) { extend = doc.cm && (doc.cm.display.shift || doc.extend) } + setSelection(doc, new Selection([extendRange(doc.sel.primary(), head, other, extend)], 0), options) +} + +// Extend all selections (pos is an array of selections with length +// equal the number of selections) +function extendSelections(doc, heads, options) { + var out = [] + var extend = doc.cm && (doc.cm.display.shift || doc.extend) + for (var i = 0; i < doc.sel.ranges.length; i++) + { out[i] = extendRange(doc.sel.ranges[i], heads[i], null, extend) } + var newSel = normalizeSelection(out, doc.sel.primIndex) + setSelection(doc, newSel, options) +} + +// Updates a single range in the selection. +function replaceOneSelection(doc, i, range, options) { + var ranges = doc.sel.ranges.slice(0) + ranges[i] = range + setSelection(doc, normalizeSelection(ranges, doc.sel.primIndex), options) +} + +// Reset the selection to a single range. +function setSimpleSelection(doc, anchor, head, options) { + setSelection(doc, simpleSelection(anchor, head), options) +} + +// Give beforeSelectionChange handlers a change to influence a +// selection update. +function filterSelectionChange(doc, sel, options) { + var obj = { + ranges: sel.ranges, + update: function(ranges) { + var this$1 = this; + + this.ranges = [] + for (var i = 0; i < ranges.length; i++) + { this$1.ranges[i] = new Range(clipPos(doc, ranges[i].anchor), + clipPos(doc, ranges[i].head)) } + }, + origin: options && options.origin + } + signal(doc, "beforeSelectionChange", doc, obj) + if (doc.cm) { signal(doc.cm, "beforeSelectionChange", doc.cm, obj) } + if (obj.ranges != sel.ranges) { return normalizeSelection(obj.ranges, obj.ranges.length - 1) } + else { return sel } +} + +function setSelectionReplaceHistory(doc, sel, options) { + var done = doc.history.done, last = lst(done) + if (last && last.ranges) { + done[done.length - 1] = sel + setSelectionNoUndo(doc, sel, options) + } else { + setSelection(doc, sel, options) + } +} + +// Set a new selection. +function setSelection(doc, sel, options) { + setSelectionNoUndo(doc, sel, options) + addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options) +} + +function setSelectionNoUndo(doc, sel, options) { + if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange")) + { sel = filterSelectionChange(doc, sel, options) } + + var bias = options && options.bias || + (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1) + setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true)) + + if (!(options && options.scroll === false) && doc.cm) + { ensureCursorVisible(doc.cm) } +} + +function setSelectionInner(doc, sel) { + if (sel.equals(doc.sel)) { return } + + doc.sel = sel + + if (doc.cm) { + doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged = true + signalCursorActivity(doc.cm) + } + signalLater(doc, "cursorActivity", doc) +} + +// Verify that the selection does not partially select any atomic +// marked ranges. +function reCheckSelection(doc) { + setSelectionInner(doc, skipAtomicInSelection(doc, doc.sel, null, false)) +} + +// Return a selection that does not partially select any atomic +// ranges. +function skipAtomicInSelection(doc, sel, bias, mayClear) { + var out + for (var i = 0; i < sel.ranges.length; i++) { + var range = sel.ranges[i] + var old = sel.ranges.length == doc.sel.ranges.length && doc.sel.ranges[i] + var newAnchor = skipAtomic(doc, range.anchor, old && old.anchor, bias, mayClear) + var newHead = skipAtomic(doc, range.head, old && old.head, bias, mayClear) + if (out || newAnchor != range.anchor || newHead != range.head) { + if (!out) { out = sel.ranges.slice(0, i) } + out[i] = new Range(newAnchor, newHead) + } + } + return out ? normalizeSelection(out, sel.primIndex) : sel +} + +function skipAtomicInner(doc, pos, oldPos, dir, mayClear) { + var line = getLine(doc, pos.line) + if (line.markedSpans) { for (var i = 0; i < line.markedSpans.length; ++i) { + var sp = line.markedSpans[i], m = sp.marker + if ((sp.from == null || (m.inclusiveLeft ? sp.from <= pos.ch : sp.from < pos.ch)) && + (sp.to == null || (m.inclusiveRight ? sp.to >= pos.ch : sp.to > pos.ch))) { + if (mayClear) { + signal(m, "beforeCursorEnter") + if (m.explicitlyCleared) { + if (!line.markedSpans) { break } + else {--i; continue} + } + } + if (!m.atomic) { continue } + + if (oldPos) { + var near = m.find(dir < 0 ? 1 : -1), diff = (void 0) + if (dir < 0 ? m.inclusiveRight : m.inclusiveLeft) + { near = movePos(doc, near, -dir, near && near.line == pos.line ? line : null) } + if (near && near.line == pos.line && (diff = cmp(near, oldPos)) && (dir < 0 ? diff < 0 : diff > 0)) + { return skipAtomicInner(doc, near, pos, dir, mayClear) } + } + + var far = m.find(dir < 0 ? -1 : 1) + if (dir < 0 ? m.inclusiveLeft : m.inclusiveRight) + { far = movePos(doc, far, dir, far.line == pos.line ? line : null) } + return far ? skipAtomicInner(doc, far, pos, dir, mayClear) : null + } + } } + return pos +} + +// Ensure a given position is not inside an atomic range. +function skipAtomic(doc, pos, oldPos, bias, mayClear) { + var dir = bias || 1 + var found = skipAtomicInner(doc, pos, oldPos, dir, mayClear) || + (!mayClear && skipAtomicInner(doc, pos, oldPos, dir, true)) || + skipAtomicInner(doc, pos, oldPos, -dir, mayClear) || + (!mayClear && skipAtomicInner(doc, pos, oldPos, -dir, true)) + if (!found) { + doc.cantEdit = true + return Pos(doc.first, 0) + } + return found +} + +function movePos(doc, pos, dir, line) { + if (dir < 0 && pos.ch == 0) { + if (pos.line > doc.first) { return clipPos(doc, Pos(pos.line - 1)) } + else { return null } + } else if (dir > 0 && pos.ch == (line || getLine(doc, pos.line)).text.length) { + if (pos.line < doc.first + doc.size - 1) { return Pos(pos.line + 1, 0) } + else { return null } + } else { + return new Pos(pos.line, pos.ch + dir) + } +} + +function selectAll(cm) { + cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()), sel_dontScroll) +} + +// UPDATING + +// Allow "beforeChange" event handlers to influence a change +function filterChange(doc, change, update) { + var obj = { + canceled: false, + from: change.from, + to: change.to, + text: change.text, + origin: change.origin, + cancel: function () { return obj.canceled = true; } + } + if (update) { obj.update = function (from, to, text, origin) { + if (from) { obj.from = clipPos(doc, from) } + if (to) { obj.to = clipPos(doc, to) } + if (text) { obj.text = text } + if (origin !== undefined) { obj.origin = origin } + } } + signal(doc, "beforeChange", doc, obj) + if (doc.cm) { signal(doc.cm, "beforeChange", doc.cm, obj) } + + if (obj.canceled) { return null } + return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin} +} + +// Apply a change to a document, and add it to the document's +// history, and propagating it to all linked documents. +function makeChange(doc, change, ignoreReadOnly) { + if (doc.cm) { + if (!doc.cm.curOp) { return operation(doc.cm, makeChange)(doc, change, ignoreReadOnly) } + if (doc.cm.state.suppressEdits) { return } + } + + if (hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange")) { + change = filterChange(doc, change, true) + if (!change) { return } + } + + // Possibly split or suppress the update based on the presence + // of read-only spans in its range. + var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to) + if (split) { + for (var i = split.length - 1; i >= 0; --i) + { makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [""] : change.text, origin: change.origin}) } + } else { + makeChangeInner(doc, change) + } +} + +function makeChangeInner(doc, change) { + if (change.text.length == 1 && change.text[0] == "" && cmp(change.from, change.to) == 0) { return } + var selAfter = computeSelAfterChange(doc, change) + addChangeToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN) + + makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change)) + var rebased = [] + + linkedDocs(doc, function (doc, sharedHist) { + if (!sharedHist && indexOf(rebased, doc.history) == -1) { + rebaseHist(doc.history, change) + rebased.push(doc.history) + } + makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change)) + }) +} + +// Revert a change stored in a document's history. +function makeChangeFromHistory(doc, type, allowSelectionOnly) { + var suppress = doc.cm && doc.cm.state.suppressEdits + if (suppress && !allowSelectionOnly) { return } + + var hist = doc.history, event, selAfter = doc.sel + var source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done + + // Verify that there is a useable event (so that ctrl-z won't + // needlessly clear selection events) + var i = 0 + for (; i < source.length; i++) { + event = source[i] + if (allowSelectionOnly ? event.ranges && !event.equals(doc.sel) : !event.ranges) + { break } + } + if (i == source.length) { return } + hist.lastOrigin = hist.lastSelOrigin = null + + for (;;) { + event = source.pop() + if (event.ranges) { + pushSelectionToHistory(event, dest) + if (allowSelectionOnly && !event.equals(doc.sel)) { + setSelection(doc, event, {clearRedo: false}) + return + } + selAfter = event + } else if (suppress) { + source.push(event) + return + } else { break } + } + + // Build up a reverse change object to add to the opposite history + // stack (redo when undoing, and vice versa). + var antiChanges = [] + pushSelectionToHistory(selAfter, dest) + dest.push({changes: antiChanges, generation: hist.generation}) + hist.generation = event.generation || ++hist.maxGeneration + + var filter = hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange") + + var loop = function ( i ) { + var change = event.changes[i] + change.origin = type + if (filter && !filterChange(doc, change, false)) { + source.length = 0 + return {} + } + + antiChanges.push(historyChangeFromChange(doc, change)) + + var after = i ? computeSelAfterChange(doc, change) : lst(source) + makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change)) + if (!i && doc.cm) { doc.cm.scrollIntoView({from: change.from, to: changeEnd(change)}) } + var rebased = [] + + // Propagate to the linked documents + linkedDocs(doc, function (doc, sharedHist) { + if (!sharedHist && indexOf(rebased, doc.history) == -1) { + rebaseHist(doc.history, change) + rebased.push(doc.history) + } + makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change)) + }) + }; + + for (var i$1 = event.changes.length - 1; i$1 >= 0; --i$1) { + var returned = loop( i$1 ); + + if ( returned ) return returned.v; + } +} + +// Sub-views need their line numbers shifted when text is added +// above or below them in the parent document. +function shiftDoc(doc, distance) { + if (distance == 0) { return } + doc.first += distance + doc.sel = new Selection(map(doc.sel.ranges, function (range) { return new Range( + Pos(range.anchor.line + distance, range.anchor.ch), + Pos(range.head.line + distance, range.head.ch) + ); }), doc.sel.primIndex) + if (doc.cm) { + regChange(doc.cm, doc.first, doc.first - distance, distance) + for (var d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++) + { regLineChange(doc.cm, l, "gutter") } + } +} + +// More lower-level change function, handling only a single document +// (not linked ones). +function makeChangeSingleDoc(doc, change, selAfter, spans) { + if (doc.cm && !doc.cm.curOp) + { return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans) } + + if (change.to.line < doc.first) { + shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line)) + return + } + if (change.from.line > doc.lastLine()) { return } + + // Clip the change to the size of this doc + if (change.from.line < doc.first) { + var shift = change.text.length - 1 - (doc.first - change.from.line) + shiftDoc(doc, shift) + change = {from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch), + text: [lst(change.text)], origin: change.origin} + } + var last = doc.lastLine() + if (change.to.line > last) { + change = {from: change.from, to: Pos(last, getLine(doc, last).text.length), + text: [change.text[0]], origin: change.origin} + } + + change.removed = getBetween(doc, change.from, change.to) + + if (!selAfter) { selAfter = computeSelAfterChange(doc, change) } + if (doc.cm) { makeChangeSingleDocInEditor(doc.cm, change, spans) } + else { updateDoc(doc, change, spans) } + setSelectionNoUndo(doc, selAfter, sel_dontScroll) +} + +// Handle the interaction of a change to a document with the editor +// that this document is part of. +function makeChangeSingleDocInEditor(cm, change, spans) { + var doc = cm.doc, display = cm.display, from = change.from, to = change.to + + var recomputeMaxLength = false, checkWidthStart = from.line + if (!cm.options.lineWrapping) { + checkWidthStart = lineNo(visualLine(getLine(doc, from.line))) + doc.iter(checkWidthStart, to.line + 1, function (line) { + if (line == display.maxLine) { + recomputeMaxLength = true + return true + } + }) + } + + if (doc.sel.contains(change.from, change.to) > -1) + { signalCursorActivity(cm) } + + updateDoc(doc, change, spans, estimateHeight(cm)) + + if (!cm.options.lineWrapping) { + doc.iter(checkWidthStart, from.line + change.text.length, function (line) { + var len = lineLength(line) + if (len > display.maxLineLength) { + display.maxLine = line + display.maxLineLength = len + display.maxLineChanged = true + recomputeMaxLength = false + } + }) + if (recomputeMaxLength) { cm.curOp.updateMaxLine = true } + } + + retreatFrontier(doc, from.line) + startWorker(cm, 400) + + var lendiff = change.text.length - (to.line - from.line) - 1 + // Remember that these lines changed, for updating the display + if (change.full) + { regChange(cm) } + else if (from.line == to.line && change.text.length == 1 && !isWholeLineUpdate(cm.doc, change)) + { regLineChange(cm, from.line, "text") } + else + { regChange(cm, from.line, to.line + 1, lendiff) } + + var changesHandler = hasHandler(cm, "changes"), changeHandler = hasHandler(cm, "change") + if (changeHandler || changesHandler) { + var obj = { + from: from, to: to, + text: change.text, + removed: change.removed, + origin: change.origin + } + if (changeHandler) { signalLater(cm, "change", cm, obj) } + if (changesHandler) { (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj) } + } + cm.display.selForContextMenu = null +} + +function replaceRange(doc, code, from, to, origin) { + if (!to) { to = from } + if (cmp(to, from) < 0) { var assign; + (assign = [to, from], from = assign[0], to = assign[1], assign) } + if (typeof code == "string") { code = doc.splitLines(code) } + makeChange(doc, {from: from, to: to, text: code, origin: origin}) +} + +// Rebasing/resetting history to deal with externally-sourced changes + +function rebaseHistSelSingle(pos, from, to, diff) { + if (to < pos.line) { + pos.line += diff + } else if (from < pos.line) { + pos.line = from + pos.ch = 0 + } +} + +// Tries to rebase an array of history events given a change in the +// document. If the change touches the same lines as the event, the +// event, and everything 'behind' it, is discarded. If the change is +// before the event, the event's positions are updated. Uses a +// copy-on-write scheme for the positions, to avoid having to +// reallocate them all on every rebase, but also avoid problems with +// shared position objects being unsafely updated. +function rebaseHistArray(array, from, to, diff) { + for (var i = 0; i < array.length; ++i) { + var sub = array[i], ok = true + if (sub.ranges) { + if (!sub.copied) { sub = array[i] = sub.deepCopy(); sub.copied = true } + for (var j = 0; j < sub.ranges.length; j++) { + rebaseHistSelSingle(sub.ranges[j].anchor, from, to, diff) + rebaseHistSelSingle(sub.ranges[j].head, from, to, diff) + } + continue + } + for (var j$1 = 0; j$1 < sub.changes.length; ++j$1) { + var cur = sub.changes[j$1] + if (to < cur.from.line) { + cur.from = Pos(cur.from.line + diff, cur.from.ch) + cur.to = Pos(cur.to.line + diff, cur.to.ch) + } else if (from <= cur.to.line) { + ok = false + break + } + } + if (!ok) { + array.splice(0, i + 1) + i = 0 + } + } +} + +function rebaseHist(hist, change) { + var from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1 + rebaseHistArray(hist.done, from, to, diff) + rebaseHistArray(hist.undone, from, to, diff) +} + +// Utility for applying a change to a line by handle or number, +// returning the number and optionally registering the line as +// changed. +function changeLine(doc, handle, changeType, op) { + var no = handle, line = handle + if (typeof handle == "number") { line = getLine(doc, clipLine(doc, handle)) } + else { no = lineNo(handle) } + if (no == null) { return null } + if (op(line, no) && doc.cm) { regLineChange(doc.cm, no, changeType) } + return line +} + +// The document is represented as a BTree consisting of leaves, with +// chunk of lines in them, and branches, with up to ten leaves or +// other branch nodes below them. The top node is always a branch +// node, and is the document object itself (meaning it has +// additional methods and properties). +// +// All nodes have parent links. The tree is used both to go from +// line numbers to line objects, and to go from objects to numbers. +// It also indexes by height, and is used to convert between height +// and line object, and to find the total height of the document. +// +// See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html + +function LeafChunk(lines) { + var this$1 = this; + + this.lines = lines + this.parent = null + var height = 0 + for (var i = 0; i < lines.length; ++i) { + lines[i].parent = this$1 + height += lines[i].height + } + this.height = height +} + +LeafChunk.prototype = { + chunkSize: function chunkSize() { return this.lines.length }, + + // Remove the n lines at offset 'at'. + removeInner: function removeInner(at, n) { + var this$1 = this; + + for (var i = at, e = at + n; i < e; ++i) { + var line = this$1.lines[i] + this$1.height -= line.height + cleanUpLine(line) + signalLater(line, "delete") + } + this.lines.splice(at, n) + }, + + // Helper used to collapse a small branch into a single leaf. + collapse: function collapse(lines) { + lines.push.apply(lines, this.lines) + }, + + // Insert the given array of lines at offset 'at', count them as + // having the given height. + insertInner: function insertInner(at, lines, height) { + var this$1 = this; + + this.height += height + this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at)) + for (var i = 0; i < lines.length; ++i) { lines[i].parent = this$1 } + }, + + // Used to iterate over a part of the tree. + iterN: function iterN(at, n, op) { + var this$1 = this; + + for (var e = at + n; at < e; ++at) + { if (op(this$1.lines[at])) { return true } } + } +} + +function BranchChunk(children) { + var this$1 = this; + + this.children = children + var size = 0, height = 0 + for (var i = 0; i < children.length; ++i) { + var ch = children[i] + size += ch.chunkSize(); height += ch.height + ch.parent = this$1 + } + this.size = size + this.height = height + this.parent = null +} + +BranchChunk.prototype = { + chunkSize: function chunkSize() { return this.size }, + + removeInner: function removeInner(at, n) { + var this$1 = this; + + this.size -= n + for (var i = 0; i < this.children.length; ++i) { + var child = this$1.children[i], sz = child.chunkSize() + if (at < sz) { + var rm = Math.min(n, sz - at), oldHeight = child.height + child.removeInner(at, rm) + this$1.height -= oldHeight - child.height + if (sz == rm) { this$1.children.splice(i--, 1); child.parent = null } + if ((n -= rm) == 0) { break } + at = 0 + } else { at -= sz } + } + // If the result is smaller than 25 lines, ensure that it is a + // single leaf node. + if (this.size - n < 25 && + (this.children.length > 1 || !(this.children[0] instanceof LeafChunk))) { + var lines = [] + this.collapse(lines) + this.children = [new LeafChunk(lines)] + this.children[0].parent = this + } + }, + + collapse: function collapse(lines) { + var this$1 = this; + + for (var i = 0; i < this.children.length; ++i) { this$1.children[i].collapse(lines) } + }, + + insertInner: function insertInner(at, lines, height) { + var this$1 = this; + + this.size += lines.length + this.height += height + for (var i = 0; i < this.children.length; ++i) { + var child = this$1.children[i], sz = child.chunkSize() + if (at <= sz) { + child.insertInner(at, lines, height) + if (child.lines && child.lines.length > 50) { + // To avoid memory thrashing when child.lines is huge (e.g. first view of a large file), it's never spliced. + // Instead, small slices are taken. They're taken in order because sequential memory accesses are fastest. + var remaining = child.lines.length % 25 + 25 + for (var pos = remaining; pos < child.lines.length;) { + var leaf = new LeafChunk(child.lines.slice(pos, pos += 25)) + child.height -= leaf.height + this$1.children.splice(++i, 0, leaf) + leaf.parent = this$1 + } + child.lines = child.lines.slice(0, remaining) + this$1.maybeSpill() + } + break + } + at -= sz + } + }, + + // When a node has grown, check whether it should be split. + maybeSpill: function maybeSpill() { + if (this.children.length <= 10) { return } + var me = this + do { + var spilled = me.children.splice(me.children.length - 5, 5) + var sibling = new BranchChunk(spilled) + if (!me.parent) { // Become the parent node + var copy = new BranchChunk(me.children) + copy.parent = me + me.children = [copy, sibling] + me = copy + } else { + me.size -= sibling.size + me.height -= sibling.height + var myIndex = indexOf(me.parent.children, me) + me.parent.children.splice(myIndex + 1, 0, sibling) + } + sibling.parent = me.parent + } while (me.children.length > 10) + me.parent.maybeSpill() + }, + + iterN: function iterN(at, n, op) { + var this$1 = this; + + for (var i = 0; i < this.children.length; ++i) { + var child = this$1.children[i], sz = child.chunkSize() + if (at < sz) { + var used = Math.min(n, sz - at) + if (child.iterN(at, used, op)) { return true } + if ((n -= used) == 0) { break } + at = 0 + } else { at -= sz } + } + } +} + +// Line widgets are block elements displayed above or below a line. + +var LineWidget = function(doc, node, options) { + var this$1 = this; + + if (options) { for (var opt in options) { if (options.hasOwnProperty(opt)) + { this$1[opt] = options[opt] } } } + this.doc = doc + this.node = node +}; + +LineWidget.prototype.clear = function () { + var this$1 = this; + + var cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line) + if (no == null || !ws) { return } + for (var i = 0; i < ws.length; ++i) { if (ws[i] == this$1) { ws.splice(i--, 1) } } + if (!ws.length) { line.widgets = null } + var height = widgetHeight(this) + updateLineHeight(line, Math.max(0, line.height - height)) + if (cm) { + runInOp(cm, function () { + adjustScrollWhenAboveVisible(cm, line, -height) + regLineChange(cm, no, "widget") + }) + signalLater(cm, "lineWidgetCleared", cm, this, no) + } +}; + +LineWidget.prototype.changed = function () { + var this$1 = this; + + var oldH = this.height, cm = this.doc.cm, line = this.line + this.height = null + var diff = widgetHeight(this) - oldH + if (!diff) { return } + updateLineHeight(line, line.height + diff) + if (cm) { + runInOp(cm, function () { + cm.curOp.forceUpdate = true + adjustScrollWhenAboveVisible(cm, line, diff) + signalLater(cm, "lineWidgetChanged", cm, this$1, lineNo(line)) + }) + } +}; +eventMixin(LineWidget) + +function adjustScrollWhenAboveVisible(cm, line, diff) { + if (heightAtLine(line) < ((cm.curOp && cm.curOp.scrollTop) || cm.doc.scrollTop)) + { addToScrollTop(cm, diff) } +} + +function addLineWidget(doc, handle, node, options) { + var widget = new LineWidget(doc, node, options) + var cm = doc.cm + if (cm && widget.noHScroll) { cm.display.alignWidgets = true } + changeLine(doc, handle, "widget", function (line) { + var widgets = line.widgets || (line.widgets = []) + if (widget.insertAt == null) { widgets.push(widget) } + else { widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget) } + widget.line = line + if (cm && !lineIsHidden(doc, line)) { + var aboveVisible = heightAtLine(line) < doc.scrollTop + updateLineHeight(line, line.height + widgetHeight(widget)) + if (aboveVisible) { addToScrollTop(cm, widget.height) } + cm.curOp.forceUpdate = true + } + return true + }) + if (cm) { signalLater(cm, "lineWidgetAdded", cm, widget, typeof handle == "number" ? handle : lineNo(handle)) } + return widget +} + +// TEXTMARKERS + +// Created with markText and setBookmark methods. A TextMarker is a +// handle that can be used to clear or find a marked position in the +// document. Line objects hold arrays (markedSpans) containing +// {from, to, marker} object pointing to such marker objects, and +// indicating that such a marker is present on that line. Multiple +// lines may point to the same marker when it spans across lines. +// The spans will have null for their from/to properties when the +// marker continues beyond the start/end of the line. Markers have +// links back to the lines they currently touch. + +// Collapsed markers have unique ids, in order to be able to order +// them, which is needed for uniquely determining an outer marker +// when they overlap (they may nest, but not partially overlap). +var nextMarkerId = 0 + +var TextMarker = function(doc, type) { + this.lines = [] + this.type = type + this.doc = doc + this.id = ++nextMarkerId +}; + +// Clear the marker. +TextMarker.prototype.clear = function () { + var this$1 = this; + + if (this.explicitlyCleared) { return } + var cm = this.doc.cm, withOp = cm && !cm.curOp + if (withOp) { startOperation(cm) } + if (hasHandler(this, "clear")) { + var found = this.find() + if (found) { signalLater(this, "clear", found.from, found.to) } + } + var min = null, max = null + for (var i = 0; i < this.lines.length; ++i) { + var line = this$1.lines[i] + var span = getMarkedSpanFor(line.markedSpans, this$1) + if (cm && !this$1.collapsed) { regLineChange(cm, lineNo(line), "text") } + else if (cm) { + if (span.to != null) { max = lineNo(line) } + if (span.from != null) { min = lineNo(line) } + } + line.markedSpans = removeMarkedSpan(line.markedSpans, span) + if (span.from == null && this$1.collapsed && !lineIsHidden(this$1.doc, line) && cm) + { updateLineHeight(line, textHeight(cm.display)) } + } + if (cm && this.collapsed && !cm.options.lineWrapping) { for (var i$1 = 0; i$1 < this.lines.length; ++i$1) { + var visual = visualLine(this$1.lines[i$1]), len = lineLength(visual) + if (len > cm.display.maxLineLength) { + cm.display.maxLine = visual + cm.display.maxLineLength = len + cm.display.maxLineChanged = true + } + } } + + if (min != null && cm && this.collapsed) { regChange(cm, min, max + 1) } + this.lines.length = 0 + this.explicitlyCleared = true + if (this.atomic && this.doc.cantEdit) { + this.doc.cantEdit = false + if (cm) { reCheckSelection(cm.doc) } + } + if (cm) { signalLater(cm, "markerCleared", cm, this, min, max) } + if (withOp) { endOperation(cm) } + if (this.parent) { this.parent.clear() } +}; + +// Find the position of the marker in the document. Returns a {from, +// to} object by default. Side can be passed to get a specific side +// -- 0 (both), -1 (left), or 1 (right). When lineObj is true, the +// Pos objects returned contain a line object, rather than a line +// number (used to prevent looking up the same line twice). +TextMarker.prototype.find = function (side, lineObj) { + var this$1 = this; + + if (side == null && this.type == "bookmark") { side = 1 } + var from, to + for (var i = 0; i < this.lines.length; ++i) { + var line = this$1.lines[i] + var span = getMarkedSpanFor(line.markedSpans, this$1) + if (span.from != null) { + from = Pos(lineObj ? line : lineNo(line), span.from) + if (side == -1) { return from } + } + if (span.to != null) { + to = Pos(lineObj ? line : lineNo(line), span.to) + if (side == 1) { return to } + } + } + return from && {from: from, to: to} +}; + +// Signals that the marker's widget changed, and surrounding layout +// should be recomputed. +TextMarker.prototype.changed = function () { + var this$1 = this; + + var pos = this.find(-1, true), widget = this, cm = this.doc.cm + if (!pos || !cm) { return } + runInOp(cm, function () { + var line = pos.line, lineN = lineNo(pos.line) + var view = findViewForLine(cm, lineN) + if (view) { + clearLineMeasurementCacheFor(view) + cm.curOp.selectionChanged = cm.curOp.forceUpdate = true + } + cm.curOp.updateMaxLine = true + if (!lineIsHidden(widget.doc, line) && widget.height != null) { + var oldHeight = widget.height + widget.height = null + var dHeight = widgetHeight(widget) - oldHeight + if (dHeight) + { updateLineHeight(line, line.height + dHeight) } + } + signalLater(cm, "markerChanged", cm, this$1) + }) +}; + +TextMarker.prototype.attachLine = function (line) { + if (!this.lines.length && this.doc.cm) { + var op = this.doc.cm.curOp + if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1) + { (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this) } + } + this.lines.push(line) +}; + +TextMarker.prototype.detachLine = function (line) { + this.lines.splice(indexOf(this.lines, line), 1) + if (!this.lines.length && this.doc.cm) { + var op = this.doc.cm.curOp + ;(op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this) + } +}; +eventMixin(TextMarker) + +// Create a marker, wire it up to the right lines, and +function markText(doc, from, to, options, type) { + // Shared markers (across linked documents) are handled separately + // (markTextShared will call out to this again, once per + // document). + if (options && options.shared) { return markTextShared(doc, from, to, options, type) } + // Ensure we are in an operation. + if (doc.cm && !doc.cm.curOp) { return operation(doc.cm, markText)(doc, from, to, options, type) } + + var marker = new TextMarker(doc, type), diff = cmp(from, to) + if (options) { copyObj(options, marker, false) } + // Don't connect empty markers unless clearWhenEmpty is false + if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false) + { return marker } + if (marker.replacedWith) { + // Showing up as a widget implies collapsed (widget replaces text) + marker.collapsed = true + marker.widgetNode = eltP("span", [marker.replacedWith], "CodeMirror-widget") + if (!options.handleMouseEvents) { marker.widgetNode.setAttribute("cm-ignore-events", "true") } + if (options.insertLeft) { marker.widgetNode.insertLeft = true } + } + if (marker.collapsed) { + if (conflictingCollapsedRange(doc, from.line, from, to, marker) || + from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker)) + { throw new Error("Inserting collapsed marker partially overlapping an existing one") } + seeCollapsedSpans() + } + + if (marker.addToHistory) + { addChangeToHistory(doc, {from: from, to: to, origin: "markText"}, doc.sel, NaN) } + + var curLine = from.line, cm = doc.cm, updateMaxLine + doc.iter(curLine, to.line + 1, function (line) { + if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine) + { updateMaxLine = true } + if (marker.collapsed && curLine != from.line) { updateLineHeight(line, 0) } + addMarkedSpan(line, new MarkedSpan(marker, + curLine == from.line ? from.ch : null, + curLine == to.line ? to.ch : null)) + ++curLine + }) + // lineIsHidden depends on the presence of the spans, so needs a second pass + if (marker.collapsed) { doc.iter(from.line, to.line + 1, function (line) { + if (lineIsHidden(doc, line)) { updateLineHeight(line, 0) } + }) } + + if (marker.clearOnEnter) { on(marker, "beforeCursorEnter", function () { return marker.clear(); }) } + + if (marker.readOnly) { + seeReadOnlySpans() + if (doc.history.done.length || doc.history.undone.length) + { doc.clearHistory() } + } + if (marker.collapsed) { + marker.id = ++nextMarkerId + marker.atomic = true + } + if (cm) { + // Sync editor state + if (updateMaxLine) { cm.curOp.updateMaxLine = true } + if (marker.collapsed) + { regChange(cm, from.line, to.line + 1) } + else if (marker.className || marker.title || marker.startStyle || marker.endStyle || marker.css) + { for (var i = from.line; i <= to.line; i++) { regLineChange(cm, i, "text") } } + if (marker.atomic) { reCheckSelection(cm.doc) } + signalLater(cm, "markerAdded", cm, marker) + } + return marker +} + +// SHARED TEXTMARKERS + +// A shared marker spans multiple linked documents. It is +// implemented as a meta-marker-object controlling multiple normal +// markers. +var SharedTextMarker = function(markers, primary) { + var this$1 = this; + + this.markers = markers + this.primary = primary + for (var i = 0; i < markers.length; ++i) + { markers[i].parent = this$1 } +}; + +SharedTextMarker.prototype.clear = function () { + var this$1 = this; + + if (this.explicitlyCleared) { return } + this.explicitlyCleared = true + for (var i = 0; i < this.markers.length; ++i) + { this$1.markers[i].clear() } + signalLater(this, "clear") +}; + +SharedTextMarker.prototype.find = function (side, lineObj) { + return this.primary.find(side, lineObj) +}; +eventMixin(SharedTextMarker) + +function markTextShared(doc, from, to, options, type) { + options = copyObj(options) + options.shared = false + var markers = [markText(doc, from, to, options, type)], primary = markers[0] + var widget = options.widgetNode + linkedDocs(doc, function (doc) { + if (widget) { options.widgetNode = widget.cloneNode(true) } + markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type)) + for (var i = 0; i < doc.linked.length; ++i) + { if (doc.linked[i].isParent) { return } } + primary = lst(markers) + }) + return new SharedTextMarker(markers, primary) +} + +function findSharedMarkers(doc) { + return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())), function (m) { return m.parent; }) +} + +function copySharedMarkers(doc, markers) { + for (var i = 0; i < markers.length; i++) { + var marker = markers[i], pos = marker.find() + var mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to) + if (cmp(mFrom, mTo)) { + var subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type) + marker.markers.push(subMark) + subMark.parent = marker + } + } +} + +function detachSharedMarkers(markers) { + var loop = function ( i ) { + var marker = markers[i], linked = [marker.primary.doc] + linkedDocs(marker.primary.doc, function (d) { return linked.push(d); }) + for (var j = 0; j < marker.markers.length; j++) { + var subMarker = marker.markers[j] + if (indexOf(linked, subMarker.doc) == -1) { + subMarker.parent = null + marker.markers.splice(j--, 1) + } + } + }; + + for (var i = 0; i < markers.length; i++) loop( i ); +} + +var nextDocId = 0 +var Doc = function(text, mode, firstLine, lineSep, direction) { + if (!(this instanceof Doc)) { return new Doc(text, mode, firstLine, lineSep, direction) } + if (firstLine == null) { firstLine = 0 } + + BranchChunk.call(this, [new LeafChunk([new Line("", null)])]) + this.first = firstLine + this.scrollTop = this.scrollLeft = 0 + this.cantEdit = false + this.cleanGeneration = 1 + this.modeFrontier = this.highlightFrontier = firstLine + var start = Pos(firstLine, 0) + this.sel = simpleSelection(start) + this.history = new History(null) + this.id = ++nextDocId + this.modeOption = mode + this.lineSep = lineSep + this.direction = (direction == "rtl") ? "rtl" : "ltr" + this.extend = false + + if (typeof text == "string") { text = this.splitLines(text) } + updateDoc(this, {from: start, to: start, text: text}) + setSelection(this, simpleSelection(start), sel_dontScroll) +} + +Doc.prototype = createObj(BranchChunk.prototype, { + constructor: Doc, + // Iterate over the document. Supports two forms -- with only one + // argument, it calls that for each line in the document. With + // three, it iterates over the range given by the first two (with + // the second being non-inclusive). + iter: function(from, to, op) { + if (op) { this.iterN(from - this.first, to - from, op) } + else { this.iterN(this.first, this.first + this.size, from) } + }, + + // Non-public interface for adding and removing lines. + insert: function(at, lines) { + var height = 0 + for (var i = 0; i < lines.length; ++i) { height += lines[i].height } + this.insertInner(at - this.first, lines, height) + }, + remove: function(at, n) { this.removeInner(at - this.first, n) }, + + // From here, the methods are part of the public interface. Most + // are also available from CodeMirror (editor) instances. + + getValue: function(lineSep) { + var lines = getLines(this, this.first, this.first + this.size) + if (lineSep === false) { return lines } + return lines.join(lineSep || this.lineSeparator()) + }, + setValue: docMethodOp(function(code) { + var top = Pos(this.first, 0), last = this.first + this.size - 1 + makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length), + text: this.splitLines(code), origin: "setValue", full: true}, true) + if (this.cm) { scrollToCoords(this.cm, 0, 0) } + setSelection(this, simpleSelection(top), sel_dontScroll) + }), + replaceRange: function(code, from, to, origin) { + from = clipPos(this, from) + to = to ? clipPos(this, to) : from + replaceRange(this, code, from, to, origin) + }, + getRange: function(from, to, lineSep) { + var lines = getBetween(this, clipPos(this, from), clipPos(this, to)) + if (lineSep === false) { return lines } + return lines.join(lineSep || this.lineSeparator()) + }, + + getLine: function(line) {var l = this.getLineHandle(line); return l && l.text}, + + getLineHandle: function(line) {if (isLine(this, line)) { return getLine(this, line) }}, + getLineNumber: function(line) {return lineNo(line)}, + + getLineHandleVisualStart: function(line) { + if (typeof line == "number") { line = getLine(this, line) } + return visualLine(line) + }, + + lineCount: function() {return this.size}, + firstLine: function() {return this.first}, + lastLine: function() {return this.first + this.size - 1}, + + clipPos: function(pos) {return clipPos(this, pos)}, + + getCursor: function(start) { + var range = this.sel.primary(), pos + if (start == null || start == "head") { pos = range.head } + else if (start == "anchor") { pos = range.anchor } + else if (start == "end" || start == "to" || start === false) { pos = range.to() } + else { pos = range.from() } + return pos + }, + listSelections: function() { return this.sel.ranges }, + somethingSelected: function() {return this.sel.somethingSelected()}, + + setCursor: docMethodOp(function(line, ch, options) { + setSimpleSelection(this, clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : line), null, options) + }), + setSelection: docMethodOp(function(anchor, head, options) { + setSimpleSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), options) + }), + extendSelection: docMethodOp(function(head, other, options) { + extendSelection(this, clipPos(this, head), other && clipPos(this, other), options) + }), + extendSelections: docMethodOp(function(heads, options) { + extendSelections(this, clipPosArray(this, heads), options) + }), + extendSelectionsBy: docMethodOp(function(f, options) { + var heads = map(this.sel.ranges, f) + extendSelections(this, clipPosArray(this, heads), options) + }), + setSelections: docMethodOp(function(ranges, primary, options) { + var this$1 = this; + + if (!ranges.length) { return } + var out = [] + for (var i = 0; i < ranges.length; i++) + { out[i] = new Range(clipPos(this$1, ranges[i].anchor), + clipPos(this$1, ranges[i].head)) } + if (primary == null) { primary = Math.min(ranges.length - 1, this.sel.primIndex) } + setSelection(this, normalizeSelection(out, primary), options) + }), + addSelection: docMethodOp(function(anchor, head, options) { + var ranges = this.sel.ranges.slice(0) + ranges.push(new Range(clipPos(this, anchor), clipPos(this, head || anchor))) + setSelection(this, normalizeSelection(ranges, ranges.length - 1), options) + }), + + getSelection: function(lineSep) { + var this$1 = this; + + var ranges = this.sel.ranges, lines + for (var i = 0; i < ranges.length; i++) { + var sel = getBetween(this$1, ranges[i].from(), ranges[i].to()) + lines = lines ? lines.concat(sel) : sel + } + if (lineSep === false) { return lines } + else { return lines.join(lineSep || this.lineSeparator()) } + }, + getSelections: function(lineSep) { + var this$1 = this; + + var parts = [], ranges = this.sel.ranges + for (var i = 0; i < ranges.length; i++) { + var sel = getBetween(this$1, ranges[i].from(), ranges[i].to()) + if (lineSep !== false) { sel = sel.join(lineSep || this$1.lineSeparator()) } + parts[i] = sel + } + return parts + }, + replaceSelection: function(code, collapse, origin) { + var dup = [] + for (var i = 0; i < this.sel.ranges.length; i++) + { dup[i] = code } + this.replaceSelections(dup, collapse, origin || "+input") + }, + replaceSelections: docMethodOp(function(code, collapse, origin) { + var this$1 = this; + + var changes = [], sel = this.sel + for (var i = 0; i < sel.ranges.length; i++) { + var range = sel.ranges[i] + changes[i] = {from: range.from(), to: range.to(), text: this$1.splitLines(code[i]), origin: origin} + } + var newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse) + for (var i$1 = changes.length - 1; i$1 >= 0; i$1--) + { makeChange(this$1, changes[i$1]) } + if (newSel) { setSelectionReplaceHistory(this, newSel) } + else if (this.cm) { ensureCursorVisible(this.cm) } + }), + undo: docMethodOp(function() {makeChangeFromHistory(this, "undo")}), + redo: docMethodOp(function() {makeChangeFromHistory(this, "redo")}), + undoSelection: docMethodOp(function() {makeChangeFromHistory(this, "undo", true)}), + redoSelection: docMethodOp(function() {makeChangeFromHistory(this, "redo", true)}), + + setExtending: function(val) {this.extend = val}, + getExtending: function() {return this.extend}, + + historySize: function() { + var hist = this.history, done = 0, undone = 0 + for (var i = 0; i < hist.done.length; i++) { if (!hist.done[i].ranges) { ++done } } + for (var i$1 = 0; i$1 < hist.undone.length; i$1++) { if (!hist.undone[i$1].ranges) { ++undone } } + return {undo: done, redo: undone} + }, + clearHistory: function() {this.history = new History(this.history.maxGeneration)}, + + markClean: function() { + this.cleanGeneration = this.changeGeneration(true) + }, + changeGeneration: function(forceSplit) { + if (forceSplit) + { this.history.lastOp = this.history.lastSelOp = this.history.lastOrigin = null } + return this.history.generation + }, + isClean: function (gen) { + return this.history.generation == (gen || this.cleanGeneration) + }, + + getHistory: function() { + return {done: copyHistoryArray(this.history.done), + undone: copyHistoryArray(this.history.undone)} + }, + setHistory: function(histData) { + var hist = this.history = new History(this.history.maxGeneration) + hist.done = copyHistoryArray(histData.done.slice(0), null, true) + hist.undone = copyHistoryArray(histData.undone.slice(0), null, true) + }, + + setGutterMarker: docMethodOp(function(line, gutterID, value) { + return changeLine(this, line, "gutter", function (line) { + var markers = line.gutterMarkers || (line.gutterMarkers = {}) + markers[gutterID] = value + if (!value && isEmpty(markers)) { line.gutterMarkers = null } + return true + }) + }), + + clearGutter: docMethodOp(function(gutterID) { + var this$1 = this; + + this.iter(function (line) { + if (line.gutterMarkers && line.gutterMarkers[gutterID]) { + changeLine(this$1, line, "gutter", function () { + line.gutterMarkers[gutterID] = null + if (isEmpty(line.gutterMarkers)) { line.gutterMarkers = null } + return true + }) + } + }) + }), + + lineInfo: function(line) { + var n + if (typeof line == "number") { + if (!isLine(this, line)) { return null } + n = line + line = getLine(this, line) + if (!line) { return null } + } else { + n = lineNo(line) + if (n == null) { return null } + } + return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers, + textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass, + widgets: line.widgets} + }, + + addLineClass: docMethodOp(function(handle, where, cls) { + return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function (line) { + var prop = where == "text" ? "textClass" + : where == "background" ? "bgClass" + : where == "gutter" ? "gutterClass" : "wrapClass" + if (!line[prop]) { line[prop] = cls } + else if (classTest(cls).test(line[prop])) { return false } + else { line[prop] += " " + cls } + return true + }) + }), + removeLineClass: docMethodOp(function(handle, where, cls) { + return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function (line) { + var prop = where == "text" ? "textClass" + : where == "background" ? "bgClass" + : where == "gutter" ? "gutterClass" : "wrapClass" + var cur = line[prop] + if (!cur) { return false } + else if (cls == null) { line[prop] = null } + else { + var found = cur.match(classTest(cls)) + if (!found) { return false } + var end = found.index + found[0].length + line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? "" : " ") + cur.slice(end) || null + } + return true + }) + }), + + addLineWidget: docMethodOp(function(handle, node, options) { + return addLineWidget(this, handle, node, options) + }), + removeLineWidget: function(widget) { widget.clear() }, + + markText: function(from, to, options) { + return markText(this, clipPos(this, from), clipPos(this, to), options, options && options.type || "range") + }, + setBookmark: function(pos, options) { + var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options), + insertLeft: options && options.insertLeft, + clearWhenEmpty: false, shared: options && options.shared, + handleMouseEvents: options && options.handleMouseEvents} + pos = clipPos(this, pos) + return markText(this, pos, pos, realOpts, "bookmark") + }, + findMarksAt: function(pos) { + pos = clipPos(this, pos) + var markers = [], spans = getLine(this, pos.line).markedSpans + if (spans) { for (var i = 0; i < spans.length; ++i) { + var span = spans[i] + if ((span.from == null || span.from <= pos.ch) && + (span.to == null || span.to >= pos.ch)) + { markers.push(span.marker.parent || span.marker) } + } } + return markers + }, + findMarks: function(from, to, filter) { + from = clipPos(this, from); to = clipPos(this, to) + var found = [], lineNo = from.line + this.iter(from.line, to.line + 1, function (line) { + var spans = line.markedSpans + if (spans) { for (var i = 0; i < spans.length; i++) { + var span = spans[i] + if (!(span.to != null && lineNo == from.line && from.ch >= span.to || + span.from == null && lineNo != from.line || + span.from != null && lineNo == to.line && span.from >= to.ch) && + (!filter || filter(span.marker))) + { found.push(span.marker.parent || span.marker) } + } } + ++lineNo + }) + return found + }, + getAllMarks: function() { + var markers = [] + this.iter(function (line) { + var sps = line.markedSpans + if (sps) { for (var i = 0; i < sps.length; ++i) + { if (sps[i].from != null) { markers.push(sps[i].marker) } } } + }) + return markers + }, + + posFromIndex: function(off) { + var ch, lineNo = this.first, sepSize = this.lineSeparator().length + this.iter(function (line) { + var sz = line.text.length + sepSize + if (sz > off) { ch = off; return true } + off -= sz + ++lineNo + }) + return clipPos(this, Pos(lineNo, ch)) + }, + indexFromPos: function (coords) { + coords = clipPos(this, coords) + var index = coords.ch + if (coords.line < this.first || coords.ch < 0) { return 0 } + var sepSize = this.lineSeparator().length + this.iter(this.first, coords.line, function (line) { // iter aborts when callback returns a truthy value + index += line.text.length + sepSize + }) + return index + }, + + copy: function(copyHistory) { + var doc = new Doc(getLines(this, this.first, this.first + this.size), + this.modeOption, this.first, this.lineSep, this.direction) + doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft + doc.sel = this.sel + doc.extend = false + if (copyHistory) { + doc.history.undoDepth = this.history.undoDepth + doc.setHistory(this.getHistory()) + } + return doc + }, + + linkedDoc: function(options) { + if (!options) { options = {} } + var from = this.first, to = this.first + this.size + if (options.from != null && options.from > from) { from = options.from } + if (options.to != null && options.to < to) { to = options.to } + var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from, this.lineSep, this.direction) + if (options.sharedHist) { copy.history = this.history + ; }(this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist}) + copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}] + copySharedMarkers(copy, findSharedMarkers(this)) + return copy + }, + unlinkDoc: function(other) { + var this$1 = this; + + if (other instanceof CodeMirror) { other = other.doc } + if (this.linked) { for (var i = 0; i < this.linked.length; ++i) { + var link = this$1.linked[i] + if (link.doc != other) { continue } + this$1.linked.splice(i, 1) + other.unlinkDoc(this$1) + detachSharedMarkers(findSharedMarkers(this$1)) + break + } } + // If the histories were shared, split them again + if (other.history == this.history) { + var splitIds = [other.id] + linkedDocs(other, function (doc) { return splitIds.push(doc.id); }, true) + other.history = new History(null) + other.history.done = copyHistoryArray(this.history.done, splitIds) + other.history.undone = copyHistoryArray(this.history.undone, splitIds) + } + }, + iterLinkedDocs: function(f) {linkedDocs(this, f)}, + + getMode: function() {return this.mode}, + getEditor: function() {return this.cm}, + + splitLines: function(str) { + if (this.lineSep) { return str.split(this.lineSep) } + return splitLinesAuto(str) + }, + lineSeparator: function() { return this.lineSep || "\n" }, + + setDirection: docMethodOp(function (dir) { + if (dir != "rtl") { dir = "ltr" } + if (dir == this.direction) { return } + this.direction = dir + this.iter(function (line) { return line.order = null; }) + if (this.cm) { directionChanged(this.cm) } + }) +}) + +// Public alias. +Doc.prototype.eachLine = Doc.prototype.iter + +// Kludge to work around strange IE behavior where it'll sometimes +// re-fire a series of drag-related events right after the drop (#1551) +var lastDrop = 0 + +function onDrop(e) { + var cm = this + clearDragCursor(cm) + if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) + { return } + e_preventDefault(e) + if (ie) { lastDrop = +new Date } + var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files + if (!pos || cm.isReadOnly()) { return } + // Might be a file drop, in which case we simply extract the text + // and insert it. + if (files && files.length && window.FileReader && window.File) { + var n = files.length, text = Array(n), read = 0 + var loadFile = function (file, i) { + if (cm.options.allowDropFileTypes && + indexOf(cm.options.allowDropFileTypes, file.type) == -1) + { return } + + var reader = new FileReader + reader.onload = operation(cm, function () { + var content = reader.result + if (/[\x00-\x08\x0e-\x1f]{2}/.test(content)) { content = "" } + text[i] = content + if (++read == n) { + pos = clipPos(cm.doc, pos) + var change = {from: pos, to: pos, + text: cm.doc.splitLines(text.join(cm.doc.lineSeparator())), + origin: "paste"} + makeChange(cm.doc, change) + setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change))) + } + }) + reader.readAsText(file) + } + for (var i = 0; i < n; ++i) { loadFile(files[i], i) } + } else { // Normal drop + // Don't do a replace if the drop happened inside of the selected text. + if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) { + cm.state.draggingText(e) + // Ensure the editor is re-focused + setTimeout(function () { return cm.display.input.focus(); }, 20) + return + } + try { + var text$1 = e.dataTransfer.getData("Text") + if (text$1) { + var selected + if (cm.state.draggingText && !cm.state.draggingText.copy) + { selected = cm.listSelections() } + setSelectionNoUndo(cm.doc, simpleSelection(pos, pos)) + if (selected) { for (var i$1 = 0; i$1 < selected.length; ++i$1) + { replaceRange(cm.doc, "", selected[i$1].anchor, selected[i$1].head, "drag") } } + cm.replaceSelection(text$1, "around", "paste") + cm.display.input.focus() + } + } + catch(e){} + } +} + +function onDragStart(cm, e) { + if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return } + if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) { return } + + e.dataTransfer.setData("Text", cm.getSelection()) + e.dataTransfer.effectAllowed = "copyMove" + + // Use dummy image instead of default browsers image. + // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there. + if (e.dataTransfer.setDragImage && !safari) { + var img = elt("img", null, null, "position: fixed; left: 0; top: 0;") + img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" + if (presto) { + img.width = img.height = 1 + cm.display.wrapper.appendChild(img) + // Force a relayout, or Opera won't use our image for some obscure reason + img._top = img.offsetTop + } + e.dataTransfer.setDragImage(img, 0, 0) + if (presto) { img.parentNode.removeChild(img) } + } +} + +function onDragOver(cm, e) { + var pos = posFromMouse(cm, e) + if (!pos) { return } + var frag = document.createDocumentFragment() + drawSelectionCursor(cm, pos, frag) + if (!cm.display.dragCursor) { + cm.display.dragCursor = elt("div", null, "CodeMirror-cursors CodeMirror-dragcursors") + cm.display.lineSpace.insertBefore(cm.display.dragCursor, cm.display.cursorDiv) + } + removeChildrenAndAdd(cm.display.dragCursor, frag) +} + +function clearDragCursor(cm) { + if (cm.display.dragCursor) { + cm.display.lineSpace.removeChild(cm.display.dragCursor) + cm.display.dragCursor = null + } +} + +// These must be handled carefully, because naively registering a +// handler for each editor will cause the editors to never be +// garbage collected. + +function forEachCodeMirror(f) { + if (!document.getElementsByClassName) { return } + var byClass = document.getElementsByClassName("CodeMirror") + for (var i = 0; i < byClass.length; i++) { + var cm = byClass[i].CodeMirror + if (cm) { f(cm) } + } +} + +var globalsRegistered = false +function ensureGlobalHandlers() { + if (globalsRegistered) { return } + registerGlobalHandlers() + globalsRegistered = true +} +function registerGlobalHandlers() { + // When the window resizes, we need to refresh active editors. + var resizeTimer + on(window, "resize", function () { + if (resizeTimer == null) { resizeTimer = setTimeout(function () { + resizeTimer = null + forEachCodeMirror(onResize) + }, 100) } + }) + // When the window loses focus, we want to show the editor as blurred + on(window, "blur", function () { return forEachCodeMirror(onBlur); }) +} +// Called when the window resizes +function onResize(cm) { + var d = cm.display + // Might be a text scaling operation, clear size caches. + d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null + d.scrollbarsClipped = false + cm.setSize() +} + +var keyNames = { + 3: "Pause", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt", + 19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End", + 36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert", + 46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod", + 106: "*", 107: "=", 109: "-", 110: ".", 111: "/", 127: "Delete", 145: "ScrollLock", + 173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\", + 221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete", + 63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert" +} + +// Number keys +for (var i = 0; i < 10; i++) { keyNames[i + 48] = keyNames[i + 96] = String(i) } +// Alphabetic keys +for (var i$1 = 65; i$1 <= 90; i$1++) { keyNames[i$1] = String.fromCharCode(i$1) } +// Function keys +for (var i$2 = 1; i$2 <= 12; i$2++) { keyNames[i$2 + 111] = keyNames[i$2 + 63235] = "F" + i$2 } + +var keyMap = {} + +keyMap.basic = { + "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown", + "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown", + "Delete": "delCharAfter", "Backspace": "delCharBefore", "Shift-Backspace": "delCharBefore", + "Tab": "defaultTab", "Shift-Tab": "indentAuto", + "Enter": "newlineAndIndent", "Insert": "toggleOverwrite", + "Esc": "singleSelection" +} +// Note that the save and find-related commands aren't defined by +// default. User code or addons can define them. Unknown commands +// are simply ignored. +keyMap.pcDefault = { + "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo", + "Ctrl-Home": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Up": "goLineUp", "Ctrl-Down": "goLineDown", + "Ctrl-Left": "goGroupLeft", "Ctrl-Right": "goGroupRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd", + "Ctrl-Backspace": "delGroupBefore", "Ctrl-Delete": "delGroupAfter", "Ctrl-S": "save", "Ctrl-F": "find", + "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll", + "Ctrl-[": "indentLess", "Ctrl-]": "indentMore", + "Ctrl-U": "undoSelection", "Shift-Ctrl-U": "redoSelection", "Alt-U": "redoSelection", + "fallthrough": "basic" +} +// Very basic readline/emacs-style bindings, which are standard on Mac. +keyMap.emacsy = { + "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown", + "Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd", + "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore", + "Alt-D": "delWordAfter", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars", + "Ctrl-O": "openLine" +} +keyMap.macDefault = { + "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo", + "Cmd-Home": "goDocStart", "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft", + "Alt-Right": "goGroupRight", "Cmd-Left": "goLineLeft", "Cmd-Right": "goLineRight", "Alt-Backspace": "delGroupBefore", + "Ctrl-Alt-Backspace": "delGroupAfter", "Alt-Delete": "delGroupAfter", "Cmd-S": "save", "Cmd-F": "find", + "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll", + "Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delWrappedLineLeft", "Cmd-Delete": "delWrappedLineRight", + "Cmd-U": "undoSelection", "Shift-Cmd-U": "redoSelection", "Ctrl-Up": "goDocStart", "Ctrl-Down": "goDocEnd", + "fallthrough": ["basic", "emacsy"] +} +keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault + +// KEYMAP DISPATCH + +function normalizeKeyName(name) { + var parts = name.split(/-(?!$)/) + name = parts[parts.length - 1] + var alt, ctrl, shift, cmd + for (var i = 0; i < parts.length - 1; i++) { + var mod = parts[i] + if (/^(cmd|meta|m)$/i.test(mod)) { cmd = true } + else if (/^a(lt)?$/i.test(mod)) { alt = true } + else if (/^(c|ctrl|control)$/i.test(mod)) { ctrl = true } + else if (/^s(hift)?$/i.test(mod)) { shift = true } + else { throw new Error("Unrecognized modifier name: " + mod) } + } + if (alt) { name = "Alt-" + name } + if (ctrl) { name = "Ctrl-" + name } + if (cmd) { name = "Cmd-" + name } + if (shift) { name = "Shift-" + name } + return name +} + +// This is a kludge to keep keymaps mostly working as raw objects +// (backwards compatibility) while at the same time support features +// like normalization and multi-stroke key bindings. It compiles a +// new normalized keymap, and then updates the old object to reflect +// this. +function normalizeKeyMap(keymap) { + var copy = {} + for (var keyname in keymap) { if (keymap.hasOwnProperty(keyname)) { + var value = keymap[keyname] + if (/^(name|fallthrough|(de|at)tach)$/.test(keyname)) { continue } + if (value == "...") { delete keymap[keyname]; continue } + + var keys = map(keyname.split(" "), normalizeKeyName) + for (var i = 0; i < keys.length; i++) { + var val = (void 0), name = (void 0) + if (i == keys.length - 1) { + name = keys.join(" ") + val = value + } else { + name = keys.slice(0, i + 1).join(" ") + val = "..." + } + var prev = copy[name] + if (!prev) { copy[name] = val } + else if (prev != val) { throw new Error("Inconsistent bindings for " + name) } + } + delete keymap[keyname] + } } + for (var prop in copy) { keymap[prop] = copy[prop] } + return keymap +} + +function lookupKey(key, map, handle, context) { + map = getKeyMap(map) + var found = map.call ? map.call(key, context) : map[key] + if (found === false) { return "nothing" } + if (found === "...") { return "multi" } + if (found != null && handle(found)) { return "handled" } + + if (map.fallthrough) { + if (Object.prototype.toString.call(map.fallthrough) != "[object Array]") + { return lookupKey(key, map.fallthrough, handle, context) } + for (var i = 0; i < map.fallthrough.length; i++) { + var result = lookupKey(key, map.fallthrough[i], handle, context) + if (result) { return result } + } + } +} + +// Modifier key presses don't count as 'real' key presses for the +// purpose of keymap fallthrough. +function isModifierKey(value) { + var name = typeof value == "string" ? value : keyNames[value.keyCode] + return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod" +} + +function addModifierNames(name, event, noShift) { + var base = name + if (event.altKey && base != "Alt") { name = "Alt-" + name } + if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != "Ctrl") { name = "Ctrl-" + name } + if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != "Cmd") { name = "Cmd-" + name } + if (!noShift && event.shiftKey && base != "Shift") { name = "Shift-" + name } + return name +} + +// Look up the name of a key as indicated by an event object. +function keyName(event, noShift) { + if (presto && event.keyCode == 34 && event["char"]) { return false } + var name = keyNames[event.keyCode] + if (name == null || event.altGraphKey) { return false } + // Ctrl-ScrollLock has keyCode 3, same as Ctrl-Pause, + // so we'll use event.code when available (Chrome 48+, FF 38+, Safari 10.1+) + if (event.keyCode == 3 && event.code) { name = event.code } + return addModifierNames(name, event, noShift) +} + +function getKeyMap(val) { + return typeof val == "string" ? keyMap[val] : val +} + +// Helper for deleting text near the selection(s), used to implement +// backspace, delete, and similar functionality. +function deleteNearSelection(cm, compute) { + var ranges = cm.doc.sel.ranges, kill = [] + // Build up a set of ranges to kill first, merging overlapping + // ranges. + for (var i = 0; i < ranges.length; i++) { + var toKill = compute(ranges[i]) + while (kill.length && cmp(toKill.from, lst(kill).to) <= 0) { + var replaced = kill.pop() + if (cmp(replaced.from, toKill.from) < 0) { + toKill.from = replaced.from + break + } + } + kill.push(toKill) + } + // Next, remove those actual ranges. + runInOp(cm, function () { + for (var i = kill.length - 1; i >= 0; i--) + { replaceRange(cm.doc, "", kill[i].from, kill[i].to, "+delete") } + ensureCursorVisible(cm) + }) +} + +function moveCharLogically(line, ch, dir) { + var target = skipExtendingChars(line.text, ch + dir, dir) + return target < 0 || target > line.text.length ? null : target +} + +function moveLogically(line, start, dir) { + var ch = moveCharLogically(line, start.ch, dir) + return ch == null ? null : new Pos(start.line, ch, dir < 0 ? "after" : "before") +} + +function endOfLine(visually, cm, lineObj, lineNo, dir) { + if (visually) { + var order = getOrder(lineObj, cm.doc.direction) + if (order) { + var part = dir < 0 ? lst(order) : order[0] + var moveInStorageOrder = (dir < 0) == (part.level == 1) + var sticky = moveInStorageOrder ? "after" : "before" + var ch + // With a wrapped rtl chunk (possibly spanning multiple bidi parts), + // it could be that the last bidi part is not on the last visual line, + // since visual lines contain content order-consecutive chunks. + // Thus, in rtl, we are looking for the first (content-order) character + // in the rtl chunk that is on the last line (that is, the same line + // as the last (content-order) character). + if (part.level > 0 || cm.doc.direction == "rtl") { + var prep = prepareMeasureForLine(cm, lineObj) + ch = dir < 0 ? lineObj.text.length - 1 : 0 + var targetTop = measureCharPrepared(cm, prep, ch).top + ch = findFirst(function (ch) { return measureCharPrepared(cm, prep, ch).top == targetTop; }, (dir < 0) == (part.level == 1) ? part.from : part.to - 1, ch) + if (sticky == "before") { ch = moveCharLogically(lineObj, ch, 1) } + } else { ch = dir < 0 ? part.to : part.from } + return new Pos(lineNo, ch, sticky) + } + } + return new Pos(lineNo, dir < 0 ? lineObj.text.length : 0, dir < 0 ? "before" : "after") +} + +function moveVisually(cm, line, start, dir) { + var bidi = getOrder(line, cm.doc.direction) + if (!bidi) { return moveLogically(line, start, dir) } + if (start.ch >= line.text.length) { + start.ch = line.text.length + start.sticky = "before" + } else if (start.ch <= 0) { + start.ch = 0 + start.sticky = "after" + } + var partPos = getBidiPartAt(bidi, start.ch, start.sticky), part = bidi[partPos] + if (cm.doc.direction == "ltr" && part.level % 2 == 0 && (dir > 0 ? part.to > start.ch : part.from < start.ch)) { + // Case 1: We move within an ltr part in an ltr editor. Even with wrapped lines, + // nothing interesting happens. + return moveLogically(line, start, dir) + } + + var mv = function (pos, dir) { return moveCharLogically(line, pos instanceof Pos ? pos.ch : pos, dir); } + var prep + var getWrappedLineExtent = function (ch) { + if (!cm.options.lineWrapping) { return {begin: 0, end: line.text.length} } + prep = prep || prepareMeasureForLine(cm, line) + return wrappedLineExtentChar(cm, line, prep, ch) + } + var wrappedLineExtent = getWrappedLineExtent(start.sticky == "before" ? mv(start, -1) : start.ch) + + if (cm.doc.direction == "rtl" || part.level == 1) { + var moveInStorageOrder = (part.level == 1) == (dir < 0) + var ch = mv(start, moveInStorageOrder ? 1 : -1) + if (ch != null && (!moveInStorageOrder ? ch >= part.from && ch >= wrappedLineExtent.begin : ch <= part.to && ch <= wrappedLineExtent.end)) { + // Case 2: We move within an rtl part or in an rtl editor on the same visual line + var sticky = moveInStorageOrder ? "before" : "after" + return new Pos(start.line, ch, sticky) + } + } + + // Case 3: Could not move within this bidi part in this visual line, so leave + // the current bidi part + + var searchInVisualLine = function (partPos, dir, wrappedLineExtent) { + var getRes = function (ch, moveInStorageOrder) { return moveInStorageOrder + ? new Pos(start.line, mv(ch, 1), "before") + : new Pos(start.line, ch, "after"); } + + for (; partPos >= 0 && partPos < bidi.length; partPos += dir) { + var part = bidi[partPos] + var moveInStorageOrder = (dir > 0) == (part.level != 1) + var ch = moveInStorageOrder ? wrappedLineExtent.begin : mv(wrappedLineExtent.end, -1) + if (part.from <= ch && ch < part.to) { return getRes(ch, moveInStorageOrder) } + ch = moveInStorageOrder ? part.from : mv(part.to, -1) + if (wrappedLineExtent.begin <= ch && ch < wrappedLineExtent.end) { return getRes(ch, moveInStorageOrder) } + } + } + + // Case 3a: Look for other bidi parts on the same visual line + var res = searchInVisualLine(partPos + dir, dir, wrappedLineExtent) + if (res) { return res } + + // Case 3b: Look for other bidi parts on the next visual line + var nextCh = dir > 0 ? wrappedLineExtent.end : mv(wrappedLineExtent.begin, -1) + if (nextCh != null && !(dir > 0 && nextCh == line.text.length)) { + res = searchInVisualLine(dir > 0 ? 0 : bidi.length - 1, dir, getWrappedLineExtent(nextCh)) + if (res) { return res } + } + + // Case 4: Nowhere to move + return null +} + +// Commands are parameter-less actions that can be performed on an +// editor, mostly used for keybindings. +var commands = { + selectAll: selectAll, + singleSelection: function (cm) { return cm.setSelection(cm.getCursor("anchor"), cm.getCursor("head"), sel_dontScroll); }, + killLine: function (cm) { return deleteNearSelection(cm, function (range) { + if (range.empty()) { + var len = getLine(cm.doc, range.head.line).text.length + if (range.head.ch == len && range.head.line < cm.lastLine()) + { return {from: range.head, to: Pos(range.head.line + 1, 0)} } + else + { return {from: range.head, to: Pos(range.head.line, len)} } + } else { + return {from: range.from(), to: range.to()} + } + }); }, + deleteLine: function (cm) { return deleteNearSelection(cm, function (range) { return ({ + from: Pos(range.from().line, 0), + to: clipPos(cm.doc, Pos(range.to().line + 1, 0)) + }); }); }, + delLineLeft: function (cm) { return deleteNearSelection(cm, function (range) { return ({ + from: Pos(range.from().line, 0), to: range.from() + }); }); }, + delWrappedLineLeft: function (cm) { return deleteNearSelection(cm, function (range) { + var top = cm.charCoords(range.head, "div").top + 5 + var leftPos = cm.coordsChar({left: 0, top: top}, "div") + return {from: leftPos, to: range.from()} + }); }, + delWrappedLineRight: function (cm) { return deleteNearSelection(cm, function (range) { + var top = cm.charCoords(range.head, "div").top + 5 + var rightPos = cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div") + return {from: range.from(), to: rightPos } + }); }, + undo: function (cm) { return cm.undo(); }, + redo: function (cm) { return cm.redo(); }, + undoSelection: function (cm) { return cm.undoSelection(); }, + redoSelection: function (cm) { return cm.redoSelection(); }, + goDocStart: function (cm) { return cm.extendSelection(Pos(cm.firstLine(), 0)); }, + goDocEnd: function (cm) { return cm.extendSelection(Pos(cm.lastLine())); }, + goLineStart: function (cm) { return cm.extendSelectionsBy(function (range) { return lineStart(cm, range.head.line); }, + {origin: "+move", bias: 1} + ); }, + goLineStartSmart: function (cm) { return cm.extendSelectionsBy(function (range) { return lineStartSmart(cm, range.head); }, + {origin: "+move", bias: 1} + ); }, + goLineEnd: function (cm) { return cm.extendSelectionsBy(function (range) { return lineEnd(cm, range.head.line); }, + {origin: "+move", bias: -1} + ); }, + goLineRight: function (cm) { return cm.extendSelectionsBy(function (range) { + var top = cm.cursorCoords(range.head, "div").top + 5 + return cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div") + }, sel_move); }, + goLineLeft: function (cm) { return cm.extendSelectionsBy(function (range) { + var top = cm.cursorCoords(range.head, "div").top + 5 + return cm.coordsChar({left: 0, top: top}, "div") + }, sel_move); }, + goLineLeftSmart: function (cm) { return cm.extendSelectionsBy(function (range) { + var top = cm.cursorCoords(range.head, "div").top + 5 + var pos = cm.coordsChar({left: 0, top: top}, "div") + if (pos.ch < cm.getLine(pos.line).search(/\S/)) { return lineStartSmart(cm, range.head) } + return pos + }, sel_move); }, + goLineUp: function (cm) { return cm.moveV(-1, "line"); }, + goLineDown: function (cm) { return cm.moveV(1, "line"); }, + goPageUp: function (cm) { return cm.moveV(-1, "page"); }, + goPageDown: function (cm) { return cm.moveV(1, "page"); }, + goCharLeft: function (cm) { return cm.moveH(-1, "char"); }, + goCharRight: function (cm) { return cm.moveH(1, "char"); }, + goColumnLeft: function (cm) { return cm.moveH(-1, "column"); }, + goColumnRight: function (cm) { return cm.moveH(1, "column"); }, + goWordLeft: function (cm) { return cm.moveH(-1, "word"); }, + goGroupRight: function (cm) { return cm.moveH(1, "group"); }, + goGroupLeft: function (cm) { return cm.moveH(-1, "group"); }, + goWordRight: function (cm) { return cm.moveH(1, "word"); }, + delCharBefore: function (cm) { return cm.deleteH(-1, "char"); }, + delCharAfter: function (cm) { return cm.deleteH(1, "char"); }, + delWordBefore: function (cm) { return cm.deleteH(-1, "word"); }, + delWordAfter: function (cm) { return cm.deleteH(1, "word"); }, + delGroupBefore: function (cm) { return cm.deleteH(-1, "group"); }, + delGroupAfter: function (cm) { return cm.deleteH(1, "group"); }, + indentAuto: function (cm) { return cm.indentSelection("smart"); }, + indentMore: function (cm) { return cm.indentSelection("add"); }, + indentLess: function (cm) { return cm.indentSelection("subtract"); }, + insertTab: function (cm) { return cm.replaceSelection("\t"); }, + insertSoftTab: function (cm) { + var spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize + for (var i = 0; i < ranges.length; i++) { + var pos = ranges[i].from() + var col = countColumn(cm.getLine(pos.line), pos.ch, tabSize) + spaces.push(spaceStr(tabSize - col % tabSize)) + } + cm.replaceSelections(spaces) + }, + defaultTab: function (cm) { + if (cm.somethingSelected()) { cm.indentSelection("add") } + else { cm.execCommand("insertTab") } + }, + // Swap the two chars left and right of each selection's head. + // Move cursor behind the two swapped characters afterwards. + // + // Doesn't consider line feeds a character. + // Doesn't scan more than one line above to find a character. + // Doesn't do anything on an empty line. + // Doesn't do anything with non-empty selections. + transposeChars: function (cm) { return runInOp(cm, function () { + var ranges = cm.listSelections(), newSel = [] + for (var i = 0; i < ranges.length; i++) { + if (!ranges[i].empty()) { continue } + var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text + if (line) { + if (cur.ch == line.length) { cur = new Pos(cur.line, cur.ch - 1) } + if (cur.ch > 0) { + cur = new Pos(cur.line, cur.ch + 1) + cm.replaceRange(line.charAt(cur.ch - 1) + line.charAt(cur.ch - 2), + Pos(cur.line, cur.ch - 2), cur, "+transpose") + } else if (cur.line > cm.doc.first) { + var prev = getLine(cm.doc, cur.line - 1).text + if (prev) { + cur = new Pos(cur.line, 1) + cm.replaceRange(line.charAt(0) + cm.doc.lineSeparator() + + prev.charAt(prev.length - 1), + Pos(cur.line - 1, prev.length - 1), cur, "+transpose") + } + } + } + newSel.push(new Range(cur, cur)) + } + cm.setSelections(newSel) + }); }, + newlineAndIndent: function (cm) { return runInOp(cm, function () { + var sels = cm.listSelections() + for (var i = sels.length - 1; i >= 0; i--) + { cm.replaceRange(cm.doc.lineSeparator(), sels[i].anchor, sels[i].head, "+input") } + sels = cm.listSelections() + for (var i$1 = 0; i$1 < sels.length; i$1++) + { cm.indentLine(sels[i$1].from().line, null, true) } + ensureCursorVisible(cm) + }); }, + openLine: function (cm) { return cm.replaceSelection("\n", "start"); }, + toggleOverwrite: function (cm) { return cm.toggleOverwrite(); } +} + + +function lineStart(cm, lineN) { + var line = getLine(cm.doc, lineN) + var visual = visualLine(line) + if (visual != line) { lineN = lineNo(visual) } + return endOfLine(true, cm, visual, lineN, 1) +} +function lineEnd(cm, lineN) { + var line = getLine(cm.doc, lineN) + var visual = visualLineEnd(line) + if (visual != line) { lineN = lineNo(visual) } + return endOfLine(true, cm, line, lineN, -1) +} +function lineStartSmart(cm, pos) { + var start = lineStart(cm, pos.line) + var line = getLine(cm.doc, start.line) + var order = getOrder(line, cm.doc.direction) + if (!order || order[0].level == 0) { + var firstNonWS = Math.max(0, line.text.search(/\S/)) + var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch + return Pos(start.line, inWS ? 0 : firstNonWS, start.sticky) + } + return start +} + +// Run a handler that was bound to a key. +function doHandleBinding(cm, bound, dropShift) { + if (typeof bound == "string") { + bound = commands[bound] + if (!bound) { return false } + } + // Ensure previous input has been read, so that the handler sees a + // consistent view of the document + cm.display.input.ensurePolled() + var prevShift = cm.display.shift, done = false + try { + if (cm.isReadOnly()) { cm.state.suppressEdits = true } + if (dropShift) { cm.display.shift = false } + done = bound(cm) != Pass + } finally { + cm.display.shift = prevShift + cm.state.suppressEdits = false + } + return done +} + +function lookupKeyForEditor(cm, name, handle) { + for (var i = 0; i < cm.state.keyMaps.length; i++) { + var result = lookupKey(name, cm.state.keyMaps[i], handle, cm) + if (result) { return result } + } + return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle, cm)) + || lookupKey(name, cm.options.keyMap, handle, cm) +} + +// Note that, despite the name, this function is also used to check +// for bound mouse clicks. + +var stopSeq = new Delayed + +function dispatchKey(cm, name, e, handle) { + var seq = cm.state.keySeq + if (seq) { + if (isModifierKey(name)) { return "handled" } + if (/\'$/.test(name)) + { cm.state.keySeq = null } + else + { stopSeq.set(50, function () { + if (cm.state.keySeq == seq) { + cm.state.keySeq = null + cm.display.input.reset() + } + }) } + if (dispatchKeyInner(cm, seq + " " + name, e, handle)) { return true } + } + return dispatchKeyInner(cm, name, e, handle) +} + +function dispatchKeyInner(cm, name, e, handle) { + var result = lookupKeyForEditor(cm, name, handle) + + if (result == "multi") + { cm.state.keySeq = name } + if (result == "handled") + { signalLater(cm, "keyHandled", cm, name, e) } + + if (result == "handled" || result == "multi") { + e_preventDefault(e) + restartBlink(cm) + } + + return !!result +} + +// Handle a key from the keydown event. +function handleKeyBinding(cm, e) { + var name = keyName(e, true) + if (!name) { return false } + + if (e.shiftKey && !cm.state.keySeq) { + // First try to resolve full name (including 'Shift-'). Failing + // that, see if there is a cursor-motion command (starting with + // 'go') bound to the keyname without 'Shift-'. + return dispatchKey(cm, "Shift-" + name, e, function (b) { return doHandleBinding(cm, b, true); }) + || dispatchKey(cm, name, e, function (b) { + if (typeof b == "string" ? /^go[A-Z]/.test(b) : b.motion) + { return doHandleBinding(cm, b) } + }) + } else { + return dispatchKey(cm, name, e, function (b) { return doHandleBinding(cm, b); }) + } +} + +// Handle a key from the keypress event +function handleCharBinding(cm, e, ch) { + return dispatchKey(cm, "'" + ch + "'", e, function (b) { return doHandleBinding(cm, b, true); }) +} + +var lastStoppedKey = null +function onKeyDown(e) { + var cm = this + cm.curOp.focus = activeElt() + if (signalDOMEvent(cm, e)) { return } + // IE does strange things with escape. + if (ie && ie_version < 11 && e.keyCode == 27) { e.returnValue = false } + var code = e.keyCode + cm.display.shift = code == 16 || e.shiftKey + var handled = handleKeyBinding(cm, e) + if (presto) { + lastStoppedKey = handled ? code : null + // Opera has no cut event... we try to at least catch the key combo + if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey)) + { cm.replaceSelection("", null, "cut") } + } + + // Turn mouse into crosshair when Alt is held on Mac. + if (code == 18 && !/\bCodeMirror-crosshair\b/.test(cm.display.lineDiv.className)) + { showCrossHair(cm) } +} + +function showCrossHair(cm) { + var lineDiv = cm.display.lineDiv + addClass(lineDiv, "CodeMirror-crosshair") + + function up(e) { + if (e.keyCode == 18 || !e.altKey) { + rmClass(lineDiv, "CodeMirror-crosshair") + off(document, "keyup", up) + off(document, "mouseover", up) + } + } + on(document, "keyup", up) + on(document, "mouseover", up) +} + +function onKeyUp(e) { + if (e.keyCode == 16) { this.doc.sel.shift = false } + signalDOMEvent(this, e) +} + +function onKeyPress(e) { + var cm = this + if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) { return } + var keyCode = e.keyCode, charCode = e.charCode + if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return} + if ((presto && (!e.which || e.which < 10)) && handleKeyBinding(cm, e)) { return } + var ch = String.fromCharCode(charCode == null ? keyCode : charCode) + // Some browsers fire keypress events for backspace + if (ch == "\x08") { return } + if (handleCharBinding(cm, e, ch)) { return } + cm.display.input.onKeyPress(e) +} + +var DOUBLECLICK_DELAY = 400 + +var PastClick = function(time, pos, button) { + this.time = time + this.pos = pos + this.button = button +}; + +PastClick.prototype.compare = function (time, pos, button) { + return this.time + DOUBLECLICK_DELAY > time && + cmp(pos, this.pos) == 0 && button == this.button +}; + +var lastClick; +var lastDoubleClick; +function clickRepeat(pos, button) { + var now = +new Date + if (lastDoubleClick && lastDoubleClick.compare(now, pos, button)) { + lastClick = lastDoubleClick = null + return "triple" + } else if (lastClick && lastClick.compare(now, pos, button)) { + lastDoubleClick = new PastClick(now, pos, button) + lastClick = null + return "double" + } else { + lastClick = new PastClick(now, pos, button) + lastDoubleClick = null + return "single" + } +} + +// A mouse down can be a single click, double click, triple click, +// start of selection drag, start of text drag, new cursor +// (ctrl-click), rectangle drag (alt-drag), or xwin +// middle-click-paste. Or it might be a click on something we should +// not interfere with, such as a scrollbar or widget. +function onMouseDown(e) { + var cm = this, display = cm.display + if (signalDOMEvent(cm, e) || display.activeTouch && display.input.supportsTouch()) { return } + display.input.ensurePolled() + display.shift = e.shiftKey + + if (eventInWidget(display, e)) { + if (!webkit) { + // Briefly turn off draggability, to allow widgets to do + // normal dragging things. + display.scroller.draggable = false + setTimeout(function () { return display.scroller.draggable = true; }, 100) + } + return + } + if (clickInGutter(cm, e)) { return } + var pos = posFromMouse(cm, e), button = e_button(e), repeat = pos ? clickRepeat(pos, button) : "single" + window.focus() + + // #3261: make sure, that we're not starting a second selection + if (button == 1 && cm.state.selectingText) + { cm.state.selectingText(e) } + + if (pos && handleMappedButton(cm, button, pos, repeat, e)) { return } + + if (button == 1) { + if (pos) { leftButtonDown(cm, pos, repeat, e) } + else if (e_target(e) == display.scroller) { e_preventDefault(e) } + } else if (button == 2) { + if (pos) { extendSelection(cm.doc, pos) } + setTimeout(function () { return display.input.focus(); }, 20) + } else if (button == 3) { + if (captureRightClick) { onContextMenu(cm, e) } + else { delayBlurEvent(cm) } + } +} + +function handleMappedButton(cm, button, pos, repeat, event) { + var name = "Click" + if (repeat == "double") { name = "Double" + name } + else if (repeat == "triple") { name = "Triple" + name } + name = (button == 1 ? "Left" : button == 2 ? "Middle" : "Right") + name + + return dispatchKey(cm, addModifierNames(name, event), event, function (bound) { + if (typeof bound == "string") { bound = commands[bound] } + if (!bound) { return false } + var done = false + try { + if (cm.isReadOnly()) { cm.state.suppressEdits = true } + done = bound(cm, pos) != Pass + } finally { + cm.state.suppressEdits = false + } + return done + }) +} + +function configureMouse(cm, repeat, event) { + var option = cm.getOption("configureMouse") + var value = option ? option(cm, repeat, event) : {} + if (value.unit == null) { + var rect = chromeOS ? event.shiftKey && event.metaKey : event.altKey + value.unit = rect ? "rectangle" : repeat == "single" ? "char" : repeat == "double" ? "word" : "line" + } + if (value.extend == null || cm.doc.extend) { value.extend = cm.doc.extend || event.shiftKey } + if (value.addNew == null) { value.addNew = mac ? event.metaKey : event.ctrlKey } + if (value.moveOnDrag == null) { value.moveOnDrag = !(mac ? event.altKey : event.ctrlKey) } + return value +} + +function leftButtonDown(cm, pos, repeat, event) { + if (ie) { setTimeout(bind(ensureFocus, cm), 0) } + else { cm.curOp.focus = activeElt() } + + var behavior = configureMouse(cm, repeat, event) + + var sel = cm.doc.sel, contained + if (cm.options.dragDrop && dragAndDrop && !cm.isReadOnly() && + repeat == "single" && (contained = sel.contains(pos)) > -1 && + (cmp((contained = sel.ranges[contained]).from(), pos) < 0 || pos.xRel > 0) && + (cmp(contained.to(), pos) > 0 || pos.xRel < 0)) + { leftButtonStartDrag(cm, event, pos, behavior) } + else + { leftButtonSelect(cm, event, pos, behavior) } +} + +// Start a text drag. When it ends, see if any dragging actually +// happen, and treat as a click if it didn't. +function leftButtonStartDrag(cm, event, pos, behavior) { + var display = cm.display, moved = false + var dragEnd = operation(cm, function (e) { + if (webkit) { display.scroller.draggable = false } + cm.state.draggingText = false + off(display.wrapper.ownerDocument, "mouseup", dragEnd) + off(display.wrapper.ownerDocument, "mousemove", mouseMove) + off(display.scroller, "dragstart", dragStart) + off(display.scroller, "drop", dragEnd) + if (!moved) { + e_preventDefault(e) + if (!behavior.addNew) + { extendSelection(cm.doc, pos, null, null, behavior.extend) } + // Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081) + if (webkit || ie && ie_version == 9) + { setTimeout(function () {display.wrapper.ownerDocument.body.focus(); display.input.focus()}, 20) } + else + { display.input.focus() } + } + }) + var mouseMove = function(e2) { + moved = moved || Math.abs(event.clientX - e2.clientX) + Math.abs(event.clientY - e2.clientY) >= 10 + } + var dragStart = function () { return moved = true; } + // Let the drag handler handle this. + if (webkit) { display.scroller.draggable = true } + cm.state.draggingText = dragEnd + dragEnd.copy = !behavior.moveOnDrag + // IE's approach to draggable + if (display.scroller.dragDrop) { display.scroller.dragDrop() } + on(display.wrapper.ownerDocument, "mouseup", dragEnd) + on(display.wrapper.ownerDocument, "mousemove", mouseMove) + on(display.scroller, "dragstart", dragStart) + on(display.scroller, "drop", dragEnd) + + delayBlurEvent(cm) + setTimeout(function () { return display.input.focus(); }, 20) +} + +function rangeForUnit(cm, pos, unit) { + if (unit == "char") { return new Range(pos, pos) } + if (unit == "word") { return cm.findWordAt(pos) } + if (unit == "line") { return new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0))) } + var result = unit(cm, pos) + return new Range(result.from, result.to) +} + +// Normal selection, as opposed to text dragging. +function leftButtonSelect(cm, event, start, behavior) { + var display = cm.display, doc = cm.doc + e_preventDefault(event) + + var ourRange, ourIndex, startSel = doc.sel, ranges = startSel.ranges + if (behavior.addNew && !behavior.extend) { + ourIndex = doc.sel.contains(start) + if (ourIndex > -1) + { ourRange = ranges[ourIndex] } + else + { ourRange = new Range(start, start) } + } else { + ourRange = doc.sel.primary() + ourIndex = doc.sel.primIndex + } + + if (behavior.unit == "rectangle") { + if (!behavior.addNew) { ourRange = new Range(start, start) } + start = posFromMouse(cm, event, true, true) + ourIndex = -1 + } else { + var range = rangeForUnit(cm, start, behavior.unit) + if (behavior.extend) + { ourRange = extendRange(ourRange, range.anchor, range.head, behavior.extend) } + else + { ourRange = range } + } + + if (!behavior.addNew) { + ourIndex = 0 + setSelection(doc, new Selection([ourRange], 0), sel_mouse) + startSel = doc.sel + } else if (ourIndex == -1) { + ourIndex = ranges.length + setSelection(doc, normalizeSelection(ranges.concat([ourRange]), ourIndex), + {scroll: false, origin: "*mouse"}) + } else if (ranges.length > 1 && ranges[ourIndex].empty() && behavior.unit == "char" && !behavior.extend) { + setSelection(doc, normalizeSelection(ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0), + {scroll: false, origin: "*mouse"}) + startSel = doc.sel + } else { + replaceOneSelection(doc, ourIndex, ourRange, sel_mouse) + } + + var lastPos = start + function extendTo(pos) { + if (cmp(lastPos, pos) == 0) { return } + lastPos = pos + + if (behavior.unit == "rectangle") { + var ranges = [], tabSize = cm.options.tabSize + var startCol = countColumn(getLine(doc, start.line).text, start.ch, tabSize) + var posCol = countColumn(getLine(doc, pos.line).text, pos.ch, tabSize) + var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol) + for (var line = Math.min(start.line, pos.line), end = Math.min(cm.lastLine(), Math.max(start.line, pos.line)); + line <= end; line++) { + var text = getLine(doc, line).text, leftPos = findColumn(text, left, tabSize) + if (left == right) + { ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos))) } + else if (text.length > leftPos) + { ranges.push(new Range(Pos(line, leftPos), Pos(line, findColumn(text, right, tabSize)))) } + } + if (!ranges.length) { ranges.push(new Range(start, start)) } + setSelection(doc, normalizeSelection(startSel.ranges.slice(0, ourIndex).concat(ranges), ourIndex), + {origin: "*mouse", scroll: false}) + cm.scrollIntoView(pos) + } else { + var oldRange = ourRange + var range = rangeForUnit(cm, pos, behavior.unit) + var anchor = oldRange.anchor, head + if (cmp(range.anchor, anchor) > 0) { + head = range.head + anchor = minPos(oldRange.from(), range.anchor) + } else { + head = range.anchor + anchor = maxPos(oldRange.to(), range.head) + } + var ranges$1 = startSel.ranges.slice(0) + ranges$1[ourIndex] = bidiSimplify(cm, new Range(clipPos(doc, anchor), head)) + setSelection(doc, normalizeSelection(ranges$1, ourIndex), sel_mouse) + } + } + + var editorSize = display.wrapper.getBoundingClientRect() + // Used to ensure timeout re-tries don't fire when another extend + // happened in the meantime (clearTimeout isn't reliable -- at + // least on Chrome, the timeouts still happen even when cleared, + // if the clear happens after their scheduled firing time). + var counter = 0 + + function extend(e) { + var curCount = ++counter + var cur = posFromMouse(cm, e, true, behavior.unit == "rectangle") + if (!cur) { return } + if (cmp(cur, lastPos) != 0) { + cm.curOp.focus = activeElt() + extendTo(cur) + var visible = visibleLines(display, doc) + if (cur.line >= visible.to || cur.line < visible.from) + { setTimeout(operation(cm, function () {if (counter == curCount) { extend(e) }}), 150) } + } else { + var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0 + if (outside) { setTimeout(operation(cm, function () { + if (counter != curCount) { return } + display.scroller.scrollTop += outside + extend(e) + }), 50) } + } + } + + function done(e) { + cm.state.selectingText = false + counter = Infinity + e_preventDefault(e) + display.input.focus() + off(display.wrapper.ownerDocument, "mousemove", move) + off(display.wrapper.ownerDocument, "mouseup", up) + doc.history.lastSelOrigin = null + } + + var move = operation(cm, function (e) { + if (e.buttons === 0 || !e_button(e)) { done(e) } + else { extend(e) } + }) + var up = operation(cm, done) + cm.state.selectingText = up + on(display.wrapper.ownerDocument, "mousemove", move) + on(display.wrapper.ownerDocument, "mouseup", up) +} + +// Used when mouse-selecting to adjust the anchor to the proper side +// of a bidi jump depending on the visual position of the head. +function bidiSimplify(cm, range) { + var anchor = range.anchor; + var head = range.head; + var anchorLine = getLine(cm.doc, anchor.line) + if (cmp(anchor, head) == 0 && anchor.sticky == head.sticky) { return range } + var order = getOrder(anchorLine) + if (!order) { return range } + var index = getBidiPartAt(order, anchor.ch, anchor.sticky), part = order[index] + if (part.from != anchor.ch && part.to != anchor.ch) { return range } + var boundary = index + ((part.from == anchor.ch) == (part.level != 1) ? 0 : 1) + if (boundary == 0 || boundary == order.length) { return range } + + // Compute the relative visual position of the head compared to the + // anchor (<0 is to the left, >0 to the right) + var leftSide + if (head.line != anchor.line) { + leftSide = (head.line - anchor.line) * (cm.doc.direction == "ltr" ? 1 : -1) > 0 + } else { + var headIndex = getBidiPartAt(order, head.ch, head.sticky) + var dir = headIndex - index || (head.ch - anchor.ch) * (part.level == 1 ? -1 : 1) + if (headIndex == boundary - 1 || headIndex == boundary) + { leftSide = dir < 0 } + else + { leftSide = dir > 0 } + } + + var usePart = order[boundary + (leftSide ? -1 : 0)] + var from = leftSide == (usePart.level == 1) + var ch = from ? usePart.from : usePart.to, sticky = from ? "after" : "before" + return anchor.ch == ch && anchor.sticky == sticky ? range : new Range(new Pos(anchor.line, ch, sticky), head) +} + + +// Determines whether an event happened in the gutter, and fires the +// handlers for the corresponding event. +function gutterEvent(cm, e, type, prevent) { + var mX, mY + if (e.touches) { + mX = e.touches[0].clientX + mY = e.touches[0].clientY + } else { + try { mX = e.clientX; mY = e.clientY } + catch(e) { return false } + } + if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) { return false } + if (prevent) { e_preventDefault(e) } + + var display = cm.display + var lineBox = display.lineDiv.getBoundingClientRect() + + if (mY > lineBox.bottom || !hasHandler(cm, type)) { return e_defaultPrevented(e) } + mY -= lineBox.top - display.viewOffset + + for (var i = 0; i < cm.options.gutters.length; ++i) { + var g = display.gutters.childNodes[i] + if (g && g.getBoundingClientRect().right >= mX) { + var line = lineAtHeight(cm.doc, mY) + var gutter = cm.options.gutters[i] + signal(cm, type, cm, line, gutter, e) + return e_defaultPrevented(e) + } + } +} + +function clickInGutter(cm, e) { + return gutterEvent(cm, e, "gutterClick", true) +} + +// CONTEXT MENU HANDLING + +// To make the context menu work, we need to briefly unhide the +// textarea (making it as unobtrusive as possible) to let the +// right-click take effect on it. +function onContextMenu(cm, e) { + if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) { return } + if (signalDOMEvent(cm, e, "contextmenu")) { return } + cm.display.input.onContextMenu(e) +} + +function contextMenuInGutter(cm, e) { + if (!hasHandler(cm, "gutterContextMenu")) { return false } + return gutterEvent(cm, e, "gutterContextMenu", false) +} + +function themeChanged(cm) { + cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") + + cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-") + clearCaches(cm) +} + +var Init = {toString: function(){return "CodeMirror.Init"}} + +var defaults = {} +var optionHandlers = {} + +function defineOptions(CodeMirror) { + var optionHandlers = CodeMirror.optionHandlers + + function option(name, deflt, handle, notOnInit) { + CodeMirror.defaults[name] = deflt + if (handle) { optionHandlers[name] = + notOnInit ? function (cm, val, old) {if (old != Init) { handle(cm, val, old) }} : handle } + } + + CodeMirror.defineOption = option + + // Passed to option handlers when there is no old value. + CodeMirror.Init = Init + + // These two are, on init, called from the constructor because they + // have to be initialized before the editor can start at all. + option("value", "", function (cm, val) { return cm.setValue(val); }, true) + option("mode", null, function (cm, val) { + cm.doc.modeOption = val + loadMode(cm) + }, true) + + option("indentUnit", 2, loadMode, true) + option("indentWithTabs", false) + option("smartIndent", true) + option("tabSize", 4, function (cm) { + resetModeState(cm) + clearCaches(cm) + regChange(cm) + }, true) + + option("lineSeparator", null, function (cm, val) { + cm.doc.lineSep = val + if (!val) { return } + var newBreaks = [], lineNo = cm.doc.first + cm.doc.iter(function (line) { + for (var pos = 0;;) { + var found = line.text.indexOf(val, pos) + if (found == -1) { break } + pos = found + val.length + newBreaks.push(Pos(lineNo, found)) + } + lineNo++ + }) + for (var i = newBreaks.length - 1; i >= 0; i--) + { replaceRange(cm.doc, val, newBreaks[i], Pos(newBreaks[i].line, newBreaks[i].ch + val.length)) } + }) + option("specialChars", /[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b-\u200f\u2028\u2029\ufeff]/g, function (cm, val, old) { + cm.state.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g") + if (old != Init) { cm.refresh() } + }) + option("specialCharPlaceholder", defaultSpecialCharPlaceholder, function (cm) { return cm.refresh(); }, true) + option("electricChars", true) + option("inputStyle", mobile ? "contenteditable" : "textarea", function () { + throw new Error("inputStyle can not (yet) be changed in a running editor") // FIXME + }, true) + option("spellcheck", false, function (cm, val) { return cm.getInputField().spellcheck = val; }, true) + option("rtlMoveVisually", !windows) + option("wholeLineUpdateBefore", true) + + option("theme", "default", function (cm) { + themeChanged(cm) + guttersChanged(cm) + }, true) + option("keyMap", "default", function (cm, val, old) { + var next = getKeyMap(val) + var prev = old != Init && getKeyMap(old) + if (prev && prev.detach) { prev.detach(cm, next) } + if (next.attach) { next.attach(cm, prev || null) } + }) + option("extraKeys", null) + option("configureMouse", null) + + option("lineWrapping", false, wrappingChanged, true) + option("gutters", [], function (cm) { + setGuttersForLineNumbers(cm.options) + guttersChanged(cm) + }, true) + option("fixedGutter", true, function (cm, val) { + cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0" + cm.refresh() + }, true) + option("coverGutterNextToScrollbar", false, function (cm) { return updateScrollbars(cm); }, true) + option("scrollbarStyle", "native", function (cm) { + initScrollbars(cm) + updateScrollbars(cm) + cm.display.scrollbars.setScrollTop(cm.doc.scrollTop) + cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft) + }, true) + option("lineNumbers", false, function (cm) { + setGuttersForLineNumbers(cm.options) + guttersChanged(cm) + }, true) + option("firstLineNumber", 1, guttersChanged, true) + option("lineNumberFormatter", function (integer) { return integer; }, guttersChanged, true) + option("showCursorWhenSelecting", false, updateSelection, true) + + option("resetSelectionOnContextMenu", true) + option("lineWiseCopyCut", true) + option("pasteLinesPerSelection", true) + + option("readOnly", false, function (cm, val) { + if (val == "nocursor") { + onBlur(cm) + cm.display.input.blur() + } + cm.display.input.readOnlyChanged(val) + }) + option("disableInput", false, function (cm, val) {if (!val) { cm.display.input.reset() }}, true) + option("dragDrop", true, dragDropChanged) + option("allowDropFileTypes", null) + + option("cursorBlinkRate", 530) + option("cursorScrollMargin", 0) + option("cursorHeight", 1, updateSelection, true) + option("singleCursorHeightPerLine", true, updateSelection, true) + option("workTime", 100) + option("workDelay", 100) + option("flattenSpans", true, resetModeState, true) + option("addModeClass", false, resetModeState, true) + option("pollInterval", 100) + option("undoDepth", 200, function (cm, val) { return cm.doc.history.undoDepth = val; }) + option("historyEventDelay", 1250) + option("viewportMargin", 10, function (cm) { return cm.refresh(); }, true) + option("maxHighlightLength", 10000, resetModeState, true) + option("moveInputWithCursor", true, function (cm, val) { + if (!val) { cm.display.input.resetPosition() } + }) + + option("tabindex", null, function (cm, val) { return cm.display.input.getField().tabIndex = val || ""; }) + option("autofocus", null) + option("direction", "ltr", function (cm, val) { return cm.doc.setDirection(val); }, true) +} + +function guttersChanged(cm) { + updateGutters(cm) + regChange(cm) + alignHorizontally(cm) +} + +function dragDropChanged(cm, value, old) { + var wasOn = old && old != Init + if (!value != !wasOn) { + var funcs = cm.display.dragFunctions + var toggle = value ? on : off + toggle(cm.display.scroller, "dragstart", funcs.start) + toggle(cm.display.scroller, "dragenter", funcs.enter) + toggle(cm.display.scroller, "dragover", funcs.over) + toggle(cm.display.scroller, "dragleave", funcs.leave) + toggle(cm.display.scroller, "drop", funcs.drop) + } +} + +function wrappingChanged(cm) { + if (cm.options.lineWrapping) { + addClass(cm.display.wrapper, "CodeMirror-wrap") + cm.display.sizer.style.minWidth = "" + cm.display.sizerWidth = null + } else { + rmClass(cm.display.wrapper, "CodeMirror-wrap") + findMaxLine(cm) + } + estimateLineHeights(cm) + regChange(cm) + clearCaches(cm) + setTimeout(function () { return updateScrollbars(cm); }, 100) +} + +// A CodeMirror instance represents an editor. This is the object +// that user code is usually dealing with. + +function CodeMirror(place, options) { + var this$1 = this; + + if (!(this instanceof CodeMirror)) { return new CodeMirror(place, options) } + + this.options = options = options ? copyObj(options) : {} + // Determine effective options based on given values and defaults. + copyObj(defaults, options, false) + setGuttersForLineNumbers(options) + + var doc = options.value + if (typeof doc == "string") { doc = new Doc(doc, options.mode, null, options.lineSeparator, options.direction) } + this.doc = doc + + var input = new CodeMirror.inputStyles[options.inputStyle](this) + var display = this.display = new Display(place, doc, input) + display.wrapper.CodeMirror = this + updateGutters(this) + themeChanged(this) + if (options.lineWrapping) + { this.display.wrapper.className += " CodeMirror-wrap" } + initScrollbars(this) + + this.state = { + keyMaps: [], // stores maps added by addKeyMap + overlays: [], // highlighting overlays, as added by addOverlay + modeGen: 0, // bumped when mode/overlay changes, used to invalidate highlighting info + overwrite: false, + delayingBlurEvent: false, + focused: false, + suppressEdits: false, // used to disable editing during key handlers when in readOnly mode + pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edits in input.poll + selectingText: false, + draggingText: false, + highlight: new Delayed(), // stores highlight worker timeout + keySeq: null, // Unfinished key sequence + specialChars: null + } + + if (options.autofocus && !mobile) { display.input.focus() } + + // Override magic textarea content restore that IE sometimes does + // on our hidden textarea on reload + if (ie && ie_version < 11) { setTimeout(function () { return this$1.display.input.reset(true); }, 20) } + + registerEventHandlers(this) + ensureGlobalHandlers() + + startOperation(this) + this.curOp.forceUpdate = true + attachDoc(this, doc) + + if ((options.autofocus && !mobile) || this.hasFocus()) + { setTimeout(bind(onFocus, this), 20) } + else + { onBlur(this) } + + for (var opt in optionHandlers) { if (optionHandlers.hasOwnProperty(opt)) + { optionHandlers[opt](this$1, options[opt], Init) } } + maybeUpdateLineNumberWidth(this) + if (options.finishInit) { options.finishInit(this) } + for (var i = 0; i < initHooks.length; ++i) { initHooks[i](this$1) } + endOperation(this) + // Suppress optimizelegibility in Webkit, since it breaks text + // measuring on line wrapping boundaries. + if (webkit && options.lineWrapping && + getComputedStyle(display.lineDiv).textRendering == "optimizelegibility") + { display.lineDiv.style.textRendering = "auto" } +} + +// The default configuration options. +CodeMirror.defaults = defaults +// Functions to run when options are changed. +CodeMirror.optionHandlers = optionHandlers + +// Attach the necessary event handlers when initializing the editor +function registerEventHandlers(cm) { + var d = cm.display + on(d.scroller, "mousedown", operation(cm, onMouseDown)) + // Older IE's will not fire a second mousedown for a double click + if (ie && ie_version < 11) + { on(d.scroller, "dblclick", operation(cm, function (e) { + if (signalDOMEvent(cm, e)) { return } + var pos = posFromMouse(cm, e) + if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) { return } + e_preventDefault(e) + var word = cm.findWordAt(pos) + extendSelection(cm.doc, word.anchor, word.head) + })) } + else + { on(d.scroller, "dblclick", function (e) { return signalDOMEvent(cm, e) || e_preventDefault(e); }) } + // Some browsers fire contextmenu *after* opening the menu, at + // which point we can't mess with it anymore. Context menu is + // handled in onMouseDown for these browsers. + if (!captureRightClick) { on(d.scroller, "contextmenu", function (e) { return onContextMenu(cm, e); }) } + + // Used to suppress mouse event handling when a touch happens + var touchFinished, prevTouch = {end: 0} + function finishTouch() { + if (d.activeTouch) { + touchFinished = setTimeout(function () { return d.activeTouch = null; }, 1000) + prevTouch = d.activeTouch + prevTouch.end = +new Date + } + } + function isMouseLikeTouchEvent(e) { + if (e.touches.length != 1) { return false } + var touch = e.touches[0] + return touch.radiusX <= 1 && touch.radiusY <= 1 + } + function farAway(touch, other) { + if (other.left == null) { return true } + var dx = other.left - touch.left, dy = other.top - touch.top + return dx * dx + dy * dy > 20 * 20 + } + on(d.scroller, "touchstart", function (e) { + if (!signalDOMEvent(cm, e) && !isMouseLikeTouchEvent(e) && !clickInGutter(cm, e)) { + d.input.ensurePolled() + clearTimeout(touchFinished) + var now = +new Date + d.activeTouch = {start: now, moved: false, + prev: now - prevTouch.end <= 300 ? prevTouch : null} + if (e.touches.length == 1) { + d.activeTouch.left = e.touches[0].pageX + d.activeTouch.top = e.touches[0].pageY + } + } + }) + on(d.scroller, "touchmove", function () { + if (d.activeTouch) { d.activeTouch.moved = true } + }) + on(d.scroller, "touchend", function (e) { + var touch = d.activeTouch + if (touch && !eventInWidget(d, e) && touch.left != null && + !touch.moved && new Date - touch.start < 300) { + var pos = cm.coordsChar(d.activeTouch, "page"), range + if (!touch.prev || farAway(touch, touch.prev)) // Single tap + { range = new Range(pos, pos) } + else if (!touch.prev.prev || farAway(touch, touch.prev.prev)) // Double tap + { range = cm.findWordAt(pos) } + else // Triple tap + { range = new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0))) } + cm.setSelection(range.anchor, range.head) + cm.focus() + e_preventDefault(e) + } + finishTouch() + }) + on(d.scroller, "touchcancel", finishTouch) + + // Sync scrolling between fake scrollbars and real scrollable + // area, ensure viewport is updated when scrolling. + on(d.scroller, "scroll", function () { + if (d.scroller.clientHeight) { + updateScrollTop(cm, d.scroller.scrollTop) + setScrollLeft(cm, d.scroller.scrollLeft, true) + signal(cm, "scroll", cm) + } + }) + + // Listen to wheel events in order to try and update the viewport on time. + on(d.scroller, "mousewheel", function (e) { return onScrollWheel(cm, e); }) + on(d.scroller, "DOMMouseScroll", function (e) { return onScrollWheel(cm, e); }) + + // Prevent wrapper from ever scrolling + on(d.wrapper, "scroll", function () { return d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; }) + + d.dragFunctions = { + enter: function (e) {if (!signalDOMEvent(cm, e)) { e_stop(e) }}, + over: function (e) {if (!signalDOMEvent(cm, e)) { onDragOver(cm, e); e_stop(e) }}, + start: function (e) { return onDragStart(cm, e); }, + drop: operation(cm, onDrop), + leave: function (e) {if (!signalDOMEvent(cm, e)) { clearDragCursor(cm) }} + } + + var inp = d.input.getField() + on(inp, "keyup", function (e) { return onKeyUp.call(cm, e); }) + on(inp, "keydown", operation(cm, onKeyDown)) + on(inp, "keypress", operation(cm, onKeyPress)) + on(inp, "focus", function (e) { return onFocus(cm, e); }) + on(inp, "blur", function (e) { return onBlur(cm, e); }) +} + +var initHooks = [] +CodeMirror.defineInitHook = function (f) { return initHooks.push(f); } + +// Indent the given line. The how parameter can be "smart", +// "add"/null, "subtract", or "prev". When aggressive is false +// (typically set to true for forced single-line indents), empty +// lines are not indented, and places where the mode returns Pass +// are left alone. +function indentLine(cm, n, how, aggressive) { + var doc = cm.doc, state + if (how == null) { how = "add" } + if (how == "smart") { + // Fall back to "prev" when the mode doesn't have an indentation + // method. + if (!doc.mode.indent) { how = "prev" } + else { state = getContextBefore(cm, n).state } + } + + var tabSize = cm.options.tabSize + var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize) + if (line.stateAfter) { line.stateAfter = null } + var curSpaceString = line.text.match(/^\s*/)[0], indentation + if (!aggressive && !/\S/.test(line.text)) { + indentation = 0 + how = "not" + } else if (how == "smart") { + indentation = doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text) + if (indentation == Pass || indentation > 150) { + if (!aggressive) { return } + how = "prev" + } + } + if (how == "prev") { + if (n > doc.first) { indentation = countColumn(getLine(doc, n-1).text, null, tabSize) } + else { indentation = 0 } + } else if (how == "add") { + indentation = curSpace + cm.options.indentUnit + } else if (how == "subtract") { + indentation = curSpace - cm.options.indentUnit + } else if (typeof how == "number") { + indentation = curSpace + how + } + indentation = Math.max(0, indentation) + + var indentString = "", pos = 0 + if (cm.options.indentWithTabs) + { for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t"} } + if (pos < indentation) { indentString += spaceStr(indentation - pos) } + + if (indentString != curSpaceString) { + replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input") + line.stateAfter = null + return true + } else { + // Ensure that, if the cursor was in the whitespace at the start + // of the line, it is moved to the end of that space. + for (var i$1 = 0; i$1 < doc.sel.ranges.length; i$1++) { + var range = doc.sel.ranges[i$1] + if (range.head.line == n && range.head.ch < curSpaceString.length) { + var pos$1 = Pos(n, curSpaceString.length) + replaceOneSelection(doc, i$1, new Range(pos$1, pos$1)) + break + } + } + } +} + +// This will be set to a {lineWise: bool, text: [string]} object, so +// that, when pasting, we know what kind of selections the copied +// text was made out of. +var lastCopied = null + +function setLastCopied(newLastCopied) { + lastCopied = newLastCopied +} + +function applyTextInput(cm, inserted, deleted, sel, origin) { + var doc = cm.doc + cm.display.shift = false + if (!sel) { sel = doc.sel } + + var paste = cm.state.pasteIncoming || origin == "paste" + var textLines = splitLinesAuto(inserted), multiPaste = null + // When pasting N lines into N selections, insert one line per selection + if (paste && sel.ranges.length > 1) { + if (lastCopied && lastCopied.text.join("\n") == inserted) { + if (sel.ranges.length % lastCopied.text.length == 0) { + multiPaste = [] + for (var i = 0; i < lastCopied.text.length; i++) + { multiPaste.push(doc.splitLines(lastCopied.text[i])) } + } + } else if (textLines.length == sel.ranges.length && cm.options.pasteLinesPerSelection) { + multiPaste = map(textLines, function (l) { return [l]; }) + } + } + + var updateInput + // Normal behavior is to insert the new text into every selection + for (var i$1 = sel.ranges.length - 1; i$1 >= 0; i$1--) { + var range = sel.ranges[i$1] + var from = range.from(), to = range.to() + if (range.empty()) { + if (deleted && deleted > 0) // Handle deletion + { from = Pos(from.line, from.ch - deleted) } + else if (cm.state.overwrite && !paste) // Handle overwrite + { to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length)) } + else if (lastCopied && lastCopied.lineWise && lastCopied.text.join("\n") == inserted) + { from = to = Pos(from.line, 0) } + } + updateInput = cm.curOp.updateInput + var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i$1 % multiPaste.length] : textLines, + origin: origin || (paste ? "paste" : cm.state.cutIncoming ? "cut" : "+input")} + makeChange(cm.doc, changeEvent) + signalLater(cm, "inputRead", cm, changeEvent) + } + if (inserted && !paste) + { triggerElectric(cm, inserted) } + + ensureCursorVisible(cm) + cm.curOp.updateInput = updateInput + cm.curOp.typing = true + cm.state.pasteIncoming = cm.state.cutIncoming = false +} + +function handlePaste(e, cm) { + var pasted = e.clipboardData && e.clipboardData.getData("Text") + if (pasted) { + e.preventDefault() + if (!cm.isReadOnly() && !cm.options.disableInput) + { runInOp(cm, function () { return applyTextInput(cm, pasted, 0, null, "paste"); }) } + return true + } +} + +function triggerElectric(cm, inserted) { + // When an 'electric' character is inserted, immediately trigger a reindent + if (!cm.options.electricChars || !cm.options.smartIndent) { return } + var sel = cm.doc.sel + + for (var i = sel.ranges.length - 1; i >= 0; i--) { + var range = sel.ranges[i] + if (range.head.ch > 100 || (i && sel.ranges[i - 1].head.line == range.head.line)) { continue } + var mode = cm.getModeAt(range.head) + var indented = false + if (mode.electricChars) { + for (var j = 0; j < mode.electricChars.length; j++) + { if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) { + indented = indentLine(cm, range.head.line, "smart") + break + } } + } else if (mode.electricInput) { + if (mode.electricInput.test(getLine(cm.doc, range.head.line).text.slice(0, range.head.ch))) + { indented = indentLine(cm, range.head.line, "smart") } + } + if (indented) { signalLater(cm, "electricInput", cm, range.head.line) } + } +} + +function copyableRanges(cm) { + var text = [], ranges = [] + for (var i = 0; i < cm.doc.sel.ranges.length; i++) { + var line = cm.doc.sel.ranges[i].head.line + var lineRange = {anchor: Pos(line, 0), head: Pos(line + 1, 0)} + ranges.push(lineRange) + text.push(cm.getRange(lineRange.anchor, lineRange.head)) + } + return {text: text, ranges: ranges} +} + +function disableBrowserMagic(field, spellcheck) { + field.setAttribute("autocorrect", "off") + field.setAttribute("autocapitalize", "off") + field.setAttribute("spellcheck", !!spellcheck) +} + +function hiddenTextarea() { + var te = elt("textarea", null, null, "position: absolute; bottom: -1em; padding: 0; width: 1px; height: 1em; outline: none") + var div = elt("div", [te], null, "overflow: hidden; position: relative; width: 3px; height: 0px;") + // The textarea is kept positioned near the cursor to prevent the + // fact that it'll be scrolled into view on input from scrolling + // our fake cursor out of view. On webkit, when wrap=off, paste is + // very slow. So make the area wide instead. + if (webkit) { te.style.width = "1000px" } + else { te.setAttribute("wrap", "off") } + // If border: 0; -- iOS fails to open keyboard (issue #1287) + if (ios) { te.style.border = "1px solid black" } + disableBrowserMagic(te) + return div +} + +// The publicly visible API. Note that methodOp(f) means +// 'wrap f in an operation, performed on its `this` parameter'. + +// This is not the complete set of editor methods. Most of the +// methods defined on the Doc type are also injected into +// CodeMirror.prototype, for backwards compatibility and +// convenience. + +function addEditorMethods(CodeMirror) { + var optionHandlers = CodeMirror.optionHandlers + + var helpers = CodeMirror.helpers = {} + + CodeMirror.prototype = { + constructor: CodeMirror, + focus: function(){window.focus(); this.display.input.focus()}, + + setOption: function(option, value) { + var options = this.options, old = options[option] + if (options[option] == value && option != "mode") { return } + options[option] = value + if (optionHandlers.hasOwnProperty(option)) + { operation(this, optionHandlers[option])(this, value, old) } + signal(this, "optionChange", this, option) + }, + + getOption: function(option) {return this.options[option]}, + getDoc: function() {return this.doc}, + + addKeyMap: function(map, bottom) { + this.state.keyMaps[bottom ? "push" : "unshift"](getKeyMap(map)) + }, + removeKeyMap: function(map) { + var maps = this.state.keyMaps + for (var i = 0; i < maps.length; ++i) + { if (maps[i] == map || maps[i].name == map) { + maps.splice(i, 1) + return true + } } + }, + + addOverlay: methodOp(function(spec, options) { + var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec) + if (mode.startState) { throw new Error("Overlays may not be stateful.") } + insertSorted(this.state.overlays, + {mode: mode, modeSpec: spec, opaque: options && options.opaque, + priority: (options && options.priority) || 0}, + function (overlay) { return overlay.priority; }) + this.state.modeGen++ + regChange(this) + }), + removeOverlay: methodOp(function(spec) { + var this$1 = this; + + var overlays = this.state.overlays + for (var i = 0; i < overlays.length; ++i) { + var cur = overlays[i].modeSpec + if (cur == spec || typeof spec == "string" && cur.name == spec) { + overlays.splice(i, 1) + this$1.state.modeGen++ + regChange(this$1) + return + } + } + }), + + indentLine: methodOp(function(n, dir, aggressive) { + if (typeof dir != "string" && typeof dir != "number") { + if (dir == null) { dir = this.options.smartIndent ? "smart" : "prev" } + else { dir = dir ? "add" : "subtract" } + } + if (isLine(this.doc, n)) { indentLine(this, n, dir, aggressive) } + }), + indentSelection: methodOp(function(how) { + var this$1 = this; + + var ranges = this.doc.sel.ranges, end = -1 + for (var i = 0; i < ranges.length; i++) { + var range = ranges[i] + if (!range.empty()) { + var from = range.from(), to = range.to() + var start = Math.max(end, from.line) + end = Math.min(this$1.lastLine(), to.line - (to.ch ? 0 : 1)) + 1 + for (var j = start; j < end; ++j) + { indentLine(this$1, j, how) } + var newRanges = this$1.doc.sel.ranges + if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0) + { replaceOneSelection(this$1.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll) } + } else if (range.head.line > end) { + indentLine(this$1, range.head.line, how, true) + end = range.head.line + if (i == this$1.doc.sel.primIndex) { ensureCursorVisible(this$1) } + } + } + }), + + // Fetch the parser token for a given character. Useful for hacks + // that want to inspect the mode state (say, for completion). + getTokenAt: function(pos, precise) { + return takeToken(this, pos, precise) + }, + + getLineTokens: function(line, precise) { + return takeToken(this, Pos(line), precise, true) + }, + + getTokenTypeAt: function(pos) { + pos = clipPos(this.doc, pos) + var styles = getLineStyles(this, getLine(this.doc, pos.line)) + var before = 0, after = (styles.length - 1) / 2, ch = pos.ch + var type + if (ch == 0) { type = styles[2] } + else { for (;;) { + var mid = (before + after) >> 1 + if ((mid ? styles[mid * 2 - 1] : 0) >= ch) { after = mid } + else if (styles[mid * 2 + 1] < ch) { before = mid + 1 } + else { type = styles[mid * 2 + 2]; break } + } } + var cut = type ? type.indexOf("overlay ") : -1 + return cut < 0 ? type : cut == 0 ? null : type.slice(0, cut - 1) + }, + + getModeAt: function(pos) { + var mode = this.doc.mode + if (!mode.innerMode) { return mode } + return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode + }, + + getHelper: function(pos, type) { + return this.getHelpers(pos, type)[0] + }, + + getHelpers: function(pos, type) { + var this$1 = this; + + var found = [] + if (!helpers.hasOwnProperty(type)) { return found } + var help = helpers[type], mode = this.getModeAt(pos) + if (typeof mode[type] == "string") { + if (help[mode[type]]) { found.push(help[mode[type]]) } + } else if (mode[type]) { + for (var i = 0; i < mode[type].length; i++) { + var val = help[mode[type][i]] + if (val) { found.push(val) } + } + } else if (mode.helperType && help[mode.helperType]) { + found.push(help[mode.helperType]) + } else if (help[mode.name]) { + found.push(help[mode.name]) + } + for (var i$1 = 0; i$1 < help._global.length; i$1++) { + var cur = help._global[i$1] + if (cur.pred(mode, this$1) && indexOf(found, cur.val) == -1) + { found.push(cur.val) } + } + return found + }, + + getStateAfter: function(line, precise) { + var doc = this.doc + line = clipLine(doc, line == null ? doc.first + doc.size - 1: line) + return getContextBefore(this, line + 1, precise).state + }, + + cursorCoords: function(start, mode) { + var pos, range = this.doc.sel.primary() + if (start == null) { pos = range.head } + else if (typeof start == "object") { pos = clipPos(this.doc, start) } + else { pos = start ? range.from() : range.to() } + return cursorCoords(this, pos, mode || "page") + }, + + charCoords: function(pos, mode) { + return charCoords(this, clipPos(this.doc, pos), mode || "page") + }, + + coordsChar: function(coords, mode) { + coords = fromCoordSystem(this, coords, mode || "page") + return coordsChar(this, coords.left, coords.top) + }, + + lineAtHeight: function(height, mode) { + height = fromCoordSystem(this, {top: height, left: 0}, mode || "page").top + return lineAtHeight(this.doc, height + this.display.viewOffset) + }, + heightAtLine: function(line, mode, includeWidgets) { + var end = false, lineObj + if (typeof line == "number") { + var last = this.doc.first + this.doc.size - 1 + if (line < this.doc.first) { line = this.doc.first } + else if (line > last) { line = last; end = true } + lineObj = getLine(this.doc, line) + } else { + lineObj = line + } + return intoCoordSystem(this, lineObj, {top: 0, left: 0}, mode || "page", includeWidgets || end).top + + (end ? this.doc.height - heightAtLine(lineObj) : 0) + }, + + defaultTextHeight: function() { return textHeight(this.display) }, + defaultCharWidth: function() { return charWidth(this.display) }, + + getViewport: function() { return {from: this.display.viewFrom, to: this.display.viewTo}}, + + addWidget: function(pos, node, scroll, vert, horiz) { + var display = this.display + pos = cursorCoords(this, clipPos(this.doc, pos)) + var top = pos.bottom, left = pos.left + node.style.position = "absolute" + node.setAttribute("cm-ignore-events", "true") + this.display.input.setUneditable(node) + display.sizer.appendChild(node) + if (vert == "over") { + top = pos.top + } else if (vert == "above" || vert == "near") { + var vspace = Math.max(display.wrapper.clientHeight, this.doc.height), + hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth) + // Default to positioning above (if specified and possible); otherwise default to positioning below + if ((vert == 'above' || pos.bottom + node.offsetHeight > vspace) && pos.top > node.offsetHeight) + { top = pos.top - node.offsetHeight } + else if (pos.bottom + node.offsetHeight <= vspace) + { top = pos.bottom } + if (left + node.offsetWidth > hspace) + { left = hspace - node.offsetWidth } + } + node.style.top = top + "px" + node.style.left = node.style.right = "" + if (horiz == "right") { + left = display.sizer.clientWidth - node.offsetWidth + node.style.right = "0px" + } else { + if (horiz == "left") { left = 0 } + else if (horiz == "middle") { left = (display.sizer.clientWidth - node.offsetWidth) / 2 } + node.style.left = left + "px" + } + if (scroll) + { scrollIntoView(this, {left: left, top: top, right: left + node.offsetWidth, bottom: top + node.offsetHeight}) } + }, + + triggerOnKeyDown: methodOp(onKeyDown), + triggerOnKeyPress: methodOp(onKeyPress), + triggerOnKeyUp: onKeyUp, + triggerOnMouseDown: methodOp(onMouseDown), + + execCommand: function(cmd) { + if (commands.hasOwnProperty(cmd)) + { return commands[cmd].call(null, this) } + }, + + triggerElectric: methodOp(function(text) { triggerElectric(this, text) }), + + findPosH: function(from, amount, unit, visually) { + var this$1 = this; + + var dir = 1 + if (amount < 0) { dir = -1; amount = -amount } + var cur = clipPos(this.doc, from) + for (var i = 0; i < amount; ++i) { + cur = findPosH(this$1.doc, cur, dir, unit, visually) + if (cur.hitSide) { break } + } + return cur + }, + + moveH: methodOp(function(dir, unit) { + var this$1 = this; + + this.extendSelectionsBy(function (range) { + if (this$1.display.shift || this$1.doc.extend || range.empty()) + { return findPosH(this$1.doc, range.head, dir, unit, this$1.options.rtlMoveVisually) } + else + { return dir < 0 ? range.from() : range.to() } + }, sel_move) + }), + + deleteH: methodOp(function(dir, unit) { + var sel = this.doc.sel, doc = this.doc + if (sel.somethingSelected()) + { doc.replaceSelection("", null, "+delete") } + else + { deleteNearSelection(this, function (range) { + var other = findPosH(doc, range.head, dir, unit, false) + return dir < 0 ? {from: other, to: range.head} : {from: range.head, to: other} + }) } + }), + + findPosV: function(from, amount, unit, goalColumn) { + var this$1 = this; + + var dir = 1, x = goalColumn + if (amount < 0) { dir = -1; amount = -amount } + var cur = clipPos(this.doc, from) + for (var i = 0; i < amount; ++i) { + var coords = cursorCoords(this$1, cur, "div") + if (x == null) { x = coords.left } + else { coords.left = x } + cur = findPosV(this$1, coords, dir, unit) + if (cur.hitSide) { break } + } + return cur + }, + + moveV: methodOp(function(dir, unit) { + var this$1 = this; + + var doc = this.doc, goals = [] + var collapse = !this.display.shift && !doc.extend && doc.sel.somethingSelected() + doc.extendSelectionsBy(function (range) { + if (collapse) + { return dir < 0 ? range.from() : range.to() } + var headPos = cursorCoords(this$1, range.head, "div") + if (range.goalColumn != null) { headPos.left = range.goalColumn } + goals.push(headPos.left) + var pos = findPosV(this$1, headPos, dir, unit) + if (unit == "page" && range == doc.sel.primary()) + { addToScrollTop(this$1, charCoords(this$1, pos, "div").top - headPos.top) } + return pos + }, sel_move) + if (goals.length) { for (var i = 0; i < doc.sel.ranges.length; i++) + { doc.sel.ranges[i].goalColumn = goals[i] } } + }), + + // Find the word at the given position (as returned by coordsChar). + findWordAt: function(pos) { + var doc = this.doc, line = getLine(doc, pos.line).text + var start = pos.ch, end = pos.ch + if (line) { + var helper = this.getHelper(pos, "wordChars") + if ((pos.sticky == "before" || end == line.length) && start) { --start; } else { ++end } + var startChar = line.charAt(start) + var check = isWordChar(startChar, helper) + ? function (ch) { return isWordChar(ch, helper); } + : /\s/.test(startChar) ? function (ch) { return /\s/.test(ch); } + : function (ch) { return (!/\s/.test(ch) && !isWordChar(ch)); } + while (start > 0 && check(line.charAt(start - 1))) { --start } + while (end < line.length && check(line.charAt(end))) { ++end } + } + return new Range(Pos(pos.line, start), Pos(pos.line, end)) + }, + + toggleOverwrite: function(value) { + if (value != null && value == this.state.overwrite) { return } + if (this.state.overwrite = !this.state.overwrite) + { addClass(this.display.cursorDiv, "CodeMirror-overwrite") } + else + { rmClass(this.display.cursorDiv, "CodeMirror-overwrite") } + + signal(this, "overwriteToggle", this, this.state.overwrite) + }, + hasFocus: function() { return this.display.input.getField() == activeElt() }, + isReadOnly: function() { return !!(this.options.readOnly || this.doc.cantEdit) }, + + scrollTo: methodOp(function (x, y) { scrollToCoords(this, x, y) }), + getScrollInfo: function() { + var scroller = this.display.scroller + return {left: scroller.scrollLeft, top: scroller.scrollTop, + height: scroller.scrollHeight - scrollGap(this) - this.display.barHeight, + width: scroller.scrollWidth - scrollGap(this) - this.display.barWidth, + clientHeight: displayHeight(this), clientWidth: displayWidth(this)} + }, + + scrollIntoView: methodOp(function(range, margin) { + if (range == null) { + range = {from: this.doc.sel.primary().head, to: null} + if (margin == null) { margin = this.options.cursorScrollMargin } + } else if (typeof range == "number") { + range = {from: Pos(range, 0), to: null} + } else if (range.from == null) { + range = {from: range, to: null} + } + if (!range.to) { range.to = range.from } + range.margin = margin || 0 + + if (range.from.line != null) { + scrollToRange(this, range) + } else { + scrollToCoordsRange(this, range.from, range.to, range.margin) + } + }), + + setSize: methodOp(function(width, height) { + var this$1 = this; + + var interpret = function (val) { return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val; } + if (width != null) { this.display.wrapper.style.width = interpret(width) } + if (height != null) { this.display.wrapper.style.height = interpret(height) } + if (this.options.lineWrapping) { clearLineMeasurementCache(this) } + var lineNo = this.display.viewFrom + this.doc.iter(lineNo, this.display.viewTo, function (line) { + if (line.widgets) { for (var i = 0; i < line.widgets.length; i++) + { if (line.widgets[i].noHScroll) { regLineChange(this$1, lineNo, "widget"); break } } } + ++lineNo + }) + this.curOp.forceUpdate = true + signal(this, "refresh", this) + }), + + operation: function(f){return runInOp(this, f)}, + startOperation: function(){return startOperation(this)}, + endOperation: function(){return endOperation(this)}, + + refresh: methodOp(function() { + var oldHeight = this.display.cachedTextHeight + regChange(this) + this.curOp.forceUpdate = true + clearCaches(this) + scrollToCoords(this, this.doc.scrollLeft, this.doc.scrollTop) + updateGutterSpace(this) + if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5) + { estimateLineHeights(this) } + signal(this, "refresh", this) + }), + + swapDoc: methodOp(function(doc) { + var old = this.doc + old.cm = null + attachDoc(this, doc) + clearCaches(this) + this.display.input.reset() + scrollToCoords(this, doc.scrollLeft, doc.scrollTop) + this.curOp.forceScroll = true + signalLater(this, "swapDoc", this, old) + return old + }), + + getInputField: function(){return this.display.input.getField()}, + getWrapperElement: function(){return this.display.wrapper}, + getScrollerElement: function(){return this.display.scroller}, + getGutterElement: function(){return this.display.gutters} + } + eventMixin(CodeMirror) + + CodeMirror.registerHelper = function(type, name, value) { + if (!helpers.hasOwnProperty(type)) { helpers[type] = CodeMirror[type] = {_global: []} } + helpers[type][name] = value + } + CodeMirror.registerGlobalHelper = function(type, name, predicate, value) { + CodeMirror.registerHelper(type, name, value) + helpers[type]._global.push({pred: predicate, val: value}) + } +} + +// Used for horizontal relative motion. Dir is -1 or 1 (left or +// right), unit can be "char", "column" (like char, but doesn't +// cross line boundaries), "word" (across next word), or "group" (to +// the start of next group of word or non-word-non-whitespace +// chars). The visually param controls whether, in right-to-left +// text, direction 1 means to move towards the next index in the +// string, or towards the character to the right of the current +// position. The resulting position will have a hitSide=true +// property if it reached the end of the document. +function findPosH(doc, pos, dir, unit, visually) { + var oldPos = pos + var origDir = dir + var lineObj = getLine(doc, pos.line) + function findNextLine() { + var l = pos.line + dir + if (l < doc.first || l >= doc.first + doc.size) { return false } + pos = new Pos(l, pos.ch, pos.sticky) + return lineObj = getLine(doc, l) + } + function moveOnce(boundToLine) { + var next + if (visually) { + next = moveVisually(doc.cm, lineObj, pos, dir) + } else { + next = moveLogically(lineObj, pos, dir) + } + if (next == null) { + if (!boundToLine && findNextLine()) + { pos = endOfLine(visually, doc.cm, lineObj, pos.line, dir) } + else + { return false } + } else { + pos = next + } + return true + } + + if (unit == "char") { + moveOnce() + } else if (unit == "column") { + moveOnce(true) + } else if (unit == "word" || unit == "group") { + var sawType = null, group = unit == "group" + var helper = doc.cm && doc.cm.getHelper(pos, "wordChars") + for (var first = true;; first = false) { + if (dir < 0 && !moveOnce(!first)) { break } + var cur = lineObj.text.charAt(pos.ch) || "\n" + var type = isWordChar(cur, helper) ? "w" + : group && cur == "\n" ? "n" + : !group || /\s/.test(cur) ? null + : "p" + if (group && !first && !type) { type = "s" } + if (sawType && sawType != type) { + if (dir < 0) {dir = 1; moveOnce(); pos.sticky = "after"} + break + } + + if (type) { sawType = type } + if (dir > 0 && !moveOnce(!first)) { break } + } + } + var result = skipAtomic(doc, pos, oldPos, origDir, true) + if (equalCursorPos(oldPos, result)) { result.hitSide = true } + return result +} + +// For relative vertical movement. Dir may be -1 or 1. Unit can be +// "page" or "line". The resulting position will have a hitSide=true +// property if it reached the end of the document. +function findPosV(cm, pos, dir, unit) { + var doc = cm.doc, x = pos.left, y + if (unit == "page") { + var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight) + var moveAmount = Math.max(pageSize - .5 * textHeight(cm.display), 3) + y = (dir > 0 ? pos.bottom : pos.top) + dir * moveAmount + + } else if (unit == "line") { + y = dir > 0 ? pos.bottom + 3 : pos.top - 3 + } + var target + for (;;) { + target = coordsChar(cm, x, y) + if (!target.outside) { break } + if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break } + y += dir * 5 + } + return target +} + +// CONTENTEDITABLE INPUT STYLE + +var ContentEditableInput = function(cm) { + this.cm = cm + this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null + this.polling = new Delayed() + this.composing = null + this.gracePeriod = false + this.readDOMTimeout = null +}; + +ContentEditableInput.prototype.init = function (display) { + var this$1 = this; + + var input = this, cm = input.cm + var div = input.div = display.lineDiv + disableBrowserMagic(div, cm.options.spellcheck) + + on(div, "paste", function (e) { + if (signalDOMEvent(cm, e) || handlePaste(e, cm)) { return } + // IE doesn't fire input events, so we schedule a read for the pasted content in this way + if (ie_version <= 11) { setTimeout(operation(cm, function () { return this$1.updateFromDOM(); }), 20) } + }) + + on(div, "compositionstart", function (e) { + this$1.composing = {data: e.data, done: false} + }) + on(div, "compositionupdate", function (e) { + if (!this$1.composing) { this$1.composing = {data: e.data, done: false} } + }) + on(div, "compositionend", function (e) { + if (this$1.composing) { + if (e.data != this$1.composing.data) { this$1.readFromDOMSoon() } + this$1.composing.done = true + } + }) + + on(div, "touchstart", function () { return input.forceCompositionEnd(); }) + + on(div, "input", function () { + if (!this$1.composing) { this$1.readFromDOMSoon() } + }) + + function onCopyCut(e) { + if (signalDOMEvent(cm, e)) { return } + if (cm.somethingSelected()) { + setLastCopied({lineWise: false, text: cm.getSelections()}) + if (e.type == "cut") { cm.replaceSelection("", null, "cut") } + } else if (!cm.options.lineWiseCopyCut) { + return + } else { + var ranges = copyableRanges(cm) + setLastCopied({lineWise: true, text: ranges.text}) + if (e.type == "cut") { + cm.operation(function () { + cm.setSelections(ranges.ranges, 0, sel_dontScroll) + cm.replaceSelection("", null, "cut") + }) + } + } + if (e.clipboardData) { + e.clipboardData.clearData() + var content = lastCopied.text.join("\n") + // iOS exposes the clipboard API, but seems to discard content inserted into it + e.clipboardData.setData("Text", content) + if (e.clipboardData.getData("Text") == content) { + e.preventDefault() + return + } + } + // Old-fashioned briefly-focus-a-textarea hack + var kludge = hiddenTextarea(), te = kludge.firstChild + cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild) + te.value = lastCopied.text.join("\n") + var hadFocus = document.activeElement + selectInput(te) + setTimeout(function () { + cm.display.lineSpace.removeChild(kludge) + hadFocus.focus() + if (hadFocus == div) { input.showPrimarySelection() } + }, 50) + } + on(div, "copy", onCopyCut) + on(div, "cut", onCopyCut) +}; + +ContentEditableInput.prototype.prepareSelection = function () { + var result = prepareSelection(this.cm, false) + result.focus = this.cm.state.focused + return result +}; + +ContentEditableInput.prototype.showSelection = function (info, takeFocus) { + if (!info || !this.cm.display.view.length) { return } + if (info.focus || takeFocus) { this.showPrimarySelection() } + this.showMultipleSelections(info) +}; + +ContentEditableInput.prototype.getSelection = function () { + return this.cm.display.wrapper.ownerDocument.getSelection() +}; + +ContentEditableInput.prototype.showPrimarySelection = function () { + var sel = this.getSelection(), cm = this.cm, prim = cm.doc.sel.primary() + var from = prim.from(), to = prim.to() + + if (cm.display.viewTo == cm.display.viewFrom || from.line >= cm.display.viewTo || to.line < cm.display.viewFrom) { + sel.removeAllRanges() + return + } + + var curAnchor = domToPos(cm, sel.anchorNode, sel.anchorOffset) + var curFocus = domToPos(cm, sel.focusNode, sel.focusOffset) + if (curAnchor && !curAnchor.bad && curFocus && !curFocus.bad && + cmp(minPos(curAnchor, curFocus), from) == 0 && + cmp(maxPos(curAnchor, curFocus), to) == 0) + { return } + + var view = cm.display.view + var start = (from.line >= cm.display.viewFrom && posToDOM(cm, from)) || + {node: view[0].measure.map[2], offset: 0} + var end = to.line < cm.display.viewTo && posToDOM(cm, to) + if (!end) { + var measure = view[view.length - 1].measure + var map = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map + end = {node: map[map.length - 1], offset: map[map.length - 2] - map[map.length - 3]} + } + + if (!start || !end) { + sel.removeAllRanges() + return + } + + var old = sel.rangeCount && sel.getRangeAt(0), rng + try { rng = range(start.node, start.offset, end.offset, end.node) } + catch(e) {} // Our model of the DOM might be outdated, in which case the range we try to set can be impossible + if (rng) { + if (!gecko && cm.state.focused) { + sel.collapse(start.node, start.offset) + if (!rng.collapsed) { + sel.removeAllRanges() + sel.addRange(rng) + } + } else { + sel.removeAllRanges() + sel.addRange(rng) + } + if (old && sel.anchorNode == null) { sel.addRange(old) } + else if (gecko) { this.startGracePeriod() } + } + this.rememberSelection() +}; + +ContentEditableInput.prototype.startGracePeriod = function () { + var this$1 = this; + + clearTimeout(this.gracePeriod) + this.gracePeriod = setTimeout(function () { + this$1.gracePeriod = false + if (this$1.selectionChanged()) + { this$1.cm.operation(function () { return this$1.cm.curOp.selectionChanged = true; }) } + }, 20) +}; + +ContentEditableInput.prototype.showMultipleSelections = function (info) { + removeChildrenAndAdd(this.cm.display.cursorDiv, info.cursors) + removeChildrenAndAdd(this.cm.display.selectionDiv, info.selection) +}; + +ContentEditableInput.prototype.rememberSelection = function () { + var sel = this.getSelection() + this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset + this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset +}; + +ContentEditableInput.prototype.selectionInEditor = function () { + var sel = this.getSelection() + if (!sel.rangeCount) { return false } + var node = sel.getRangeAt(0).commonAncestorContainer + return contains(this.div, node) +}; + +ContentEditableInput.prototype.focus = function () { + if (this.cm.options.readOnly != "nocursor") { + if (!this.selectionInEditor()) + { this.showSelection(this.prepareSelection(), true) } + this.div.focus() + } +}; +ContentEditableInput.prototype.blur = function () { this.div.blur() }; +ContentEditableInput.prototype.getField = function () { return this.div }; + +ContentEditableInput.prototype.supportsTouch = function () { return true }; + +ContentEditableInput.prototype.receivedFocus = function () { + var input = this + if (this.selectionInEditor()) + { this.pollSelection() } + else + { runInOp(this.cm, function () { return input.cm.curOp.selectionChanged = true; }) } + + function poll() { + if (input.cm.state.focused) { + input.pollSelection() + input.polling.set(input.cm.options.pollInterval, poll) + } + } + this.polling.set(this.cm.options.pollInterval, poll) +}; + +ContentEditableInput.prototype.selectionChanged = function () { + var sel = this.getSelection() + return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset || + sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset +}; + +ContentEditableInput.prototype.pollSelection = function () { + if (this.readDOMTimeout != null || this.gracePeriod || !this.selectionChanged()) { return } + var sel = this.getSelection(), cm = this.cm + // On Android Chrome (version 56, at least), backspacing into an + // uneditable block element will put the cursor in that element, + // and then, because it's not editable, hide the virtual keyboard. + // Because Android doesn't allow us to actually detect backspace + // presses in a sane way, this code checks for when that happens + // and simulates a backspace press in this case. + if (android && chrome && this.cm.options.gutters.length && isInGutter(sel.anchorNode)) { + this.cm.triggerOnKeyDown({type: "keydown", keyCode: 8, preventDefault: Math.abs}) + this.blur() + this.focus() + return + } + if (this.composing) { return } + this.rememberSelection() + var anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset) + var head = domToPos(cm, sel.focusNode, sel.focusOffset) + if (anchor && head) { runInOp(cm, function () { + setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll) + if (anchor.bad || head.bad) { cm.curOp.selectionChanged = true } + }) } +}; + +ContentEditableInput.prototype.pollContent = function () { + if (this.readDOMTimeout != null) { + clearTimeout(this.readDOMTimeout) + this.readDOMTimeout = null + } + + var cm = this.cm, display = cm.display, sel = cm.doc.sel.primary() + var from = sel.from(), to = sel.to() + if (from.ch == 0 && from.line > cm.firstLine()) + { from = Pos(from.line - 1, getLine(cm.doc, from.line - 1).length) } + if (to.ch == getLine(cm.doc, to.line).text.length && to.line < cm.lastLine()) + { to = Pos(to.line + 1, 0) } + if (from.line < display.viewFrom || to.line > display.viewTo - 1) { return false } + + var fromIndex, fromLine, fromNode + if (from.line == display.viewFrom || (fromIndex = findViewIndex(cm, from.line)) == 0) { + fromLine = lineNo(display.view[0].line) + fromNode = display.view[0].node + } else { + fromLine = lineNo(display.view[fromIndex].line) + fromNode = display.view[fromIndex - 1].node.nextSibling + } + var toIndex = findViewIndex(cm, to.line) + var toLine, toNode + if (toIndex == display.view.length - 1) { + toLine = display.viewTo - 1 + toNode = display.lineDiv.lastChild + } else { + toLine = lineNo(display.view[toIndex + 1].line) - 1 + toNode = display.view[toIndex + 1].node.previousSibling + } + + if (!fromNode) { return false } + var newText = cm.doc.splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine)) + var oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length)) + while (newText.length > 1 && oldText.length > 1) { + if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine-- } + else if (newText[0] == oldText[0]) { newText.shift(); oldText.shift(); fromLine++ } + else { break } + } + + var cutFront = 0, cutEnd = 0 + var newTop = newText[0], oldTop = oldText[0], maxCutFront = Math.min(newTop.length, oldTop.length) + while (cutFront < maxCutFront && newTop.charCodeAt(cutFront) == oldTop.charCodeAt(cutFront)) + { ++cutFront } + var newBot = lst(newText), oldBot = lst(oldText) + var maxCutEnd = Math.min(newBot.length - (newText.length == 1 ? cutFront : 0), + oldBot.length - (oldText.length == 1 ? cutFront : 0)) + while (cutEnd < maxCutEnd && + newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1)) + { ++cutEnd } + // Try to move start of change to start of selection if ambiguous + if (newText.length == 1 && oldText.length == 1 && fromLine == from.line) { + while (cutFront && cutFront > from.ch && + newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1)) { + cutFront-- + cutEnd++ + } + } + + newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd).replace(/^\u200b+/, "") + newText[0] = newText[0].slice(cutFront).replace(/\u200b+$/, "") + + var chFrom = Pos(fromLine, cutFront) + var chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0) + if (newText.length > 1 || newText[0] || cmp(chFrom, chTo)) { + replaceRange(cm.doc, newText, chFrom, chTo, "+input") + return true + } +}; + +ContentEditableInput.prototype.ensurePolled = function () { + this.forceCompositionEnd() +}; +ContentEditableInput.prototype.reset = function () { + this.forceCompositionEnd() +}; +ContentEditableInput.prototype.forceCompositionEnd = function () { + if (!this.composing) { return } + clearTimeout(this.readDOMTimeout) + this.composing = null + this.updateFromDOM() + this.div.blur() + this.div.focus() +}; +ContentEditableInput.prototype.readFromDOMSoon = function () { + var this$1 = this; + + if (this.readDOMTimeout != null) { return } + this.readDOMTimeout = setTimeout(function () { + this$1.readDOMTimeout = null + if (this$1.composing) { + if (this$1.composing.done) { this$1.composing = null } + else { return } + } + this$1.updateFromDOM() + }, 80) +}; + +ContentEditableInput.prototype.updateFromDOM = function () { + var this$1 = this; + + if (this.cm.isReadOnly() || !this.pollContent()) + { runInOp(this.cm, function () { return regChange(this$1.cm); }) } +}; + +ContentEditableInput.prototype.setUneditable = function (node) { + node.contentEditable = "false" +}; + +ContentEditableInput.prototype.onKeyPress = function (e) { + if (e.charCode == 0 || this.composing) { return } + e.preventDefault() + if (!this.cm.isReadOnly()) + { operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0) } +}; + +ContentEditableInput.prototype.readOnlyChanged = function (val) { + this.div.contentEditable = String(val != "nocursor") +}; + +ContentEditableInput.prototype.onContextMenu = function () {}; +ContentEditableInput.prototype.resetPosition = function () {}; + +ContentEditableInput.prototype.needsContentAttribute = true + +function posToDOM(cm, pos) { + var view = findViewForLine(cm, pos.line) + if (!view || view.hidden) { return null } + var line = getLine(cm.doc, pos.line) + var info = mapFromLineView(view, line, pos.line) + + var order = getOrder(line, cm.doc.direction), side = "left" + if (order) { + var partPos = getBidiPartAt(order, pos.ch) + side = partPos % 2 ? "right" : "left" + } + var result = nodeAndOffsetInLineMap(info.map, pos.ch, side) + result.offset = result.collapse == "right" ? result.end : result.start + return result +} + +function isInGutter(node) { + for (var scan = node; scan; scan = scan.parentNode) + { if (/CodeMirror-gutter-wrapper/.test(scan.className)) { return true } } + return false +} + +function badPos(pos, bad) { if (bad) { pos.bad = true; } return pos } + +function domTextBetween(cm, from, to, fromLine, toLine) { + var text = "", closing = false, lineSep = cm.doc.lineSeparator(), extraLinebreak = false + function recognizeMarker(id) { return function (marker) { return marker.id == id; } } + function close() { + if (closing) { + text += lineSep + if (extraLinebreak) { text += lineSep } + closing = extraLinebreak = false + } + } + function addText(str) { + if (str) { + close() + text += str + } + } + function walk(node) { + if (node.nodeType == 1) { + var cmText = node.getAttribute("cm-text") + if (cmText) { + addText(cmText) + return + } + var markerID = node.getAttribute("cm-marker"), range + if (markerID) { + var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID)) + if (found.length && (range = found[0].find(0))) + { addText(getBetween(cm.doc, range.from, range.to).join(lineSep)) } + return + } + if (node.getAttribute("contenteditable") == "false") { return } + var isBlock = /^(pre|div|p|li|table|br)$/i.test(node.nodeName) + if (!/^br$/i.test(node.nodeName) && node.textContent.length == 0) { return } + + if (isBlock) { close() } + for (var i = 0; i < node.childNodes.length; i++) + { walk(node.childNodes[i]) } + + if (/^(pre|p)$/i.test(node.nodeName)) { extraLinebreak = true } + if (isBlock) { closing = true } + } else if (node.nodeType == 3) { + addText(node.nodeValue.replace(/\u200b/g, "").replace(/\u00a0/g, " ")) + } + } + for (;;) { + walk(from) + if (from == to) { break } + from = from.nextSibling + extraLinebreak = false + } + return text +} + +function domToPos(cm, node, offset) { + var lineNode + if (node == cm.display.lineDiv) { + lineNode = cm.display.lineDiv.childNodes[offset] + if (!lineNode) { return badPos(cm.clipPos(Pos(cm.display.viewTo - 1)), true) } + node = null; offset = 0 + } else { + for (lineNode = node;; lineNode = lineNode.parentNode) { + if (!lineNode || lineNode == cm.display.lineDiv) { return null } + if (lineNode.parentNode && lineNode.parentNode == cm.display.lineDiv) { break } + } + } + for (var i = 0; i < cm.display.view.length; i++) { + var lineView = cm.display.view[i] + if (lineView.node == lineNode) + { return locateNodeInLineView(lineView, node, offset) } + } +} + +function locateNodeInLineView(lineView, node, offset) { + var wrapper = lineView.text.firstChild, bad = false + if (!node || !contains(wrapper, node)) { return badPos(Pos(lineNo(lineView.line), 0), true) } + if (node == wrapper) { + bad = true + node = wrapper.childNodes[offset] + offset = 0 + if (!node) { + var line = lineView.rest ? lst(lineView.rest) : lineView.line + return badPos(Pos(lineNo(line), line.text.length), bad) + } + } + + var textNode = node.nodeType == 3 ? node : null, topNode = node + if (!textNode && node.childNodes.length == 1 && node.firstChild.nodeType == 3) { + textNode = node.firstChild + if (offset) { offset = textNode.nodeValue.length } + } + while (topNode.parentNode != wrapper) { topNode = topNode.parentNode } + var measure = lineView.measure, maps = measure.maps + + function find(textNode, topNode, offset) { + for (var i = -1; i < (maps ? maps.length : 0); i++) { + var map = i < 0 ? measure.map : maps[i] + for (var j = 0; j < map.length; j += 3) { + var curNode = map[j + 2] + if (curNode == textNode || curNode == topNode) { + var line = lineNo(i < 0 ? lineView.line : lineView.rest[i]) + var ch = map[j] + offset + if (offset < 0 || curNode != textNode) { ch = map[j + (offset ? 1 : 0)] } + return Pos(line, ch) + } + } + } + } + var found = find(textNode, topNode, offset) + if (found) { return badPos(found, bad) } + + // FIXME this is all really shaky. might handle the few cases it needs to handle, but likely to cause problems + for (var after = topNode.nextSibling, dist = textNode ? textNode.nodeValue.length - offset : 0; after; after = after.nextSibling) { + found = find(after, after.firstChild, 0) + if (found) + { return badPos(Pos(found.line, found.ch - dist), bad) } + else + { dist += after.textContent.length } + } + for (var before = topNode.previousSibling, dist$1 = offset; before; before = before.previousSibling) { + found = find(before, before.firstChild, -1) + if (found) + { return badPos(Pos(found.line, found.ch + dist$1), bad) } + else + { dist$1 += before.textContent.length } + } +} + +// TEXTAREA INPUT STYLE + +var TextareaInput = function(cm) { + this.cm = cm + // See input.poll and input.reset + this.prevInput = "" + + // Flag that indicates whether we expect input to appear real soon + // now (after some event like 'keypress' or 'input') and are + // polling intensively. + this.pollingFast = false + // Self-resetting timeout for the poller + this.polling = new Delayed() + // Used to work around IE issue with selection being forgotten when focus moves away from textarea + this.hasSelection = false + this.composing = null +}; + +TextareaInput.prototype.init = function (display) { + var this$1 = this; + + var input = this, cm = this.cm + this.createField(display) + var te = this.textarea + + display.wrapper.insertBefore(this.wrapper, display.wrapper.firstChild) + + // Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore) + if (ios) { te.style.width = "0px" } + + on(te, "input", function () { + if (ie && ie_version >= 9 && this$1.hasSelection) { this$1.hasSelection = null } + input.poll() + }) + + on(te, "paste", function (e) { + if (signalDOMEvent(cm, e) || handlePaste(e, cm)) { return } + + cm.state.pasteIncoming = true + input.fastPoll() + }) + + function prepareCopyCut(e) { + if (signalDOMEvent(cm, e)) { return } + if (cm.somethingSelected()) { + setLastCopied({lineWise: false, text: cm.getSelections()}) + } else if (!cm.options.lineWiseCopyCut) { + return + } else { + var ranges = copyableRanges(cm) + setLastCopied({lineWise: true, text: ranges.text}) + if (e.type == "cut") { + cm.setSelections(ranges.ranges, null, sel_dontScroll) + } else { + input.prevInput = "" + te.value = ranges.text.join("\n") + selectInput(te) + } + } + if (e.type == "cut") { cm.state.cutIncoming = true } + } + on(te, "cut", prepareCopyCut) + on(te, "copy", prepareCopyCut) + + on(display.scroller, "paste", function (e) { + if (eventInWidget(display, e) || signalDOMEvent(cm, e)) { return } + cm.state.pasteIncoming = true + input.focus() + }) + + // Prevent normal selection in the editor (we handle our own) + on(display.lineSpace, "selectstart", function (e) { + if (!eventInWidget(display, e)) { e_preventDefault(e) } + }) + + on(te, "compositionstart", function () { + var start = cm.getCursor("from") + if (input.composing) { input.composing.range.clear() } + input.composing = { + start: start, + range: cm.markText(start, cm.getCursor("to"), {className: "CodeMirror-composing"}) + } + }) + on(te, "compositionend", function () { + if (input.composing) { + input.poll() + input.composing.range.clear() + input.composing = null + } + }) +}; + +TextareaInput.prototype.createField = function (_display) { + // Wraps and hides input textarea + this.wrapper = hiddenTextarea() + // The semihidden textarea that is focused when the editor is + // focused, and receives input. + this.textarea = this.wrapper.firstChild +}; + +TextareaInput.prototype.prepareSelection = function () { + // Redraw the selection and/or cursor + var cm = this.cm, display = cm.display, doc = cm.doc + var result = prepareSelection(cm) + + // Move the hidden textarea near the cursor to prevent scrolling artifacts + if (cm.options.moveInputWithCursor) { + var headPos = cursorCoords(cm, doc.sel.primary().head, "div") + var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect() + result.teTop = Math.max(0, Math.min(display.wrapper.clientHeight - 10, + headPos.top + lineOff.top - wrapOff.top)) + result.teLeft = Math.max(0, Math.min(display.wrapper.clientWidth - 10, + headPos.left + lineOff.left - wrapOff.left)) + } + + return result +}; + +TextareaInput.prototype.showSelection = function (drawn) { + var cm = this.cm, display = cm.display + removeChildrenAndAdd(display.cursorDiv, drawn.cursors) + removeChildrenAndAdd(display.selectionDiv, drawn.selection) + if (drawn.teTop != null) { + this.wrapper.style.top = drawn.teTop + "px" + this.wrapper.style.left = drawn.teLeft + "px" + } +}; + +// Reset the input to correspond to the selection (or to be empty, +// when not typing and nothing is selected) +TextareaInput.prototype.reset = function (typing) { + if (this.contextMenuPending || this.composing) { return } + var cm = this.cm + if (cm.somethingSelected()) { + this.prevInput = "" + var content = cm.getSelection() + this.textarea.value = content + if (cm.state.focused) { selectInput(this.textarea) } + if (ie && ie_version >= 9) { this.hasSelection = content } + } else if (!typing) { + this.prevInput = this.textarea.value = "" + if (ie && ie_version >= 9) { this.hasSelection = null } + } +}; + +TextareaInput.prototype.getField = function () { return this.textarea }; + +TextareaInput.prototype.supportsTouch = function () { return false }; + +TextareaInput.prototype.focus = function () { + if (this.cm.options.readOnly != "nocursor" && (!mobile || activeElt() != this.textarea)) { + try { this.textarea.focus() } + catch (e) {} // IE8 will throw if the textarea is display: none or not in DOM + } +}; + +TextareaInput.prototype.blur = function () { this.textarea.blur() }; + +TextareaInput.prototype.resetPosition = function () { + this.wrapper.style.top = this.wrapper.style.left = 0 +}; + +TextareaInput.prototype.receivedFocus = function () { this.slowPoll() }; + +// Poll for input changes, using the normal rate of polling. This +// runs as long as the editor is focused. +TextareaInput.prototype.slowPoll = function () { + var this$1 = this; + + if (this.pollingFast) { return } + this.polling.set(this.cm.options.pollInterval, function () { + this$1.poll() + if (this$1.cm.state.focused) { this$1.slowPoll() } + }) +}; + +// When an event has just come in that is likely to add or change +// something in the input textarea, we poll faster, to ensure that +// the change appears on the screen quickly. +TextareaInput.prototype.fastPoll = function () { + var missed = false, input = this + input.pollingFast = true + function p() { + var changed = input.poll() + if (!changed && !missed) {missed = true; input.polling.set(60, p)} + else {input.pollingFast = false; input.slowPoll()} + } + input.polling.set(20, p) +}; + +// Read input from the textarea, and update the document to match. +// When something is selected, it is present in the textarea, and +// selected (unless it is huge, in which case a placeholder is +// used). When nothing is selected, the cursor sits after previously +// seen text (can be empty), which is stored in prevInput (we must +// not reset the textarea when typing, because that breaks IME). +TextareaInput.prototype.poll = function () { + var this$1 = this; + + var cm = this.cm, input = this.textarea, prevInput = this.prevInput + // Since this is called a *lot*, try to bail out as cheaply as + // possible when it is clear that nothing happened. hasSelection + // will be the case when there is a lot of text in the textarea, + // in which case reading its value would be expensive. + if (this.contextMenuPending || !cm.state.focused || + (hasSelection(input) && !prevInput && !this.composing) || + cm.isReadOnly() || cm.options.disableInput || cm.state.keySeq) + { return false } + + var text = input.value + // If nothing changed, bail. + if (text == prevInput && !cm.somethingSelected()) { return false } + // Work around nonsensical selection resetting in IE9/10, and + // inexplicable appearance of private area unicode characters on + // some key combos in Mac (#2689). + if (ie && ie_version >= 9 && this.hasSelection === text || + mac && /[\uf700-\uf7ff]/.test(text)) { + cm.display.input.reset() + return false + } + + if (cm.doc.sel == cm.display.selForContextMenu) { + var first = text.charCodeAt(0) + if (first == 0x200b && !prevInput) { prevInput = "\u200b" } + if (first == 0x21da) { this.reset(); return this.cm.execCommand("undo") } + } + // Find the part of the input that is actually new + var same = 0, l = Math.min(prevInput.length, text.length) + while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) { ++same } + + runInOp(cm, function () { + applyTextInput(cm, text.slice(same), prevInput.length - same, + null, this$1.composing ? "*compose" : null) + + // Don't leave long text in the textarea, since it makes further polling slow + if (text.length > 1000 || text.indexOf("\n") > -1) { input.value = this$1.prevInput = "" } + else { this$1.prevInput = text } + + if (this$1.composing) { + this$1.composing.range.clear() + this$1.composing.range = cm.markText(this$1.composing.start, cm.getCursor("to"), + {className: "CodeMirror-composing"}) + } + }) + return true +}; + +TextareaInput.prototype.ensurePolled = function () { + if (this.pollingFast && this.poll()) { this.pollingFast = false } +}; + +TextareaInput.prototype.onKeyPress = function () { + if (ie && ie_version >= 9) { this.hasSelection = null } + this.fastPoll() +}; + +TextareaInput.prototype.onContextMenu = function (e) { + var input = this, cm = input.cm, display = cm.display, te = input.textarea + var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop + if (!pos || presto) { return } // Opera is difficult. + + // Reset the current text selection only if the click is done outside of the selection + // and 'resetSelectionOnContextMenu' option is true. + var reset = cm.options.resetSelectionOnContextMenu + if (reset && cm.doc.sel.contains(pos) == -1) + { operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll) } + + var oldCSS = te.style.cssText, oldWrapperCSS = input.wrapper.style.cssText + input.wrapper.style.cssText = "position: absolute" + var wrapperBox = input.wrapper.getBoundingClientRect() + te.style.cssText = "position: absolute; width: 30px; height: 30px;\n top: " + (e.clientY - wrapperBox.top - 5) + "px; left: " + (e.clientX - wrapperBox.left - 5) + "px;\n z-index: 1000; background: " + (ie ? "rgba(255, 255, 255, .05)" : "transparent") + ";\n outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);" + var oldScrollY + if (webkit) { oldScrollY = window.scrollY } // Work around Chrome issue (#2712) + display.input.focus() + if (webkit) { window.scrollTo(null, oldScrollY) } + display.input.reset() + // Adds "Select all" to context menu in FF + if (!cm.somethingSelected()) { te.value = input.prevInput = " " } + input.contextMenuPending = true + display.selForContextMenu = cm.doc.sel + clearTimeout(display.detectingSelectAll) + + // Select-all will be greyed out if there's nothing to select, so + // this adds a zero-width space so that we can later check whether + // it got selected. + function prepareSelectAllHack() { + if (te.selectionStart != null) { + var selected = cm.somethingSelected() + var extval = "\u200b" + (selected ? te.value : "") + te.value = "\u21da" // Used to catch context-menu undo + te.value = extval + input.prevInput = selected ? "" : "\u200b" + te.selectionStart = 1; te.selectionEnd = extval.length + // Re-set this, in case some other handler touched the + // selection in the meantime. + display.selForContextMenu = cm.doc.sel + } + } + function rehide() { + input.contextMenuPending = false + input.wrapper.style.cssText = oldWrapperCSS + te.style.cssText = oldCSS + if (ie && ie_version < 9) { display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos) } + + // Try to detect the user choosing select-all + if (te.selectionStart != null) { + if (!ie || (ie && ie_version < 9)) { prepareSelectAllHack() } + var i = 0, poll = function () { + if (display.selForContextMenu == cm.doc.sel && te.selectionStart == 0 && + te.selectionEnd > 0 && input.prevInput == "\u200b") { + operation(cm, selectAll)(cm) + } else if (i++ < 10) { + display.detectingSelectAll = setTimeout(poll, 500) + } else { + display.selForContextMenu = null + display.input.reset() + } + } + display.detectingSelectAll = setTimeout(poll, 200) + } + } + + if (ie && ie_version >= 9) { prepareSelectAllHack() } + if (captureRightClick) { + e_stop(e) + var mouseup = function () { + off(window, "mouseup", mouseup) + setTimeout(rehide, 20) + } + on(window, "mouseup", mouseup) + } else { + setTimeout(rehide, 50) + } +}; + +TextareaInput.prototype.readOnlyChanged = function (val) { + if (!val) { this.reset() } + this.textarea.disabled = val == "nocursor" +}; + +TextareaInput.prototype.setUneditable = function () {}; + +TextareaInput.prototype.needsContentAttribute = false + +function fromTextArea(textarea, options) { + options = options ? copyObj(options) : {} + options.value = textarea.value + if (!options.tabindex && textarea.tabIndex) + { options.tabindex = textarea.tabIndex } + if (!options.placeholder && textarea.placeholder) + { options.placeholder = textarea.placeholder } + // Set autofocus to true if this textarea is focused, or if it has + // autofocus and no other element is focused. + if (options.autofocus == null) { + var hasFocus = activeElt() + options.autofocus = hasFocus == textarea || + textarea.getAttribute("autofocus") != null && hasFocus == document.body + } + + function save() {textarea.value = cm.getValue()} + + var realSubmit + if (textarea.form) { + on(textarea.form, "submit", save) + // Deplorable hack to make the submit method do the right thing. + if (!options.leaveSubmitMethodAlone) { + var form = textarea.form + realSubmit = form.submit + try { + var wrappedSubmit = form.submit = function () { + save() + form.submit = realSubmit + form.submit() + form.submit = wrappedSubmit + } + } catch(e) {} + } + } + + options.finishInit = function (cm) { + cm.save = save + cm.getTextArea = function () { return textarea; } + cm.toTextArea = function () { + cm.toTextArea = isNaN // Prevent this from being ran twice + save() + textarea.parentNode.removeChild(cm.getWrapperElement()) + textarea.style.display = "" + if (textarea.form) { + off(textarea.form, "submit", save) + if (typeof textarea.form.submit == "function") + { textarea.form.submit = realSubmit } + } + } + } + + textarea.style.display = "none" + var cm = CodeMirror(function (node) { return textarea.parentNode.insertBefore(node, textarea.nextSibling); }, + options) + return cm +} + +function addLegacyProps(CodeMirror) { + CodeMirror.off = off + CodeMirror.on = on + CodeMirror.wheelEventPixels = wheelEventPixels + CodeMirror.Doc = Doc + CodeMirror.splitLines = splitLinesAuto + CodeMirror.countColumn = countColumn + CodeMirror.findColumn = findColumn + CodeMirror.isWordChar = isWordCharBasic + CodeMirror.Pass = Pass + CodeMirror.signal = signal + CodeMirror.Line = Line + CodeMirror.changeEnd = changeEnd + CodeMirror.scrollbarModel = scrollbarModel + CodeMirror.Pos = Pos + CodeMirror.cmpPos = cmp + CodeMirror.modes = modes + CodeMirror.mimeModes = mimeModes + CodeMirror.resolveMode = resolveMode + CodeMirror.getMode = getMode + CodeMirror.modeExtensions = modeExtensions + CodeMirror.extendMode = extendMode + CodeMirror.copyState = copyState + CodeMirror.startState = startState + CodeMirror.innerMode = innerMode + CodeMirror.commands = commands + CodeMirror.keyMap = keyMap + CodeMirror.keyName = keyName + CodeMirror.isModifierKey = isModifierKey + CodeMirror.lookupKey = lookupKey + CodeMirror.normalizeKeyMap = normalizeKeyMap + CodeMirror.StringStream = StringStream + CodeMirror.SharedTextMarker = SharedTextMarker + CodeMirror.TextMarker = TextMarker + CodeMirror.LineWidget = LineWidget + CodeMirror.e_preventDefault = e_preventDefault + CodeMirror.e_stopPropagation = e_stopPropagation + CodeMirror.e_stop = e_stop + CodeMirror.addClass = addClass + CodeMirror.contains = contains + CodeMirror.rmClass = rmClass + CodeMirror.keyNames = keyNames +} + +// EDITOR CONSTRUCTOR + +defineOptions(CodeMirror) + +addEditorMethods(CodeMirror) + +// Set up methods on CodeMirror's prototype to redirect to the editor's document. +var dontDelegate = "iter insert remove copy getEditor constructor".split(" ") +for (var prop in Doc.prototype) { if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0) + { CodeMirror.prototype[prop] = (function(method) { + return function() {return method.apply(this.doc, arguments)} + })(Doc.prototype[prop]) } } + +eventMixin(Doc) + +// INPUT HANDLING + +CodeMirror.inputStyles = {"textarea": TextareaInput, "contenteditable": ContentEditableInput} + +// MODE DEFINITION AND QUERYING + +// Extra arguments are stored as the mode's dependencies, which is +// used by (legacy) mechanisms like loadmode.js to automatically +// load a mode. (Preferred mechanism is the require/define calls.) +CodeMirror.defineMode = function(name/*, mode, …*/) { + if (!CodeMirror.defaults.mode && name != "null") { CodeMirror.defaults.mode = name } + defineMode.apply(this, arguments) +} + +CodeMirror.defineMIME = defineMIME + +// Minimal default mode. +CodeMirror.defineMode("null", function () { return ({token: function (stream) { return stream.skipToEnd(); }}); }) +CodeMirror.defineMIME("text/plain", "null") + +// EXTENSIONS + +CodeMirror.defineExtension = function (name, func) { + CodeMirror.prototype[name] = func +} +CodeMirror.defineDocExtension = function (name, func) { + Doc.prototype[name] = func +} + +CodeMirror.fromTextArea = fromTextArea + +addLegacyProps(CodeMirror) + +CodeMirror.version = "5.39.1" + +return CodeMirror; + +}))); \ No newline at end of file diff --git a/frontend/public/js/css.js b/frontend/public/js/css.js new file mode 100644 index 00000000..f5f3a41b --- /dev/null +++ b/frontend/public/js/css.js @@ -0,0 +1,832 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("css", function(config, parserConfig) { + var inline = parserConfig.inline + if (!parserConfig.propertyKeywords) parserConfig = CodeMirror.resolveMode("text/css"); + + var indentUnit = config.indentUnit, + tokenHooks = parserConfig.tokenHooks, + documentTypes = parserConfig.documentTypes || {}, + mediaTypes = parserConfig.mediaTypes || {}, + mediaFeatures = parserConfig.mediaFeatures || {}, + mediaValueKeywords = parserConfig.mediaValueKeywords || {}, + propertyKeywords = parserConfig.propertyKeywords || {}, + nonStandardPropertyKeywords = parserConfig.nonStandardPropertyKeywords || {}, + fontProperties = parserConfig.fontProperties || {}, + counterDescriptors = parserConfig.counterDescriptors || {}, + colorKeywords = parserConfig.colorKeywords || {}, + valueKeywords = parserConfig.valueKeywords || {}, + allowNested = parserConfig.allowNested, + lineComment = parserConfig.lineComment, + supportsAtComponent = parserConfig.supportsAtComponent === true; + + var type, override; + function ret(style, tp) { type = tp; return style; } + + // Tokenizers + + function tokenBase(stream, state) { + var ch = stream.next(); + if (tokenHooks[ch]) { + var result = tokenHooks[ch](stream, state); + if (result !== false) return result; + } + if (ch == "@") { + stream.eatWhile(/[\w\\\-]/); + return ret("def", stream.current()); + } else if (ch == "=" || (ch == "~" || ch == "|") && stream.eat("=")) { + return ret(null, "compare"); + } else if (ch == "\"" || ch == "'") { + state.tokenize = tokenString(ch); + return state.tokenize(stream, state); + } else if (ch == "#") { + stream.eatWhile(/[\w\\\-]/); + return ret("atom", "hash"); + } else if (ch == "!") { + stream.match(/^\s*\w*/); + return ret("keyword", "important"); + } else if (/\d/.test(ch) || ch == "." && stream.eat(/\d/)) { + stream.eatWhile(/[\w.%]/); + return ret("number", "unit"); + } else if (ch === "-") { + if (/[\d.]/.test(stream.peek())) { + stream.eatWhile(/[\w.%]/); + return ret("number", "unit"); + } else if (stream.match(/^-[\w\\\-]+/)) { + stream.eatWhile(/[\w\\\-]/); + if (stream.match(/^\s*:/, false)) + return ret("variable-2", "variable-definition"); + return ret("variable-2", "variable"); + } else if (stream.match(/^\w+-/)) { + return ret("meta", "meta"); + } + } else if (/[,+>*\/]/.test(ch)) { + return ret(null, "select-op"); + } else if (ch == "." && stream.match(/^-?[_a-z][_a-z0-9-]*/i)) { + return ret("qualifier", "qualifier"); + } else if (/[:;{}\[\]\(\)]/.test(ch)) { + return ret(null, ch); + } else if (((ch == "u" || ch == "U") && stream.match(/rl(-prefix)?\(/i)) || + ((ch == "d" || ch == "D") && stream.match("omain(", true, true)) || + ((ch == "r" || ch == "R") && stream.match("egexp(", true, true))) { + stream.backUp(1); + state.tokenize = tokenParenthesized; + return ret("property", "word"); + } else if (/[\w\\\-]/.test(ch)) { + stream.eatWhile(/[\w\\\-]/); + return ret("property", "word"); + } else { + return ret(null, null); + } + } + + function tokenString(quote) { + return function(stream, state) { + var escaped = false, ch; + while ((ch = stream.next()) != null) { + if (ch == quote && !escaped) { + if (quote == ")") stream.backUp(1); + break; + } + escaped = !escaped && ch == "\\"; + } + if (ch == quote || !escaped && quote != ")") state.tokenize = null; + return ret("string", "string"); + }; + } + + function tokenParenthesized(stream, state) { + stream.next(); // Must be '(' + if (!stream.match(/\s*[\"\')]/, false)) + state.tokenize = tokenString(")"); + else + state.tokenize = null; + return ret(null, "("); + } + + // Context management + + function Context(type, indent, prev) { + this.type = type; + this.indent = indent; + this.prev = prev; + } + + function pushContext(state, stream, type, indent) { + state.context = new Context(type, stream.indentation() + (indent === false ? 0 : indentUnit), state.context); + return type; + } + + function popContext(state) { + if (state.context.prev) + state.context = state.context.prev; + return state.context.type; + } + + function pass(type, stream, state) { + return states[state.context.type](type, stream, state); + } + function popAndPass(type, stream, state, n) { + for (var i = n || 1; i > 0; i--) + state.context = state.context.prev; + return pass(type, stream, state); + } + + // Parser + + function wordAsValue(stream) { + var word = stream.current().toLowerCase(); + if (valueKeywords.hasOwnProperty(word)) + override = "atom"; + else if (colorKeywords.hasOwnProperty(word)) + override = "keyword"; + else + override = "variable"; + } + + var states = {}; + + states.top = function(type, stream, state) { + if (type == "{") { + return pushContext(state, stream, "block"); + } else if (type == "}" && state.context.prev) { + return popContext(state); + } else if (supportsAtComponent && /@component/i.test(type)) { + return pushContext(state, stream, "atComponentBlock"); + } else if (/^@(-moz-)?document$/i.test(type)) { + return pushContext(state, stream, "documentTypes"); + } else if (/^@(media|supports|(-moz-)?document|import)$/i.test(type)) { + return pushContext(state, stream, "atBlock"); + } else if (/^@(font-face|counter-style)/i.test(type)) { + state.stateArg = type; + return "restricted_atBlock_before"; + } else if (/^@(-(moz|ms|o|webkit)-)?keyframes$/i.test(type)) { + return "keyframes"; + } else if (type && type.charAt(0) == "@") { + return pushContext(state, stream, "at"); + } else if (type == "hash") { + override = "builtin"; + } else if (type == "word") { + override = "tag"; + } else if (type == "variable-definition") { + return "maybeprop"; + } else if (type == "interpolation") { + return pushContext(state, stream, "interpolation"); + } else if (type == ":") { + return "pseudo"; + } else if (allowNested && type == "(") { + return pushContext(state, stream, "parens"); + } + return state.context.type; + }; + + states.block = function(type, stream, state) { + if (type == "word") { + var word = stream.current().toLowerCase(); + if (propertyKeywords.hasOwnProperty(word)) { + override = "property"; + return "maybeprop"; + } else if (nonStandardPropertyKeywords.hasOwnProperty(word)) { + override = "string-2"; + return "maybeprop"; + } else if (allowNested) { + override = stream.match(/^\s*:(?:\s|$)/, false) ? "property" : "tag"; + return "block"; + } else { + override += " error"; + return "maybeprop"; + } + } else if (type == "meta") { + return "block"; + } else if (!allowNested && (type == "hash" || type == "qualifier")) { + override = "error"; + return "block"; + } else { + return states.top(type, stream, state); + } + }; + + states.maybeprop = function(type, stream, state) { + if (type == ":") return pushContext(state, stream, "prop"); + return pass(type, stream, state); + }; + + states.prop = function(type, stream, state) { + if (type == ";") return popContext(state); + if (type == "{" && allowNested) return pushContext(state, stream, "propBlock"); + if (type == "}" || type == "{") return popAndPass(type, stream, state); + if (type == "(") return pushContext(state, stream, "parens"); + + if (type == "hash" && !/^#([0-9a-fA-f]{3,4}|[0-9a-fA-f]{6}|[0-9a-fA-f]{8})$/.test(stream.current())) { + override += " error"; + } else if (type == "word") { + wordAsValue(stream); + } else if (type == "interpolation") { + return pushContext(state, stream, "interpolation"); + } + return "prop"; + }; + + states.propBlock = function(type, _stream, state) { + if (type == "}") return popContext(state); + if (type == "word") { override = "property"; return "maybeprop"; } + return state.context.type; + }; + + states.parens = function(type, stream, state) { + if (type == "{" || type == "}") return popAndPass(type, stream, state); + if (type == ")") return popContext(state); + if (type == "(") return pushContext(state, stream, "parens"); + if (type == "interpolation") return pushContext(state, stream, "interpolation"); + if (type == "word") wordAsValue(stream); + return "parens"; + }; + + states.pseudo = function(type, stream, state) { + if (type == "meta") return "pseudo"; + + if (type == "word") { + override = "variable-3"; + return state.context.type; + } + return pass(type, stream, state); + }; + + states.documentTypes = function(type, stream, state) { + if (type == "word" && documentTypes.hasOwnProperty(stream.current())) { + override = "tag"; + return state.context.type; + } else { + return states.atBlock(type, stream, state); + } + }; + + states.atBlock = function(type, stream, state) { + if (type == "(") return pushContext(state, stream, "atBlock_parens"); + if (type == "}" || type == ";") return popAndPass(type, stream, state); + if (type == "{") return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top"); + + if (type == "interpolation") return pushContext(state, stream, "interpolation"); + + if (type == "word") { + var word = stream.current().toLowerCase(); + if (word == "only" || word == "not" || word == "and" || word == "or") + override = "keyword"; + else if (mediaTypes.hasOwnProperty(word)) + override = "attribute"; + else if (mediaFeatures.hasOwnProperty(word)) + override = "property"; + else if (mediaValueKeywords.hasOwnProperty(word)) + override = "keyword"; + else if (propertyKeywords.hasOwnProperty(word)) + override = "property"; + else if (nonStandardPropertyKeywords.hasOwnProperty(word)) + override = "string-2"; + else if (valueKeywords.hasOwnProperty(word)) + override = "atom"; + else if (colorKeywords.hasOwnProperty(word)) + override = "keyword"; + else + override = "error"; + } + return state.context.type; + }; + + states.atComponentBlock = function(type, stream, state) { + if (type == "}") + return popAndPass(type, stream, state); + if (type == "{") + return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top", false); + if (type == "word") + override = "error"; + return state.context.type; + }; + + states.atBlock_parens = function(type, stream, state) { + if (type == ")") return popContext(state); + if (type == "{" || type == "}") return popAndPass(type, stream, state, 2); + return states.atBlock(type, stream, state); + }; + + states.restricted_atBlock_before = function(type, stream, state) { + if (type == "{") + return pushContext(state, stream, "restricted_atBlock"); + if (type == "word" && state.stateArg == "@counter-style") { + override = "variable"; + return "restricted_atBlock_before"; + } + return pass(type, stream, state); + }; + + states.restricted_atBlock = function(type, stream, state) { + if (type == "}") { + state.stateArg = null; + return popContext(state); + } + if (type == "word") { + if ((state.stateArg == "@font-face" && !fontProperties.hasOwnProperty(stream.current().toLowerCase())) || + (state.stateArg == "@counter-style" && !counterDescriptors.hasOwnProperty(stream.current().toLowerCase()))) + override = "error"; + else + override = "property"; + return "maybeprop"; + } + return "restricted_atBlock"; + }; + + states.keyframes = function(type, stream, state) { + if (type == "word") { override = "variable"; return "keyframes"; } + if (type == "{") return pushContext(state, stream, "top"); + return pass(type, stream, state); + }; + + states.at = function(type, stream, state) { + if (type == ";") return popContext(state); + if (type == "{" || type == "}") return popAndPass(type, stream, state); + if (type == "word") override = "tag"; + else if (type == "hash") override = "builtin"; + return "at"; + }; + + states.interpolation = function(type, stream, state) { + if (type == "}") return popContext(state); + if (type == "{" || type == ";") return popAndPass(type, stream, state); + if (type == "word") override = "variable"; + else if (type != "variable" && type != "(" && type != ")") override = "error"; + return "interpolation"; + }; + + return { + startState: function(base) { + return {tokenize: null, + state: inline ? "block" : "top", + stateArg: null, + context: new Context(inline ? "block" : "top", base || 0, null)}; + }, + + token: function(stream, state) { + if (!state.tokenize && stream.eatSpace()) return null; + var style = (state.tokenize || tokenBase)(stream, state); + if (style && typeof style == "object") { + type = style[1]; + style = style[0]; + } + override = style; + if (type != "comment") + state.state = states[state.state](type, stream, state); + return override; + }, + + indent: function(state, textAfter) { + var cx = state.context, ch = textAfter && textAfter.charAt(0); + var indent = cx.indent; + if (cx.type == "prop" && (ch == "}" || ch == ")")) cx = cx.prev; + if (cx.prev) { + if (ch == "}" && (cx.type == "block" || cx.type == "top" || + cx.type == "interpolation" || cx.type == "restricted_atBlock")) { + // Resume indentation from parent context. + cx = cx.prev; + indent = cx.indent; + } else if (ch == ")" && (cx.type == "parens" || cx.type == "atBlock_parens") || + ch == "{" && (cx.type == "at" || cx.type == "atBlock")) { + // Dedent relative to current context. + indent = Math.max(0, cx.indent - indentUnit); + } + } + return indent; + }, + + electricChars: "}", + blockCommentStart: "/*", + blockCommentEnd: "*/", + blockCommentContinue: " * ", + lineComment: lineComment, + fold: "brace" + }; +}); + + function keySet(array) { + var keys = {}; + for (var i = 0; i < array.length; ++i) { + keys[array[i].toLowerCase()] = true; + } + return keys; + } + + var documentTypes_ = [ + "domain", "regexp", "url", "url-prefix" + ], documentTypes = keySet(documentTypes_); + + var mediaTypes_ = [ + "all", "aural", "braille", "handheld", "print", "projection", "screen", + "tty", "tv", "embossed" + ], mediaTypes = keySet(mediaTypes_); + + var mediaFeatures_ = [ + "width", "min-width", "max-width", "height", "min-height", "max-height", + "device-width", "min-device-width", "max-device-width", "device-height", + "min-device-height", "max-device-height", "aspect-ratio", + "min-aspect-ratio", "max-aspect-ratio", "device-aspect-ratio", + "min-device-aspect-ratio", "max-device-aspect-ratio", "color", "min-color", + "max-color", "color-index", "min-color-index", "max-color-index", + "monochrome", "min-monochrome", "max-monochrome", "resolution", + "min-resolution", "max-resolution", "scan", "grid", "orientation", + "device-pixel-ratio", "min-device-pixel-ratio", "max-device-pixel-ratio", + "pointer", "any-pointer", "hover", "any-hover" + ], mediaFeatures = keySet(mediaFeatures_); + + var mediaValueKeywords_ = [ + "landscape", "portrait", "none", "coarse", "fine", "on-demand", "hover", + "interlace", "progressive" + ], mediaValueKeywords = keySet(mediaValueKeywords_); + + var propertyKeywords_ = [ + "align-content", "align-items", "align-self", "alignment-adjust", + "alignment-baseline", "anchor-point", "animation", "animation-delay", + "animation-direction", "animation-duration", "animation-fill-mode", + "animation-iteration-count", "animation-name", "animation-play-state", + "animation-timing-function", "appearance", "azimuth", "backface-visibility", + "background", "background-attachment", "background-blend-mode", "background-clip", + "background-color", "background-image", "background-origin", "background-position", + "background-repeat", "background-size", "baseline-shift", "binding", + "bleed", "bookmark-label", "bookmark-level", "bookmark-state", + "bookmark-target", "border", "border-bottom", "border-bottom-color", + "border-bottom-left-radius", "border-bottom-right-radius", + "border-bottom-style", "border-bottom-width", "border-collapse", + "border-color", "border-image", "border-image-outset", + "border-image-repeat", "border-image-slice", "border-image-source", + "border-image-width", "border-left", "border-left-color", + "border-left-style", "border-left-width", "border-radius", "border-right", + "border-right-color", "border-right-style", "border-right-width", + "border-spacing", "border-style", "border-top", "border-top-color", + "border-top-left-radius", "border-top-right-radius", "border-top-style", + "border-top-width", "border-width", "bottom", "box-decoration-break", + "box-shadow", "box-sizing", "break-after", "break-before", "break-inside", + "caption-side", "caret-color", "clear", "clip", "color", "color-profile", "column-count", + "column-fill", "column-gap", "column-rule", "column-rule-color", + "column-rule-style", "column-rule-width", "column-span", "column-width", + "columns", "content", "counter-increment", "counter-reset", "crop", "cue", + "cue-after", "cue-before", "cursor", "direction", "display", + "dominant-baseline", "drop-initial-after-adjust", + "drop-initial-after-align", "drop-initial-before-adjust", + "drop-initial-before-align", "drop-initial-size", "drop-initial-value", + "elevation", "empty-cells", "fit", "fit-position", "flex", "flex-basis", + "flex-direction", "flex-flow", "flex-grow", "flex-shrink", "flex-wrap", + "float", "float-offset", "flow-from", "flow-into", "font", "font-feature-settings", + "font-family", "font-kerning", "font-language-override", "font-size", "font-size-adjust", + "font-stretch", "font-style", "font-synthesis", "font-variant", + "font-variant-alternates", "font-variant-caps", "font-variant-east-asian", + "font-variant-ligatures", "font-variant-numeric", "font-variant-position", + "font-weight", "grid", "grid-area", "grid-auto-columns", "grid-auto-flow", + "grid-auto-rows", "grid-column", "grid-column-end", "grid-column-gap", + "grid-column-start", "grid-gap", "grid-row", "grid-row-end", "grid-row-gap", + "grid-row-start", "grid-template", "grid-template-areas", "grid-template-columns", + "grid-template-rows", "hanging-punctuation", "height", "hyphens", + "icon", "image-orientation", "image-rendering", "image-resolution", + "inline-box-align", "justify-content", "justify-items", "justify-self", "left", "letter-spacing", + "line-break", "line-height", "line-stacking", "line-stacking-ruby", + "line-stacking-shift", "line-stacking-strategy", "list-style", + "list-style-image", "list-style-position", "list-style-type", "margin", + "margin-bottom", "margin-left", "margin-right", "margin-top", + "marks", "marquee-direction", "marquee-loop", + "marquee-play-count", "marquee-speed", "marquee-style", "max-height", + "max-width", "min-height", "min-width", "move-to", "nav-down", "nav-index", + "nav-left", "nav-right", "nav-up", "object-fit", "object-position", + "opacity", "order", "orphans", "outline", + "outline-color", "outline-offset", "outline-style", "outline-width", + "overflow", "overflow-style", "overflow-wrap", "overflow-x", "overflow-y", + "padding", "padding-bottom", "padding-left", "padding-right", "padding-top", + "page", "page-break-after", "page-break-before", "page-break-inside", + "page-policy", "pause", "pause-after", "pause-before", "perspective", + "perspective-origin", "pitch", "pitch-range", "place-content", "place-items", "place-self", "play-during", "position", + "presentation-level", "punctuation-trim", "quotes", "region-break-after", + "region-break-before", "region-break-inside", "region-fragment", + "rendering-intent", "resize", "rest", "rest-after", "rest-before", "richness", + "right", "rotation", "rotation-point", "ruby-align", "ruby-overhang", + "ruby-position", "ruby-span", "shape-image-threshold", "shape-inside", "shape-margin", + "shape-outside", "size", "speak", "speak-as", "speak-header", + "speak-numeral", "speak-punctuation", "speech-rate", "stress", "string-set", + "tab-size", "table-layout", "target", "target-name", "target-new", + "target-position", "text-align", "text-align-last", "text-decoration", + "text-decoration-color", "text-decoration-line", "text-decoration-skip", + "text-decoration-style", "text-emphasis", "text-emphasis-color", + "text-emphasis-position", "text-emphasis-style", "text-height", + "text-indent", "text-justify", "text-outline", "text-overflow", "text-shadow", + "text-size-adjust", "text-space-collapse", "text-transform", "text-underline-position", + "text-wrap", "top", "transform", "transform-origin", "transform-style", + "transition", "transition-delay", "transition-duration", + "transition-property", "transition-timing-function", "unicode-bidi", + "user-select", "vertical-align", "visibility", "voice-balance", "voice-duration", + "voice-family", "voice-pitch", "voice-range", "voice-rate", "voice-stress", + "voice-volume", "volume", "white-space", "widows", "width", "will-change", "word-break", + "word-spacing", "word-wrap", "z-index", + // SVG-specific + "clip-path", "clip-rule", "mask", "enable-background", "filter", "flood-color", + "flood-opacity", "lighting-color", "stop-color", "stop-opacity", "pointer-events", + "color-interpolation", "color-interpolation-filters", + "color-rendering", "fill", "fill-opacity", "fill-rule", "image-rendering", + "marker", "marker-end", "marker-mid", "marker-start", "shape-rendering", "stroke", + "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", + "stroke-miterlimit", "stroke-opacity", "stroke-width", "text-rendering", + "baseline-shift", "dominant-baseline", "glyph-orientation-horizontal", + "glyph-orientation-vertical", "text-anchor", "writing-mode" + ], propertyKeywords = keySet(propertyKeywords_); + + var nonStandardPropertyKeywords_ = [ + "scrollbar-arrow-color", "scrollbar-base-color", "scrollbar-dark-shadow-color", + "scrollbar-face-color", "scrollbar-highlight-color", "scrollbar-shadow-color", + "scrollbar-3d-light-color", "scrollbar-track-color", "shape-inside", + "searchfield-cancel-button", "searchfield-decoration", "searchfield-results-button", + "searchfield-results-decoration", "zoom" + ], nonStandardPropertyKeywords = keySet(nonStandardPropertyKeywords_); + + var fontProperties_ = [ + "font-family", "src", "unicode-range", "font-variant", "font-feature-settings", + "font-stretch", "font-weight", "font-style" + ], fontProperties = keySet(fontProperties_); + + var counterDescriptors_ = [ + "additive-symbols", "fallback", "negative", "pad", "prefix", "range", + "speak-as", "suffix", "symbols", "system" + ], counterDescriptors = keySet(counterDescriptors_); + + var colorKeywords_ = [ + "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige", + "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown", + "burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue", + "cornsilk", "crimson", "cyan", "darkblue", "darkcyan", "darkgoldenrod", + "darkgray", "darkgreen", "darkkhaki", "darkmagenta", "darkolivegreen", + "darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen", + "darkslateblue", "darkslategray", "darkturquoise", "darkviolet", + "deeppink", "deepskyblue", "dimgray", "dodgerblue", "firebrick", + "floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite", + "gold", "goldenrod", "gray", "grey", "green", "greenyellow", "honeydew", + "hotpink", "indianred", "indigo", "ivory", "khaki", "lavender", + "lavenderblush", "lawngreen", "lemonchiffon", "lightblue", "lightcoral", + "lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", "lightpink", + "lightsalmon", "lightseagreen", "lightskyblue", "lightslategray", + "lightsteelblue", "lightyellow", "lime", "limegreen", "linen", "magenta", + "maroon", "mediumaquamarine", "mediumblue", "mediumorchid", "mediumpurple", + "mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise", + "mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin", + "navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange", "orangered", + "orchid", "palegoldenrod", "palegreen", "paleturquoise", "palevioletred", + "papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue", + "purple", "rebeccapurple", "red", "rosybrown", "royalblue", "saddlebrown", + "salmon", "sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue", + "slateblue", "slategray", "snow", "springgreen", "steelblue", "tan", + "teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white", + "whitesmoke", "yellow", "yellowgreen" + ], colorKeywords = keySet(colorKeywords_); + + var valueKeywords_ = [ + "above", "absolute", "activeborder", "additive", "activecaption", "afar", + "after-white-space", "ahead", "alias", "all", "all-scroll", "alphabetic", "alternate", + "always", "amharic", "amharic-abegede", "antialiased", "appworkspace", + "arabic-indic", "armenian", "asterisks", "attr", "auto", "auto-flow", "avoid", "avoid-column", "avoid-page", + "avoid-region", "background", "backwards", "baseline", "below", "bidi-override", "binary", + "bengali", "blink", "block", "block-axis", "bold", "bolder", "border", "border-box", + "both", "bottom", "break", "break-all", "break-word", "bullets", "button", "button-bevel", + "buttonface", "buttonhighlight", "buttonshadow", "buttontext", "calc", "cambodian", + "capitalize", "caps-lock-indicator", "caption", "captiontext", "caret", + "cell", "center", "checkbox", "circle", "cjk-decimal", "cjk-earthly-branch", + "cjk-heavenly-stem", "cjk-ideographic", "clear", "clip", "close-quote", + "col-resize", "collapse", "color", "color-burn", "color-dodge", "column", "column-reverse", + "compact", "condensed", "contain", "content", "contents", + "content-box", "context-menu", "continuous", "copy", "counter", "counters", "cover", "crop", + "cross", "crosshair", "currentcolor", "cursive", "cyclic", "darken", "dashed", "decimal", + "decimal-leading-zero", "default", "default-button", "dense", "destination-atop", + "destination-in", "destination-out", "destination-over", "devanagari", "difference", + "disc", "discard", "disclosure-closed", "disclosure-open", "document", + "dot-dash", "dot-dot-dash", + "dotted", "double", "down", "e-resize", "ease", "ease-in", "ease-in-out", "ease-out", + "element", "ellipse", "ellipsis", "embed", "end", "ethiopic", "ethiopic-abegede", + "ethiopic-abegede-am-et", "ethiopic-abegede-gez", "ethiopic-abegede-ti-er", + "ethiopic-abegede-ti-et", "ethiopic-halehame-aa-er", + "ethiopic-halehame-aa-et", "ethiopic-halehame-am-et", + "ethiopic-halehame-gez", "ethiopic-halehame-om-et", + "ethiopic-halehame-sid-et", "ethiopic-halehame-so-et", + "ethiopic-halehame-ti-er", "ethiopic-halehame-ti-et", "ethiopic-halehame-tig", + "ethiopic-numeric", "ew-resize", "exclusion", "expanded", "extends", "extra-condensed", + "extra-expanded", "fantasy", "fast", "fill", "fixed", "flat", "flex", "flex-end", "flex-start", "footnotes", + "forwards", "from", "geometricPrecision", "georgian", "graytext", "grid", "groove", + "gujarati", "gurmukhi", "hand", "hangul", "hangul-consonant", "hard-light", "hebrew", + "help", "hidden", "hide", "higher", "highlight", "highlighttext", + "hiragana", "hiragana-iroha", "horizontal", "hsl", "hsla", "hue", "icon", "ignore", + "inactiveborder", "inactivecaption", "inactivecaptiontext", "infinite", + "infobackground", "infotext", "inherit", "initial", "inline", "inline-axis", + "inline-block", "inline-flex", "inline-grid", "inline-table", "inset", "inside", "intrinsic", "invert", + "italic", "japanese-formal", "japanese-informal", "justify", "kannada", + "katakana", "katakana-iroha", "keep-all", "khmer", + "korean-hangul-formal", "korean-hanja-formal", "korean-hanja-informal", + "landscape", "lao", "large", "larger", "left", "level", "lighter", "lighten", + "line-through", "linear", "linear-gradient", "lines", "list-item", "listbox", "listitem", + "local", "logical", "loud", "lower", "lower-alpha", "lower-armenian", + "lower-greek", "lower-hexadecimal", "lower-latin", "lower-norwegian", + "lower-roman", "lowercase", "ltr", "luminosity", "malayalam", "match", "matrix", "matrix3d", + "media-controls-background", "media-current-time-display", + "media-fullscreen-button", "media-mute-button", "media-play-button", + "media-return-to-realtime-button", "media-rewind-button", + "media-seek-back-button", "media-seek-forward-button", "media-slider", + "media-sliderthumb", "media-time-remaining-display", "media-volume-slider", + "media-volume-slider-container", "media-volume-sliderthumb", "medium", + "menu", "menulist", "menulist-button", "menulist-text", + "menulist-textfield", "menutext", "message-box", "middle", "min-intrinsic", + "mix", "mongolian", "monospace", "move", "multiple", "multiply", "myanmar", "n-resize", + "narrower", "ne-resize", "nesw-resize", "no-close-quote", "no-drop", + "no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap", + "ns-resize", "numbers", "numeric", "nw-resize", "nwse-resize", "oblique", "octal", "opacity", "open-quote", + "optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset", + "outside", "outside-shape", "overlay", "overline", "padding", "padding-box", + "painted", "page", "paused", "persian", "perspective", "plus-darker", "plus-lighter", + "pointer", "polygon", "portrait", "pre", "pre-line", "pre-wrap", "preserve-3d", + "progress", "push-button", "radial-gradient", "radio", "read-only", + "read-write", "read-write-plaintext-only", "rectangle", "region", + "relative", "repeat", "repeating-linear-gradient", + "repeating-radial-gradient", "repeat-x", "repeat-y", "reset", "reverse", + "rgb", "rgba", "ridge", "right", "rotate", "rotate3d", "rotateX", "rotateY", + "rotateZ", "round", "row", "row-resize", "row-reverse", "rtl", "run-in", "running", + "s-resize", "sans-serif", "saturation", "scale", "scale3d", "scaleX", "scaleY", "scaleZ", "screen", + "scroll", "scrollbar", "scroll-position", "se-resize", "searchfield", + "searchfield-cancel-button", "searchfield-decoration", + "searchfield-results-button", "searchfield-results-decoration", "self-start", "self-end", + "semi-condensed", "semi-expanded", "separate", "serif", "show", "sidama", + "simp-chinese-formal", "simp-chinese-informal", "single", + "skew", "skewX", "skewY", "skip-white-space", "slide", "slider-horizontal", + "slider-vertical", "sliderthumb-horizontal", "sliderthumb-vertical", "slow", + "small", "small-caps", "small-caption", "smaller", "soft-light", "solid", "somali", + "source-atop", "source-in", "source-out", "source-over", "space", "space-around", "space-between", "space-evenly", "spell-out", "square", + "square-button", "start", "static", "status-bar", "stretch", "stroke", "sub", + "subpixel-antialiased", "super", "sw-resize", "symbolic", "symbols", "system-ui", "table", + "table-caption", "table-cell", "table-column", "table-column-group", + "table-footer-group", "table-header-group", "table-row", "table-row-group", + "tamil", + "telugu", "text", "text-bottom", "text-top", "textarea", "textfield", "thai", + "thick", "thin", "threeddarkshadow", "threedface", "threedhighlight", + "threedlightshadow", "threedshadow", "tibetan", "tigre", "tigrinya-er", + "tigrinya-er-abegede", "tigrinya-et", "tigrinya-et-abegede", "to", "top", + "trad-chinese-formal", "trad-chinese-informal", "transform", + "translate", "translate3d", "translateX", "translateY", "translateZ", + "transparent", "ultra-condensed", "ultra-expanded", "underline", "unset", "up", + "upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal", + "upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url", + "var", "vertical", "vertical-text", "visible", "visibleFill", "visiblePainted", + "visibleStroke", "visual", "w-resize", "wait", "wave", "wider", + "window", "windowframe", "windowtext", "words", "wrap", "wrap-reverse", "x-large", "x-small", "xor", + "xx-large", "xx-small" + ], valueKeywords = keySet(valueKeywords_); + + var allWords = documentTypes_.concat(mediaTypes_).concat(mediaFeatures_).concat(mediaValueKeywords_) + .concat(propertyKeywords_).concat(nonStandardPropertyKeywords_).concat(colorKeywords_) + .concat(valueKeywords_); + CodeMirror.registerHelper("hintWords", "css", allWords); + + function tokenCComment(stream, state) { + var maybeEnd = false, ch; + while ((ch = stream.next()) != null) { + if (maybeEnd && ch == "/") { + state.tokenize = null; + break; + } + maybeEnd = (ch == "*"); + } + return ["comment", "comment"]; + } + + CodeMirror.defineMIME("text/css", { + documentTypes: documentTypes, + mediaTypes: mediaTypes, + mediaFeatures: mediaFeatures, + mediaValueKeywords: mediaValueKeywords, + propertyKeywords: propertyKeywords, + nonStandardPropertyKeywords: nonStandardPropertyKeywords, + fontProperties: fontProperties, + counterDescriptors: counterDescriptors, + colorKeywords: colorKeywords, + valueKeywords: valueKeywords, + tokenHooks: { + "/": function(stream, state) { + if (!stream.eat("*")) return false; + state.tokenize = tokenCComment; + return tokenCComment(stream, state); + } + }, + name: "css" + }); + + CodeMirror.defineMIME("text/x-scss", { + mediaTypes: mediaTypes, + mediaFeatures: mediaFeatures, + mediaValueKeywords: mediaValueKeywords, + propertyKeywords: propertyKeywords, + nonStandardPropertyKeywords: nonStandardPropertyKeywords, + colorKeywords: colorKeywords, + valueKeywords: valueKeywords, + fontProperties: fontProperties, + allowNested: true, + lineComment: "//", + tokenHooks: { + "/": function(stream, state) { + if (stream.eat("/")) { + stream.skipToEnd(); + return ["comment", "comment"]; + } else if (stream.eat("*")) { + state.tokenize = tokenCComment; + return tokenCComment(stream, state); + } else { + return ["operator", "operator"]; + } + }, + ":": function(stream) { + if (stream.match(/\s*\{/, false)) + return [null, null] + return false; + }, + "$": function(stream) { + stream.match(/^[\w-]+/); + if (stream.match(/^\s*:/, false)) + return ["variable-2", "variable-definition"]; + return ["variable-2", "variable"]; + }, + "#": function(stream) { + if (!stream.eat("{")) return false; + return [null, "interpolation"]; + } + }, + name: "css", + helperType: "scss" + }); + + CodeMirror.defineMIME("text/x-less", { + mediaTypes: mediaTypes, + mediaFeatures: mediaFeatures, + mediaValueKeywords: mediaValueKeywords, + propertyKeywords: propertyKeywords, + nonStandardPropertyKeywords: nonStandardPropertyKeywords, + colorKeywords: colorKeywords, + valueKeywords: valueKeywords, + fontProperties: fontProperties, + allowNested: true, + lineComment: "//", + tokenHooks: { + "/": function(stream, state) { + if (stream.eat("/")) { + stream.skipToEnd(); + return ["comment", "comment"]; + } else if (stream.eat("*")) { + state.tokenize = tokenCComment; + return tokenCComment(stream, state); + } else { + return ["operator", "operator"]; + } + }, + "@": function(stream) { + if (stream.eat("{")) return [null, "interpolation"]; + if (stream.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/i, false)) return false; + stream.eatWhile(/[\w\\\-]/); + if (stream.match(/^\s*:/, false)) + return ["variable-2", "variable-definition"]; + return ["variable-2", "variable"]; + }, + "&": function() { + return ["atom", "atom"]; + } + }, + name: "css", + helperType: "less" + }); + + CodeMirror.defineMIME("text/x-gss", { + documentTypes: documentTypes, + mediaTypes: mediaTypes, + mediaFeatures: mediaFeatures, + propertyKeywords: propertyKeywords, + nonStandardPropertyKeywords: nonStandardPropertyKeywords, + fontProperties: fontProperties, + counterDescriptors: counterDescriptors, + colorKeywords: colorKeywords, + valueKeywords: valueKeywords, + supportsAtComponent: true, + tokenHooks: { + "/": function(stream, state) { + if (!stream.eat("*")) return false; + state.tokenize = tokenCComment; + return tokenCComment(stream, state); + } + }, + name: "css", + helperType: "gss" + }); + +}); diff --git a/frontend/public/js/inputTags.min.js b/frontend/public/js/inputTags.min.js new file mode 100755 index 00000000..b52d4822 --- /dev/null +++ b/frontend/public/js/inputTags.min.js @@ -0,0 +1 @@ +!function(a){a.fn.inputTags=function(b){if("inputTags"in window||(window.inputTags={instances:[]}),window.inputTags.methods={tags:function(a,b){if(a){switch(typeof a){case"string":switch(a){case"_toString":var c=d.tags.toString();return b?b(c):c;case"_toObject":var e=d._toObject(d.tags);return b?b(e):e;case"_toJSON":var e=d._toObject(d.tags),f=JSON.stringify(e);return b?b(f):f;case"_toArray":return b?b(d.tags):d.tags}var g=a.split(",");if(g.length>1){var h=d.tags;d.tags=h.concat(g)}else d.tags.push(g[0]);break;case"object":var h=d.tags;"[object Object]"===Object.prototype.toString.call(a)&&(a=Object.keys(a).map(function(b){return a[b]})),d.tags=h.concat(a);break;case"function":return a(d.tags)}if(d._clean(),d._fill(),d._updateValue(),d.destroy(),d._setInstance(d),b)return b(d.tags)}return d.tags},event:function(a,b){d.options[a]=b,d._setInstance(d)},options:function(a,b){return a||b?b?(d.options[a]=b,void d._setInstance(d)):d.options[a]:d.options},destroy:function(){var b=a(this).attr("data-uniqid");delete window.inputTags.instances[b]}},"object"==typeof b||!b){var b=a.extend(!0,{},a.fn.inputTags.defaults,b);this.each(function(){var c=a(this);c.UNIQID=Math.round(Date.now()/(494*Math.random()-54)),c.DEFAULT_CLASS="inputTags",c.ELEMENT_CLASS=c.DEFAULT_CLASS+"-"+c.UNIQID,c.LIST_CLASS=c.DEFAULT_CLASS+"-list",c.ITEM_CLASS=c.DEFAULT_CLASS+"-item",c.ITEM_CONTENT='%s×',c.FIELD_CLASS=c.DEFAULT_CLASS+"-field",c.ERROR_CLASS=c.DEFAULT_CLASS+"-error",c.ERROR_CONTENT='

%s

',c.AUTOCOMPLETE_LIST_CLASS=c.DEFAULT_CLASS+"-autocomplete-list",c.AUTOCOMPLETE_ITEM_CLASS=c.DEFAULT_CLASS+"-autocomplete-item",c.AUTOCOMPLETE_ITEM_CONTENT='
  • %s
  • ',c.options=b,c.keys=[13,188,27],c.tags=[],c.options.keys.length>0&&(c.keys=c.keys.concat(c.options.keys)),c.init=function(){c.addClass(c.ELEMENT_CLASS).attr("data-uniqid",c.UNIQID),c.$element=a("."+c.ELEMENT_CLASS),c.$element.hide(),c.build(),c.fill(),c.save(),c.edit(),c.destroy(),c._autocomplete()._init(),c._focus()},c.build=function(){c.$html=a("
    ").addClass(c.LIST_CLASS),c.$input=a("").attr({type:"text",class:c.FIELD_CLASS}),c.$html.insertAfter(c.$element).prepend(c.$input),c.$list=c.$element.next("."+c.LIST_CLASS),c.$list.on("click",function(b){return!a(b.target).hasClass("inputTags-field")&&void c.$input.focus()})},c.fill=function(){return c._getDefaultValues(),0!==c.options.tags&&(c._concatenate(),c._updateValue(),void c._fill())},c._fill=function(){c.tags.forEach(function(a,b){var d=c._validate(a,!1);(!0===d||"max"===d&&b+1<=c.options.max)&&c._buildItem(a)})},c._clean=function(){a("."+c.ITEM_CLASS,c.$list).remove()},c.save=function(){c.$input.on("keyup",function(b){b.preventDefault();var d=b.keyCode||b.which,e=c.$input.val().trim();if(a.inArray(d,c.keys)<0)return!1;if(27===d)return c._cancel(),!1;if(e=188===d?e.slice(0,-1):e,!c._validate(e,!0))return!1;if(c.options.only&&c._exists(e))return c._errors("exists"),!1;if(c.$input.hasClass("is-edit")){var f=c.$input.attr("data-old-value");if(f===e)return c._cancel(),!0;c._update(f,e),c._clean(),c._fill()}else{if(c._autocomplete()._isSet()&&c._autocomplete()._get("only")&&a.inArray(e,c._autocomplete()._get("values"))<0)return c._autocomplete()._hide(),c._errors("autocomplete_only"),!1;if(c._exists(e)){c.$input.removeClass("is-autocomplete"),c._errors("exists");var g=a('[data-tag="'+e+'"]',c.$list);return g.addClass("is-exists"),setTimeout(function(){g.removeClass("is-exists")},300),!1}c._buildItem(e),c._insert(e)}return c._cancel(),c._updateValue(),c.destroy(),c._autocomplete()._build(),c._setInstance(c),c.$input.focus(),!1})},c.edit=function(){c.$list.on("click","."+c.ITEM_CLASS,function(b){if(a(b.target).hasClass("close-item")||!1===c.options.editable||c._autocomplete()._isSet()&&c._autocomplete()._get("only"))return c._cancel(),!0;var d=a(this).addClass("is-edit"),e=a(".value",d).text();c.$input.width(d.outerWidth()).insertAfter(d).addClass("is-edit").attr("data-old-value",e).val(e).focus(),c._bindEvent("selected"),c.$input.on("blur",function(){c._cancel(),c._bindEvent("unselected")})})},c.destroy=function(){a("."+c.ITEM_CLASS,c.$list).off("click").on("click",".close-item",function(){var b=a(this).parent("."+c.ITEM_CLASS),d=a(".value",b).text();b.addClass("is-closed"),setTimeout(function(){c._pop(d),c._updateValue(),b.remove(),c._autocomplete()._build(),c.$input.focus(),c._setInstance(c)},200)})},c._buildItem=function(b){var d=a(c.ITEM_CONTENT.replace("%s",b)),e=a("").addClass(c.ITEM_CLASS+" is-closed").attr("data-tag",b).html(d);e.insertBefore(c.$input).delay(100).queue(function(){a(this).removeClass("is-closed")})},c._getIndex=function(a){return c.tags.indexOf(a)},c._concatenate=function(){(!1===typeof c.options.max||c.options.max>0)&&c.options.tags.length>c.options.max&&c.options.tags.splice(-Math.abs(c.options.tags.length-c.options.max)),c.tags=c.tags.concat(c.options.tags)},c._getDefaultValues=function(){c.$element.val().length>0?c.tags=c.tags.concat(c.$element.val().split(",")):c.$element.attr("value","")},c._insert=function(a){c.tags.push(a),c._bindEvent(["change","create"])},c._update=function(a,b){var d=c._getIndex(a);c.tags[d]=b,c._bindEvent(["change","update"])},c._pop=function(a){var b=c._getIndex(a);return!(b<0)&&(c.tags.splice(b,1),void c._bindEvent(["change","destroy"]))},c._cancel=function(){a("."+c.ITEM_CLASS).removeClass("is-edit"),c.$input.removeClass("is-edit is-autocomplete").removeAttr("data-old-value style").val("").appendTo(c.$list)},c._autocomplete=function(){var b=c.options.autocomplete.values;return{_isSet:function(){return b.length>0},_init:function(){return!!c._autocomplete()._isSet()&&void c._autocomplete()._build()},_build:function(){c._autocomplete()._exists()&&c.$autocomplete.remove(),c.$autocomplete=a("
    @@ -123,7 +121,7 @@ notify_before_scale: "minute", }, config: { - altFormat: "Y-m-d H:iK", + altFormat: "l M J, \\at h:iK", altInput: true, enableTime: true, dateFormat: "Z", diff --git a/frontend/src/mixin.js b/frontend/src/mixin.js index d6538cf0..a317ba4e 100644 --- a/frontend/src/mixin.js +++ b/frontend/src/mixin.js @@ -10,16 +10,29 @@ export default Vue.mixin({ }, ago(seconds) { return this.now() - seconds + }, + duration(t1, t2) { + const val = (this.toUnix(t1) - this.toUnix(t2)) + if (val <= 59) { + return this.$moment.duration(val, 'seconds').get('seconds') + " seconds ago" + } + return this.$moment.duration(val, 'seconds').humanize(); }, niceDate(val) { return this.parseTime(val).format('LLLL') }, parseTime(val) { - return this.$moment(val, "YYYY-MM-DDTHH:mm:ssZ", true).local() + return this.$moment(val, this.$moment.ISO_8601, true) }, + toLocal(val, suf='at') { + return this.parseTime(val).local().format(`dddd, MMM Do \\${suf} h:mma`) + }, toUnix(val) { - return this.$moment(val).utc().format('MM-DD-YYYY') + return this.$moment(val).utc().unix().valueOf() }, + fromUnix(val) { + return this.$moment.unix(val).utc() + }, isBetween(t1, t2) { const now = this.$moment(t1).utc().valueOf() const sub = this.$moment(t2).utc().valueOf() diff --git a/frontend/src/pages/Index.vue b/frontend/src/pages/Index.vue index dd50a02d..0e94da46 100644 --- a/frontend/src/pages/Index.vue +++ b/frontend/src/pages/Index.vue @@ -13,7 +13,7 @@
    -
    +
    @@ -57,7 +57,12 @@ export default { const start = this.isBetween(new Date(), message.start_on) const end = this.isBetween(message.end_on, new Date()) return start && end - } + }, + clickService(s) { + this.$nextTick(() => { + this.$refs.s.scrollTop = 0; + }); + } } } diff --git a/frontend/src/pages/Settings.vue b/frontend/src/pages/Settings.vue index da35fc0e..ad9d0236 100644 --- a/frontend/src/pages/Settings.vue +++ b/frontend/src/pages/Settings.vue @@ -102,7 +102,7 @@ {{cache.url}} {{cache.size}} - {{cache.expiration}} + {{expireTime(cache.expiration)}} @@ -162,6 +162,9 @@ }, liClass (id) { return this.tab === id + }, + expireTime(ex) { + return this.toLocal(ex) }, async clearCache () { await Api.clearCache() diff --git a/handlers/api.go b/handlers/api.go index f3b22b6c..c018cf26 100644 --- a/handlers/api.go +++ b/handlers/api.go @@ -24,6 +24,7 @@ import ( "github.com/hunterlong/statping/types" "github.com/hunterlong/statping/utils" "net/http" + "time" ) type apiResponse struct { @@ -86,9 +87,9 @@ func apiCoreHandler(w http.ResponseWriter, r *http.Request) { } type cacheJson struct { - URL string `json:"url"` - Expiration int64 `json:"expiration"` - Size int `json:"size"` + URL string `json:"url"` + Expiration time.Time `json:"expiration"` + Size int `json:"size"` } func apiCacheHandler(w http.ResponseWriter, r *http.Request) { @@ -97,7 +98,7 @@ func apiCacheHandler(w http.ResponseWriter, r *http.Request) { for k, v := range cache.List() { cacheList = append(cacheList, cacheJson{ URL: k, - Expiration: v.Expiration, + Expiration: time.Unix(0, v.Expiration).UTC(), Size: len(v.Content), }) } @@ -106,6 +107,7 @@ func apiCacheHandler(w http.ResponseWriter, r *http.Request) { func apiClearCacheHandler(w http.ResponseWriter, r *http.Request) { CacheStorage = NewStorage() + go CleanRoutine() output := apiResponse{ Status: "success", } diff --git a/handlers/cache.go b/handlers/cache.go index a3783061..3736dec3 100644 --- a/handlers/cache.go +++ b/handlers/cache.go @@ -13,6 +13,8 @@ type Cacher interface { Delete(key string) Set(key string, content []byte, duration time.Duration) List() map[string]Item + Lock() + Unlock() } // Item is a cached reference @@ -21,6 +23,20 @@ type Item struct { Expiration int64 } +// CleanRoutine is a go routine to automatically remove expired caches that haven't been hit recently +func CleanRoutine() { + for CacheStorage != nil { + CacheStorage.Lock() + for k, v := range CacheStorage.List() { + if v.Expired() { + CacheStorage.Delete(k) + } + } + CacheStorage.Unlock() + time.Sleep(5 * time.Second) + } +} + // Expired returns true if the item has expired. func (item Item) Expired() bool { if item.Expiration == 0 { @@ -43,6 +59,14 @@ func NewStorage() *Storage { } } +func (s Storage) Lock() { + s.mu.Lock() +} + +func (s Storage) Unlock() { + s.mu.Unlock() +} + func (s Storage) List() map[string]Item { return s.items } diff --git a/source/wiki.go b/source/wiki.go index aed46b43..15f58b44 100644 --- a/source/wiki.go +++ b/source/wiki.go @@ -1,6 +1,6 @@ // Code generated by go generate; DO NOT EDIT. // This file was generated by robots at -// 2020-02-01 06:04:47.622695 +0000 UTC +// 2020-02-01 06:06:45.83918 +0000 UTC // // This contains the most recently Markdown source for the Statping Wiki. package source