tina4ruby 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +80 -0
- data/LICENSE.txt +21 -0
- data/README.md +768 -0
- data/exe/tina4 +4 -0
- data/lib/tina4/api.rb +152 -0
- data/lib/tina4/auth.rb +139 -0
- data/lib/tina4/cli.rb +349 -0
- data/lib/tina4/crud.rb +124 -0
- data/lib/tina4/database.rb +135 -0
- data/lib/tina4/database_result.rb +89 -0
- data/lib/tina4/debug.rb +83 -0
- data/lib/tina4/dev.rb +15 -0
- data/lib/tina4/dev_reload.rb +68 -0
- data/lib/tina4/drivers/firebird_driver.rb +94 -0
- data/lib/tina4/drivers/mssql_driver.rb +112 -0
- data/lib/tina4/drivers/mysql_driver.rb +90 -0
- data/lib/tina4/drivers/postgres_driver.rb +99 -0
- data/lib/tina4/drivers/sqlite_driver.rb +85 -0
- data/lib/tina4/env.rb +55 -0
- data/lib/tina4/field_types.rb +84 -0
- data/lib/tina4/graphql.rb +837 -0
- data/lib/tina4/localization.rb +100 -0
- data/lib/tina4/middleware.rb +59 -0
- data/lib/tina4/migration.rb +124 -0
- data/lib/tina4/orm.rb +168 -0
- data/lib/tina4/public/css/tina4.css +2286 -0
- data/lib/tina4/public/css/tina4.min.css +2 -0
- data/lib/tina4/public/js/tina4.js +134 -0
- data/lib/tina4/public/js/tina4helper.js +387 -0
- data/lib/tina4/queue.rb +117 -0
- data/lib/tina4/queue_backends/kafka_backend.rb +80 -0
- data/lib/tina4/queue_backends/lite_backend.rb +79 -0
- data/lib/tina4/queue_backends/rabbitmq_backend.rb +73 -0
- data/lib/tina4/rack_app.rb +150 -0
- data/lib/tina4/request.rb +158 -0
- data/lib/tina4/response.rb +172 -0
- data/lib/tina4/router.rb +148 -0
- data/lib/tina4/scss/tina4css/_alerts.scss +34 -0
- data/lib/tina4/scss/tina4css/_badges.scss +22 -0
- data/lib/tina4/scss/tina4css/_buttons.scss +69 -0
- data/lib/tina4/scss/tina4css/_cards.scss +49 -0
- data/lib/tina4/scss/tina4css/_forms.scss +156 -0
- data/lib/tina4/scss/tina4css/_grid.scss +81 -0
- data/lib/tina4/scss/tina4css/_modals.scss +84 -0
- data/lib/tina4/scss/tina4css/_nav.scss +149 -0
- data/lib/tina4/scss/tina4css/_reset.scss +94 -0
- data/lib/tina4/scss/tina4css/_tables.scss +54 -0
- data/lib/tina4/scss/tina4css/_typography.scss +55 -0
- data/lib/tina4/scss/tina4css/_utilities.scss +197 -0
- data/lib/tina4/scss/tina4css/_variables.scss +117 -0
- data/lib/tina4/scss/tina4css/base.scss +1 -0
- data/lib/tina4/scss/tina4css/colors.scss +48 -0
- data/lib/tina4/scss/tina4css/tina4.scss +17 -0
- data/lib/tina4/scss_compiler.rb +131 -0
- data/lib/tina4/seeder.rb +529 -0
- data/lib/tina4/session.rb +145 -0
- data/lib/tina4/session_handlers/file_handler.rb +55 -0
- data/lib/tina4/session_handlers/mongo_handler.rb +49 -0
- data/lib/tina4/session_handlers/redis_handler.rb +43 -0
- data/lib/tina4/swagger.rb +123 -0
- data/lib/tina4/template.rb +478 -0
- data/lib/tina4/templates/base.twig +26 -0
- data/lib/tina4/templates/errors/403.twig +22 -0
- data/lib/tina4/templates/errors/404.twig +22 -0
- data/lib/tina4/templates/errors/500.twig +22 -0
- data/lib/tina4/testing.rb +213 -0
- data/lib/tina4/version.rb +5 -0
- data/lib/tina4/webserver.rb +101 -0
- data/lib/tina4/websocket.rb +167 -0
- data/lib/tina4/wsdl.rb +164 -0
- data/lib/tina4.rb +259 -0
- data/lib/tina4ruby.rb +4 -0
- metadata +324 -0
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/* Tina4 CSS v2.0.0 | MIT | tina4stack/tina4-css */
|
|
2
|
+
*,*::before,*::after{box-sizing:border-box}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;scroll-behavior:smooth}body{margin:0;font-family:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;font-size:1rem;font-weight:400;line-height:1.5;color:#212529;background-color:#fff;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:0.5rem;font-weight:500;line-height:1.25}p{margin-top:0;margin-bottom:1rem}ol,ul{padding-left:2rem;margin-top:0;margin-bottom:1rem}a{color:#4a90d9;text-decoration:none}a:hover{color:#256ab1;text-decoration:underline}img,svg{max-width:100%;height:auto;vertical-align:middle}table{border-collapse:collapse;caption-side:bottom}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}button,[type="button"],[type="reset"],[type="submit"]{-webkit-appearance:button;cursor:pointer}hr{margin:1rem 0;color:inherit;border:0;border-top:1px solid rgba(0,0,0,0.1);opacity:0.25}pre,code,kbd,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}[hidden]{display:none !important}h1{font-size:2.25rem}h2{font-size:1.875rem}h3{font-size:1.5rem}h4{font-size:1.25rem}h5{font-size:1.125rem}h6{font-size:1rem}small,.small{font-size:0.875em}mark,.mark{padding:0.2em;background-color:rgba(255,193,7,0.3)}blockquote{margin:0 0 1rem;padding:0.5rem 1rem;border-left:0.25rem solid rgba(0,0,0,0.1);font-size:1.125rem}code{font-size:0.875em;color:#dc3545;word-wrap:break-word}pre{display:block;padding:1rem;font-size:0.875em;color:#212529;background-color:#f8f9fa;border-radius:.25rem}.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:0.5rem}.container,.container-fluid{width:100%;padding-right:calc($grid-gutter / 2);padding-left:calc($grid-gutter / 2);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}}@media (min-width: 1400px){.container{max-width:1320px}}.row{display:flex;flex-wrap:wrap;margin-right:calc($grid-gutter / -2);margin-left:calc($grid-gutter / -2)}.row>*{flex-shrink:0;width:100%;max-width:100%;padding-right:calc($grid-gutter / 2);padding-left:calc($grid-gutter / 2)}.col{flex:1 0 0%}.col-1{flex:0 0 auto;width:8.33333%}.col-2{flex:0 0 auto;width:16.66667%}.col-3{flex:0 0 auto;width:25%}.col-4{flex:0 0 auto;width:33.33333%}.col-5{flex:0 0 auto;width:41.66667%}.col-6{flex:0 0 auto;width:50%}.col-7{flex:0 0 auto;width:58.33333%}.col-8{flex:0 0 auto;width:66.66667%}.col-9{flex:0 0 auto;width:75%}.col-10{flex:0 0 auto;width:83.33333%}.col-11{flex:0 0 auto;width:91.66667%}.col-12{flex:0 0 auto;width:100%}.offset-1{margin-left:8.33333%}.offset-2{margin-left:16.66667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.33333%}.offset-0{margin-left:0}@media (min-width: 576px){.col-sm{flex:1 0 0%}.col-sm-1{flex:0 0 auto;width:8.33333%}.col-sm-2{flex:0 0 auto;width:16.66667%}.col-sm-3{flex:0 0 auto;width:25%}.col-sm-4{flex:0 0 auto;width:33.33333%}.col-sm-5{flex:0 0 auto;width:41.66667%}.col-sm-6{flex:0 0 auto;width:50%}.col-sm-7{flex:0 0 auto;width:58.33333%}.col-sm-8{flex:0 0 auto;width:66.66667%}.col-sm-9{flex:0 0 auto;width:75%}.col-sm-10{flex:0 0 auto;width:83.33333%}.col-sm-11{flex:0 0 auto;width:91.66667%}.col-sm-12{flex:0 0 auto;width:100%}.offset-sm-0{margin-left:0}}@media (min-width: 768px){.col-md{flex:1 0 0%}.col-md-1{flex:0 0 auto;width:8.33333%}.col-md-2{flex:0 0 auto;width:16.66667%}.col-md-3{flex:0 0 auto;width:25%}.col-md-4{flex:0 0 auto;width:33.33333%}.col-md-5{flex:0 0 auto;width:41.66667%}.col-md-6{flex:0 0 auto;width:50%}.col-md-7{flex:0 0 auto;width:58.33333%}.col-md-8{flex:0 0 auto;width:66.66667%}.col-md-9{flex:0 0 auto;width:75%}.col-md-10{flex:0 0 auto;width:83.33333%}.col-md-11{flex:0 0 auto;width:91.66667%}.col-md-12{flex:0 0 auto;width:100%}.offset-md-0{margin-left:0}}@media (min-width: 992px){.col-lg{flex:1 0 0%}.col-lg-1{flex:0 0 auto;width:8.33333%}.col-lg-2{flex:0 0 auto;width:16.66667%}.col-lg-3{flex:0 0 auto;width:25%}.col-lg-4{flex:0 0 auto;width:33.33333%}.col-lg-5{flex:0 0 auto;width:41.66667%}.col-lg-6{flex:0 0 auto;width:50%}.col-lg-7{flex:0 0 auto;width:58.33333%}.col-lg-8{flex:0 0 auto;width:66.66667%}.col-lg-9{flex:0 0 auto;width:75%}.col-lg-10{flex:0 0 auto;width:83.33333%}.col-lg-11{flex:0 0 auto;width:91.66667%}.col-lg-12{flex:0 0 auto;width:100%}.offset-lg-0{margin-left:0}}@media (min-width: 1200px){.col-xl{flex:1 0 0%}.col-xl-1{flex:0 0 auto;width:8.33333%}.col-xl-2{flex:0 0 auto;width:16.66667%}.col-xl-3{flex:0 0 auto;width:25%}.col-xl-4{flex:0 0 auto;width:33.33333%}.col-xl-5{flex:0 0 auto;width:41.66667%}.col-xl-6{flex:0 0 auto;width:50%}.col-xl-7{flex:0 0 auto;width:58.33333%}.col-xl-8{flex:0 0 auto;width:66.66667%}.col-xl-9{flex:0 0 auto;width:75%}.col-xl-10{flex:0 0 auto;width:83.33333%}.col-xl-11{flex:0 0 auto;width:91.66667%}.col-xl-12{flex:0 0 auto;width:100%}.offset-xl-0{margin-left:0}}.justify-start{justify-content:flex-start}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.justify-between{justify-content:space-between}.justify-around{justify-content:space-around}.align-start{align-items:flex-start}.align-center{align-items:center}.align-end{align-items:flex-end}.btn{display:inline-block;font-weight:400;line-height:1.5;color:#212529;text-align:center;vertical-align:middle;cursor:pointer;user-select:none;background-color:transparent;border:1px solid transparent;padding:0.375rem 0.75rem;font-size:1rem;border-radius:.25rem;transition:color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;text-decoration:none}.btn:disabled,.btn.disabled{pointer-events:none;opacity:0.65}.btn-primary{color:#fff;background-color:#4a90d9;border-color:#4a90d9}.btn-primary:hover{background-color:#2b7bcf;border-color:#2a76c6}.btn-secondary{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:hover{background-color:#596167;border-color:#545b62}.btn-success{color:#fff;background-color:#28a745;border-color:#28a745}.btn-success:hover{background-color:#208637;border-color:#1e7e34}.btn-danger{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:hover{background-color:#c62232;border-color:#bd2130}.btn-warning{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-warning:hover{background-color:#dda600;border-color:#d39e00}.btn-info{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-info:hover{background-color:#128294;border-color:#117a8b}.btn-light{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:hover{background-color:#e0e5e9;border-color:#dae0e5}.btn-dark{color:#fff;background-color:#212529;border-color:#212529}.btn-dark:hover{background-color:#0f1112;border-color:#0a0c0d}.btn-outline-primary{color:#4a90d9;border-color:#4a90d9;background-color:transparent}.btn-outline-primary:hover{color:#fff;background-color:#4a90d9}.btn-outline-secondary{color:#6c757d;border-color:#6c757d;background-color:transparent}.btn-outline-secondary:hover{color:#fff;background-color:#6c757d}.btn-outline-success{color:#28a745;border-color:#28a745;background-color:transparent}.btn-outline-success:hover{color:#fff;background-color:#28a745}.btn-outline-danger{color:#dc3545;border-color:#dc3545;background-color:transparent}.btn-outline-danger:hover{color:#fff;background-color:#dc3545}.btn-outline-warning{color:#ffc107;border-color:#ffc107;background-color:transparent}.btn-outline-warning:hover{color:#212529;background-color:#ffc107}.btn-outline-info{color:#17a2b8;border-color:#17a2b8;background-color:transparent}.btn-outline-info:hover{color:#fff;background-color:#17a2b8}.btn-outline-light{color:#f8f9fa;border-color:#f8f9fa;background-color:transparent}.btn-outline-light:hover{color:#212529;background-color:#f8f9fa}.btn-outline-dark{color:#212529;border-color:#212529;background-color:transparent}.btn-outline-dark:hover{color:#fff;background-color:#212529}.btn-sm{padding:0.25rem 0.5rem;font-size:.875rem;border-radius:.25rem}.btn-lg{padding:0.5rem 1rem;font-size:1.125rem;border-radius:.5rem}.btn-block{display:block;width:100%}.form-group{margin-bottom:1rem}.form-label{display:inline-block;margin-bottom:0.5rem;font-weight:700}.form-control{display:block;width:100%;padding:0.375rem 0.75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#212529;background-color:#fff;background-clip:padding-box;border:1px solid #ced4da;border-radius:.25rem;transition:border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;appearance:none}.form-control:focus{color:#212529;background-color:#fff;border-color:#b3d1ef;outline:0;box-shadow:0 0 0 0.2rem rgba(74,144,217,0.25)}.form-control::placeholder{color:#6c757d;opacity:1}.form-control:disabled{background-color:#f8f9fa;opacity:1}textarea.form-control{min-height:calc(1.5em + 0.75rem + 2px)}.form-select{display:block;width:100%;padding:0.375rem 2.25rem 0.375rem 0.75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#212529;background-color:#fff;border:1px solid #ced4da;border-radius:.25rem;transition:border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;appearance:none}.form-select:focus{border-color:#b3d1ef;outline:0;box-shadow:0 0 0 0.2rem rgba(74,144,217,0.25)}.form-check{display:block;min-height:1.5rem;padding-left:1.5em;margin-bottom:0.125rem}.form-check-input{float:left;width:1em;height:1em;margin-left:-1.5em;margin-top:0.25em;appearance:none;background-color:#fff;border:1px solid rgba(0,0,0,0.25)}.form-check-input[type="checkbox"]{border-radius:0.25em}.form-check-input[type="radio"]{border-radius:50%}.form-check-input:checked{background-color:#4a90d9;border-color:#4a90d9}.form-check-input:focus{border-color:#b3d1ef;outline:0;box-shadow:0 0 0 0.2rem rgba(74,144,217,0.25)}.form-check-label{cursor:pointer}.is-valid{border-color:#28a745 !important}.is-valid:focus{box-shadow:0 0 0 0.2rem rgba(40,167,69,0.25) !important}.is-invalid{border-color:#dc3545 !important}.is-invalid:focus{box-shadow:0 0 0 0.2rem rgba(220,53,69,0.25) !important}.valid-feedback,.invalid-feedback{display:none;width:100%;margin-top:0.25rem;font-size:0.875em}.valid-feedback{color:#28a745}.invalid-feedback{color:#dc3545}.is-valid~.valid-feedback,.is-invalid~.invalid-feedback{display:block}.input-group{position:relative;display:flex;flex-wrap:wrap;align-items:stretch;width:100%}.input-group>.form-control,.input-group>.form-select{position:relative;flex:1 1 auto;width:1%;min-width:0}.input-group-text{display:flex;align-items:center;padding:0.375rem 0.75rem;font-size:1rem;line-height:1.5;color:#212529;text-align:center;white-space:nowrap;background-color:#f8f9fa;border:1px solid #ced4da;border-radius:.25rem}.card{position:relative;display:flex;flex-direction:column;min-width:0;word-wrap:break-word;background-color:#fff;background-clip:border-box;border:1px solid rgba(0,0,0,0.125);border-radius:.5rem}.card-header{padding:0.75rem 1rem;margin-bottom:0;background-color:rgba(0,0,0,0.03);border-bottom:1px solid rgba(0,0,0,0.125)}.card-header:first-child{border-radius:calc($border-radius-lg - 1px) calc($border-radius-lg - 1px) 0 0}.card-body{flex:1 1 auto;padding:1rem}.card-footer{padding:0.75rem 1rem;background-color:rgba(0,0,0,0.03);border-top:1px solid rgba(0,0,0,0.125)}.card-footer:last-child{border-radius:0 0 calc($border-radius-lg - 1px) calc($border-radius-lg - 1px)}.card-title{margin-bottom:0.5rem;font-weight:700}.card-text:last-child{margin-bottom:0}.card-img-top{width:100%;border-top-left-radius:calc($border-radius-lg - 1px);border-top-right-radius:calc($border-radius-lg - 1px)}.nav{display:flex;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:0.5rem 1rem;color:#4a90d9;text-decoration:none;transition:color 0.15s ease-in-out, background-color 0.15s ease-in-out}.nav-link:hover,.nav-link:focus{color:#256ab1}.nav-link.disabled{color:#6c757d;pointer-events:none;cursor:default}.nav-link.active{color:#4a90d9;font-weight:700}.navbar{position:relative;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;padding:0.5rem 1rem}.navbar-brand{padding-top:0.3125rem;padding-bottom:0.3125rem;margin-right:1rem;font-size:1.25rem;font-weight:700;color:inherit;text-decoration:none;white-space:nowrap}.navbar-brand:hover{color:inherit;opacity:0.8}.navbar-nav{display:flex;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0.5rem;padding-left:0.5rem}.navbar-toggler{padding:0.25rem 0.75rem;font-size:1.125rem;line-height:1;background-color:transparent;border:1px solid rgba(0,0,0,0.1);border-radius:.25rem;cursor:pointer}.navbar-toggler:focus{outline:0;box-shadow:0 0 0 0.2rem rgba(74,144,217,0.25)}.navbar-collapse{flex-basis:100%;flex-grow:1;align-items:center;display:none}.navbar-collapse.show{display:flex}@media (min-width: 576px){.navbar-expand-sm .navbar-nav{flex-direction:row}.navbar-expand-sm .navbar-collapse{display:flex;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}}@media (min-width: 768px){.navbar-expand-md .navbar-nav{flex-direction:row}.navbar-expand-md .navbar-collapse{display:flex;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}}@media (min-width: 992px){.navbar-expand-lg .navbar-nav{flex-direction:row}.navbar-expand-lg .navbar-collapse{display:flex;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}}@media (min-width: 1200px){.navbar-expand-xl .navbar-nav{flex-direction:row}.navbar-expand-xl .navbar-collapse{display:flex;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}}@media (min-width: 1400px){.navbar-expand-xxl .navbar-nav{flex-direction:row}.navbar-expand-xxl .navbar-collapse{display:flex;flex-basis:auto}.navbar-expand-xxl .navbar-toggler{display:none}}@media (min-width: 992px){.navbar-nav{flex-direction:row}.navbar-collapse{display:flex;flex-basis:auto}.navbar-toggler{display:none}}.navbar-dark{color:#fff;background-color:#212529}.navbar-dark .navbar-brand{color:#fff}.navbar-dark .nav-link{color:rgba(255,255,255,0.75)}.navbar-dark .nav-link:hover,.navbar-dark .nav-link.active{color:#fff}.navbar-light{background-color:#f8f9fa}.navbar-light .nav-link{color:rgba(0,0,0,0.55)}.navbar-light .nav-link:hover,.navbar-light .nav-link.active{color:rgba(0,0,0,0.9)}.breadcrumb{display:flex;flex-wrap:wrap;padding:0.5rem 1rem;margin-bottom:1rem;list-style:none;background-color:#f8f9fa;border-radius:.25rem}.breadcrumb-item+.breadcrumb-item::before{display:inline-block;padding-right:0.5rem;padding-left:0.5rem;color:#6c757d;content:"/"}.breadcrumb-item.active{color:#6c757d}.modal{position:fixed;top:0;left:0;z-index:1050;display:none;width:100%;height:100%;overflow-x:hidden;overflow-y:auto;outline:0}.modal.show{display:block}.modal-dialog{position:relative;width:auto;margin:1.75rem auto;max-width:500px}.modal-sm{max-width:300px}.modal-lg{max-width:800px}.modal-content{position:relative;display:flex;flex-direction:column;width:100%;pointer-events:auto;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,0.2);border-radius:.5rem;box-shadow:0 0.5rem 1rem rgba(0,0,0,0.15);outline:0}.modal-header{display:flex;flex-shrink:0;align-items:center;justify-content:space-between;padding:1rem;border-bottom:1px solid rgba(0,0,0,0.1)}.modal-title{margin-bottom:0;font-weight:700}.modal-body{position:relative;flex:1 1 auto;padding:1rem}.modal-footer{display:flex;flex-shrink:0;flex-wrap:wrap;align-items:center;justify-content:flex-end;padding:0.75rem;border-top:1px solid rgba(0,0,0,0.1);gap:0.5rem}.modal-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:rgba(0,0,0,0.5);display:none}.modal-backdrop.show{display:block}.alert{position:relative;padding:0.75rem 1rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem}.alert-primary{color:#1c5187;background-color:#deeaf8;border-color:#b3d1ef}.alert-secondary{color:#313539;background-color:#caced1;border-color:#afb5ba}.alert-success{color:#0f401b;background-color:#9be7ac;border-color:#71dd8a}.alert-danger{color:#7c151f;background-color:#f6cdd1;border-color:#efa2a9}.alert-warning{color:#876500;background-color:#ffeeba;border-color:#ffe187}.alert-info{color:#093e47;background-color:#90e4f1;border-color:#63d9ec}.alert-light{color:#aeb9c5;background-color:#fff;border-color:#fff}.alert-dark{color:#000;background-color:#717e8c;border-color:#5a6570}.alert-dismissible{padding-right:3rem}.alert-dismissible .btn-close{position:absolute;top:0;right:0;padding:0.9375rem 1rem;background:transparent;border:0;cursor:pointer;color:inherit;opacity:0.5}.alert-dismissible .btn-close:hover{opacity:0.75}.table{width:100%;margin-bottom:1rem;vertical-align:top;border-color:rgba(0,0,0,0.1)}.table>:not(caption)>*>*{padding:0.5rem;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:inherit}.table>thead{vertical-align:bottom;border-bottom:2px solid currentColor}.table>tbody>tr:last-child>*{border-bottom-color:transparent}.table-sm>:not(caption)>*>*{padding:0.25rem}.table-bordered{border:1px solid rgba(0,0,0,0.1)}.table-bordered>:not(caption)>*>*{border-width:1px;border-style:solid;border-color:inherit}.table-striped>tbody>tr:nth-of-type(odd)>*{background-color:rgba(0,0,0,0.02)}.table-hover>tbody>tr:hover>*{background-color:rgba(0,0,0,0.04)}.table-responsive{overflow-x:auto;-webkit-overflow-scrolling:touch}.badge{display:inline-block;padding:0.25em 0.65em;font-size:0.75em;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:50rem}.badge-primary{color:#fff;background-color:#4a90d9}.badge-secondary{color:#fff;background-color:#6c757d}.badge-success{color:#fff;background-color:#28a745}.badge-danger{color:#fff;background-color:#dc3545}.badge-warning{color:#212529;background-color:#ffc107}.badge-info{color:#fff;background-color:#17a2b8}.badge-light{color:#212529;background-color:#f8f9fa}.badge-dark{color:#fff;background-color:#212529}.d-none{display:none !important}.d-block{display:block !important}.d-flex{display:flex !important}.d-inline{display:inline !important}.d-inline-block{display:inline-block !important}.d-grid{display:grid !important}@media (min-width: 576px){.d-sm-none{display:none !important}.d-sm-block{display:block !important}.d-sm-flex{display:flex !important}.d-sm-inline{display:inline !important}.d-sm-inline-block{display:inline-block !important}}@media (min-width: 768px){.d-md-none{display:none !important}.d-md-block{display:block !important}.d-md-flex{display:flex !important}.d-md-inline{display:inline !important}.d-md-inline-block{display:inline-block !important}}@media (min-width: 992px){.d-lg-none{display:none !important}.d-lg-block{display:block !important}.d-lg-flex{display:flex !important}.d-lg-inline{display:inline !important}.d-lg-inline-block{display:inline-block !important}}.flex-row{flex-direction:row !important}.flex-column{flex-direction:column !important}.flex-wrap{flex-wrap:wrap !important}.flex-nowrap{flex-wrap:nowrap !important}.flex-grow-0{flex-grow:0 !important}.flex-grow-1{flex-grow:1 !important}.justify-content-start{justify-content:flex-start !important}.justify-content-end{justify-content:flex-end !important}.justify-content-center{justify-content:center !important}.justify-content-between{justify-content:space-between !important}.justify-content-around{justify-content:space-around !important}.align-items-start{align-items:flex-start !important}.align-items-end{align-items:flex-end !important}.align-items-center{align-items:center !important}.gap-0{gap:0 !important}.gap-1{gap:.25rem !important}.gap-2{gap:.5rem !important}.gap-3{gap:1rem !important}.gap-4{gap:1.5rem !important}.gap-5{gap:3rem !important}.m-0{margin:0 !important}.m-1{margin:.25rem !important}.m-2{margin:.5rem !important}.m-3{margin:1rem !important}.m-4{margin:1.5rem !important}.m-5{margin:3rem !important}.mt-0{margin-top:0 !important}.mt-1{margin-top:.25rem !important}.mt-2{margin-top:.5rem !important}.mt-3{margin-top:1rem !important}.mt-4{margin-top:1.5rem !important}.mt-5{margin-top:3rem !important}.mb-0{margin-bottom:0 !important}.mb-1{margin-bottom:.25rem !important}.mb-2{margin-bottom:.5rem !important}.mb-3{margin-bottom:1rem !important}.mb-4{margin-bottom:1.5rem !important}.mb-5{margin-bottom:3rem !important}.ms-0{margin-left:0 !important}.ms-1{margin-left:.25rem !important}.ms-2{margin-left:.5rem !important}.ms-3{margin-left:1rem !important}.ms-4{margin-left:1.5rem !important}.ms-5{margin-left:3rem !important}.me-0{margin-right:0 !important}.me-1{margin-right:.25rem !important}.me-2{margin-right:.5rem !important}.me-3{margin-right:1rem !important}.me-4{margin-right:1.5rem !important}.me-5{margin-right:3rem !important}.p-0{padding:0 !important}.p-1{padding:.25rem !important}.p-2{padding:.5rem !important}.p-3{padding:1rem !important}.p-4{padding:1.5rem !important}.p-5{padding:3rem !important}.pt-0{padding-top:0 !important}.pt-1{padding-top:.25rem !important}.pt-2{padding-top:.5rem !important}.pt-3{padding-top:1rem !important}.pt-4{padding-top:1.5rem !important}.pt-5{padding-top:3rem !important}.pb-0{padding-bottom:0 !important}.pb-1{padding-bottom:.25rem !important}.pb-2{padding-bottom:.5rem !important}.pb-3{padding-bottom:1rem !important}.pb-4{padding-bottom:1.5rem !important}.pb-5{padding-bottom:3rem !important}.ps-0{padding-left:0 !important}.ps-1{padding-left:.25rem !important}.ps-2{padding-left:.5rem !important}.ps-3{padding-left:1rem !important}.ps-4{padding-left:1.5rem !important}.ps-5{padding-left:3rem !important}.pe-0{padding-right:0 !important}.pe-1{padding-right:.25rem !important}.pe-2{padding-right:.5rem !important}.pe-3{padding-right:1rem !important}.pe-4{padding-right:1.5rem !important}.pe-5{padding-right:3rem !important}.mx-auto{margin-left:auto !important;margin-right:auto !important}.text-start{text-align:left !important}.text-center{text-align:center !important}.text-end{text-align:right !important}.text-uppercase{text-transform:uppercase !important}.text-capitalize{text-transform:capitalize !important}.text-nowrap{white-space:nowrap !important}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fw-bold{font-weight:700 !important}.fw-normal{font-weight:400 !important}.fw-light{font-weight:300 !important}.fs-1{font-size:2.25rem !important}.fs-2{font-size:1.875rem !important}.fs-3{font-size:1.5rem !important}.fs-4{font-size:1.25rem !important}.fs-5{font-size:1rem !important}.fs-6{font-size:.875rem !important}.text-primary{color:#4a90d9 !important}.text-secondary{color:#6c757d !important}.text-success{color:#28a745 !important}.text-danger{color:#dc3545 !important}.text-warning{color:#ffc107 !important}.text-info{color:#17a2b8 !important}.text-light{color:#f8f9fa !important}.text-dark{color:#212529 !important}.text-muted{color:#6c757d !important}.text-white{color:#fff !important}.bg-primary{background-color:#4a90d9 !important}.bg-secondary{background-color:#6c757d !important}.bg-success{background-color:#28a745 !important}.bg-danger{background-color:#dc3545 !important}.bg-warning{background-color:#ffc107 !important}.bg-info{background-color:#17a2b8 !important}.bg-light{background-color:#f8f9fa !important}.bg-dark{background-color:#212529 !important}.bg-white{background-color:#fff !important}.border{border:1px solid rgba(0,0,0,0.1) !important}.border-0{border:0 !important}.rounded{border-radius:.25rem !important}.rounded-0{border-radius:0 !important}.rounded-circle{border-radius:50% !important}.rounded-pill{border-radius:50rem !important}.w-25{width:25% !important}.h-25{height:25% !important}.w-50{width:50% !important}.h-50{height:50% !important}.w-75{width:75% !important}.h-75{height:75% !important}.w-100{width:100% !important}.h-100{height:100% !important}.mw-100{max-width:100% !important}.mh-100{max-height:100% !important}.position-relative{position:relative !important}.position-absolute{position:absolute !important}.position-fixed{position:fixed !important}.position-sticky{position:sticky !important}.position-static{position:static !important}.visible{visibility:visible !important}.invisible{visibility:hidden !important}.overflow-hidden{overflow:hidden !important}.overflow-auto{overflow:auto !important}.shadow{box-shadow:0 0.5rem 1rem rgba(0,0,0,0.15) !important}.shadow-sm{box-shadow:0 0.125rem 0.25rem rgba(0,0,0,0.075) !important}.shadow-lg{box-shadow:0 1rem 3rem rgba(0,0,0,0.175) !important}.shadow-none{box-shadow:none !important}.collapse{display:none}.collapse.show{display:block}.fade{opacity:0;transition:opacity 0.15s linear}.fade.show{opacity:1}.clearfix::after{display:block;clear:both;content:""}.cursor-pointer{cursor:pointer !important}.btn-close{box-sizing:content-box;width:1em;height:1em;padding:0.25em;color:#000;background:transparent;border:0;opacity:0.5;cursor:pointer;font-size:1.25rem;line-height:1}.btn-close:hover{opacity:0.75}.btn-close:focus{opacity:1;outline:0;box-shadow:0 0 0 0.2rem rgba(74,144,217,0.25)}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:0.25rem;background-color:#fff;border:1px solid rgba(0,0,0,0.1);border-radius:.25rem;max-width:100%;height:auto}.border-top{border-top:1px solid rgba(0,0,0,0.1) !important}.border-bottom{border-bottom:1px solid rgba(0,0,0,0.1) !important}.align-middle{vertical-align:middle !important}.align-top{vertical-align:top !important}.align-bottom{vertical-align:bottom !important}.float-start{float:left !important}.float-end{float:right !important}.float-none{float:none !important}.visually-hidden{position:absolute !important;width:1px !important;height:1px !important;padding:0 !important;margin:-1px !important;overflow:hidden !important;clip:rect(0, 0, 0, 0) !important;white-space:nowrap !important;border:0 !important}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tina4 CSS — Lightweight JS components
|
|
3
|
+
* Replaces Bootstrap's JavaScript for: modals, alerts, navbar toggler
|
|
4
|
+
* ~3KB unminified, zero dependencies
|
|
5
|
+
*/
|
|
6
|
+
(function () {
|
|
7
|
+
"use strict";
|
|
8
|
+
|
|
9
|
+
// ── Modals ──────────────────────────────────────────────────
|
|
10
|
+
// Usage: <button data-t4-toggle="modal" data-t4-target="#myModal">Open</button>
|
|
11
|
+
// <button data-t4-dismiss="modal">Close</button>
|
|
12
|
+
// Also supports Bootstrap syntax: data-bs-toggle, data-bs-target, data-bs-dismiss
|
|
13
|
+
|
|
14
|
+
function getModalEl(selector) {
|
|
15
|
+
if (!selector) return null;
|
|
16
|
+
return document.querySelector(selector);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function openModal(modal) {
|
|
20
|
+
if (!modal) return;
|
|
21
|
+
// Create backdrop if not exists
|
|
22
|
+
var backdrop = modal._t4Backdrop;
|
|
23
|
+
if (!backdrop) {
|
|
24
|
+
backdrop = document.createElement("div");
|
|
25
|
+
backdrop.className = "modal-backdrop";
|
|
26
|
+
document.body.appendChild(backdrop);
|
|
27
|
+
modal._t4Backdrop = backdrop;
|
|
28
|
+
backdrop.addEventListener("click", function () {
|
|
29
|
+
closeModal(modal);
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
modal.style.display = "block";
|
|
33
|
+
backdrop.style.display = "block";
|
|
34
|
+
// Force reflow then add .show for transition
|
|
35
|
+
void modal.offsetHeight;
|
|
36
|
+
modal.classList.add("show");
|
|
37
|
+
backdrop.classList.add("show");
|
|
38
|
+
document.body.style.overflow = "hidden";
|
|
39
|
+
// Focus trap — focus first focusable element
|
|
40
|
+
var focusable = modal.querySelector("input, select, textarea, button, [tabindex]");
|
|
41
|
+
if (focusable) focusable.focus();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function closeModal(modal) {
|
|
45
|
+
if (!modal) return;
|
|
46
|
+
modal.classList.remove("show");
|
|
47
|
+
var backdrop = modal._t4Backdrop;
|
|
48
|
+
if (backdrop) backdrop.classList.remove("show");
|
|
49
|
+
// Wait for transition
|
|
50
|
+
setTimeout(function () {
|
|
51
|
+
modal.style.display = "none";
|
|
52
|
+
if (backdrop) backdrop.style.display = "none";
|
|
53
|
+
document.body.style.overflow = "";
|
|
54
|
+
}, 150);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Delegated click handler for modal triggers
|
|
58
|
+
document.addEventListener("click", function (e) {
|
|
59
|
+
var trigger = e.target.closest("[data-t4-toggle='modal'], [data-bs-toggle='modal']");
|
|
60
|
+
if (trigger) {
|
|
61
|
+
e.preventDefault();
|
|
62
|
+
var target = trigger.getAttribute("data-t4-target") || trigger.getAttribute("data-bs-target") || trigger.getAttribute("href");
|
|
63
|
+
var modal = getModalEl(target);
|
|
64
|
+
if (modal) openModal(modal);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Dismiss button
|
|
69
|
+
var dismiss = e.target.closest("[data-t4-dismiss='modal'], [data-bs-dismiss='modal'], .btn-close");
|
|
70
|
+
if (dismiss) {
|
|
71
|
+
var modal = dismiss.closest(".modal");
|
|
72
|
+
if (modal) closeModal(modal);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// ESC key closes top modal
|
|
78
|
+
document.addEventListener("keydown", function (e) {
|
|
79
|
+
if (e.key === "Escape") {
|
|
80
|
+
var modals = document.querySelectorAll(".modal.show");
|
|
81
|
+
if (modals.length > 0) closeModal(modals[modals.length - 1]);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// ── Alerts (dismissible) ────────────────────────────────────
|
|
86
|
+
// Usage: <div class="alert alert-danger alert-dismissible">
|
|
87
|
+
// Message <button class="btn-close" data-t4-dismiss="alert">×</button>
|
|
88
|
+
// </div>
|
|
89
|
+
|
|
90
|
+
document.addEventListener("click", function (e) {
|
|
91
|
+
var dismiss = e.target.closest("[data-t4-dismiss='alert'], [data-bs-dismiss='alert']");
|
|
92
|
+
if (dismiss) {
|
|
93
|
+
var alert = dismiss.closest(".alert");
|
|
94
|
+
if (alert) {
|
|
95
|
+
alert.style.opacity = "0";
|
|
96
|
+
setTimeout(function () { alert.remove(); }, 150);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// ── Navbar toggler ──────────────────────────────────────────
|
|
102
|
+
// Usage: <button class="navbar-toggler" data-t4-toggle="collapse" data-t4-target="#navContent">
|
|
103
|
+
// ☰
|
|
104
|
+
// </button>
|
|
105
|
+
// <div class="navbar-collapse collapse" id="navContent">...</div>
|
|
106
|
+
|
|
107
|
+
document.addEventListener("click", function (e) {
|
|
108
|
+
var toggler = e.target.closest("[data-t4-toggle='collapse'], [data-bs-toggle='collapse']");
|
|
109
|
+
if (toggler) {
|
|
110
|
+
e.preventDefault();
|
|
111
|
+
var target = toggler.getAttribute("data-t4-target") || toggler.getAttribute("data-bs-target") || toggler.getAttribute("href");
|
|
112
|
+
var el = document.querySelector(target);
|
|
113
|
+
if (el) {
|
|
114
|
+
el.classList.toggle("show");
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
// ── Programmatic API ────────────────────────────────────────
|
|
120
|
+
// window.tina4.modal.open("#myModal")
|
|
121
|
+
// window.tina4.modal.close("#myModal")
|
|
122
|
+
|
|
123
|
+
window.tina4 = window.tina4 || {};
|
|
124
|
+
window.tina4.modal = {
|
|
125
|
+
open: function (selector) {
|
|
126
|
+
var modal = typeof selector === "string" ? document.querySelector(selector) : selector;
|
|
127
|
+
openModal(modal);
|
|
128
|
+
},
|
|
129
|
+
close: function (selector) {
|
|
130
|
+
var modal = typeof selector === "string" ? document.querySelector(selector) : selector;
|
|
131
|
+
closeModal(modal);
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
})();
|
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
var formToken = null;
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Sends an http request
|
|
5
|
+
* @param url
|
|
6
|
+
* @param request
|
|
7
|
+
* @param method
|
|
8
|
+
* @param callback
|
|
9
|
+
*/
|
|
10
|
+
function sendRequest(url, request, method, callback) {
|
|
11
|
+
// Default values
|
|
12
|
+
if (url === undefined) url = "";
|
|
13
|
+
if (request === undefined) request = null;
|
|
14
|
+
if (method === undefined) method = 'GET';
|
|
15
|
+
|
|
16
|
+
const xhr = new XMLHttpRequest();
|
|
17
|
+
xhr.open(method, url, true);
|
|
18
|
+
|
|
19
|
+
// Add authorization header if token exists
|
|
20
|
+
if (formToken !== null) {
|
|
21
|
+
xhr.setRequestHeader('Authorization', 'Bearer ' + formToken);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// ────────────────────────────────────────────────
|
|
25
|
+
// Content-Type logic – only set when appropriate
|
|
26
|
+
// ────────────────────────────────────────────────
|
|
27
|
+
let isFormData = request instanceof FormData;
|
|
28
|
+
|
|
29
|
+
if (method.toUpperCase() === 'POST' || method.toUpperCase() === 'PUT' || method.toUpperCase() === 'PATCH') {
|
|
30
|
+
if (isFormData) {
|
|
31
|
+
//DO not touch this
|
|
32
|
+
} else if (typeof request === 'object' && request !== null) {
|
|
33
|
+
//Becomes a JSON String
|
|
34
|
+
request = JSON.stringify(request);
|
|
35
|
+
xhr.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
|
|
36
|
+
} else if (typeof request === 'string') {
|
|
37
|
+
// Already a string – assume JSON or let server decide
|
|
38
|
+
// You can set charset=UTF-8 if you're sure it's JSON/text
|
|
39
|
+
xhr.setRequestHeader('Content-Type', 'text/plain; charset=UTF-8');
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// ────────────────────────────────────────────────
|
|
44
|
+
// Response handling
|
|
45
|
+
// ────────────────────────────────────────────────
|
|
46
|
+
xhr.onload = function () {
|
|
47
|
+
let content = xhr.response;
|
|
48
|
+
|
|
49
|
+
// Update token if server sent a fresh one
|
|
50
|
+
const freshToken = xhr.getResponseHeader('FreshToken');
|
|
51
|
+
if (freshToken && freshToken !== '') {
|
|
52
|
+
formToken = freshToken;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
content = JSON.parse(content);
|
|
57
|
+
} catch (e) {
|
|
58
|
+
// Not JSON → keep as raw string/text
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (typeof callback === 'function') {
|
|
62
|
+
callback(content, xhr.status, xhr);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
// Optional: handle errors
|
|
67
|
+
xhr.onerror = function () {
|
|
68
|
+
if (typeof callback === 'function') {
|
|
69
|
+
callback(null, xhr.status, xhr);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
// Send the body (or null)
|
|
74
|
+
xhr.send(request);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Gets form data based on a form Id
|
|
79
|
+
* @param formId
|
|
80
|
+
* @returns {FormData}
|
|
81
|
+
*/
|
|
82
|
+
function getFormData(formId) {
|
|
83
|
+
let data = new FormData();
|
|
84
|
+
let elements = document.querySelectorAll("#" + formId + " select, #" + formId + " input, #" + formId + " textarea");
|
|
85
|
+
for (let ie = 0; ie < elements.length; ie++ )
|
|
86
|
+
{
|
|
87
|
+
let element = elements[ie];
|
|
88
|
+
//refresh the token
|
|
89
|
+
if (element.name === 'formToken' && formToken !== null) {
|
|
90
|
+
element.value = formToken;
|
|
91
|
+
}
|
|
92
|
+
if (element.name) {
|
|
93
|
+
if (element.type === 'file') {
|
|
94
|
+
for (let i = 0; i < element.files.length; i++) {
|
|
95
|
+
let fileData = element.files[i];
|
|
96
|
+
let elementName = element.name;
|
|
97
|
+
if (fileData !== undefined) {
|
|
98
|
+
if (element.files.length > 1 && !elementName.includes('[')) {
|
|
99
|
+
elementName = elementName + '[]';
|
|
100
|
+
}
|
|
101
|
+
data.append(elementName, fileData, fileData.name);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
} else if (element.type === 'checkbox' || element.type === 'radio') {
|
|
105
|
+
if (element.checked) {
|
|
106
|
+
data.append(element.name, element.value)
|
|
107
|
+
} else {
|
|
108
|
+
if (element.type !== 'radio') {
|
|
109
|
+
data.append(element.name, "0")
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
} else {
|
|
113
|
+
if (element.value === '') {
|
|
114
|
+
element.value = null;
|
|
115
|
+
}
|
|
116
|
+
data.append(element.name, element.value);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return data;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Handles the data returned from a request
|
|
125
|
+
* @param data
|
|
126
|
+
* @param targetElement
|
|
127
|
+
*/
|
|
128
|
+
function handleHtmlData(data, targetElement) {
|
|
129
|
+
//Strip out the scripts
|
|
130
|
+
if (data === "") return '';
|
|
131
|
+
const parser = new DOMParser();
|
|
132
|
+
const htmlData = parser.parseFromString(data.includes !== undefined && data.includes('<html>') ? data : '<body>'+data+'</body></html>', 'text/html');
|
|
133
|
+
const body = htmlData.querySelector('body');
|
|
134
|
+
const scripts = body.querySelectorAll('script');
|
|
135
|
+
// remove the script tags
|
|
136
|
+
body.querySelectorAll('script').forEach(script => script.remove());
|
|
137
|
+
|
|
138
|
+
if (targetElement !== null) {
|
|
139
|
+
if (body.children.length > 0) {
|
|
140
|
+
document.getElementById(targetElement).replaceChildren(...body.children);
|
|
141
|
+
} else {
|
|
142
|
+
document.getElementById(targetElement).replaceChildren(body.innerHTML);
|
|
143
|
+
}
|
|
144
|
+
if (scripts) {
|
|
145
|
+
scripts.forEach(script => {
|
|
146
|
+
const newScript = document.createElement("script");
|
|
147
|
+
newScript.type = 'text/javascript';
|
|
148
|
+
newScript.async = true;
|
|
149
|
+
newScript.textContent = script.innerText;
|
|
150
|
+
document.getElementById(targetElement).append(newScript);
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
} else {
|
|
154
|
+
if (scripts) {
|
|
155
|
+
scripts.forEach(script => {
|
|
156
|
+
const newScript = document.createElement("script");
|
|
157
|
+
newScript.type = 'text/javascript';
|
|
158
|
+
newScript.async = true;
|
|
159
|
+
newScript.textContent = script.innerText;
|
|
160
|
+
document.body.append(newScript);
|
|
161
|
+
console.log(newScript);
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return body.innerHTML;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return '';
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Loads a page to a target html element
|
|
173
|
+
* @param loadURL
|
|
174
|
+
* @param targetElement
|
|
175
|
+
* @param callback
|
|
176
|
+
* @callback
|
|
177
|
+
*/
|
|
178
|
+
function loadPage(loadURL, targetElement, callback = null) {
|
|
179
|
+
if (targetElement === undefined) targetElement = 'content';
|
|
180
|
+
sendRequest(loadURL, null, "GET", function(data) {
|
|
181
|
+
let processedHTML = '';
|
|
182
|
+
if (document.getElementById(targetElement) !== null) {
|
|
183
|
+
processedHTML = handleHtmlData(data, targetElement);
|
|
184
|
+
} else {
|
|
185
|
+
if (callback) {
|
|
186
|
+
callback(data);
|
|
187
|
+
} else {
|
|
188
|
+
console.log('TINA4 - define targetElement or callback for loadPage', data);
|
|
189
|
+
}
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (callback) {
|
|
194
|
+
callback(processedHTML, data);
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Shows a form from a URL in a target html element
|
|
201
|
+
* @param action
|
|
202
|
+
* @param loadURL
|
|
203
|
+
* @param targetElement
|
|
204
|
+
* @param callback
|
|
205
|
+
*/
|
|
206
|
+
function showForm(action, loadURL, targetElement, callback = null) {
|
|
207
|
+
if (targetElement === undefined) targetElement = 'form';
|
|
208
|
+
|
|
209
|
+
if (action === 'create') action = 'GET';
|
|
210
|
+
if (action === 'edit') action = 'GET';
|
|
211
|
+
if (action === 'delete') action = 'DELETE';
|
|
212
|
+
|
|
213
|
+
sendRequest(loadURL, null, action, function(data) {
|
|
214
|
+
let processedHTML = '';
|
|
215
|
+
if (data.message !== undefined) {
|
|
216
|
+
processedHTML = handleHtmlData ((data.message), targetElement);
|
|
217
|
+
} else {
|
|
218
|
+
if (document.getElementById(targetElement) !== null) {
|
|
219
|
+
processedHTML = handleHtmlData (data, targetElement);
|
|
220
|
+
} else {
|
|
221
|
+
if (callback) {
|
|
222
|
+
callback(data);
|
|
223
|
+
} else {
|
|
224
|
+
console.log('TINA4 - define targetElement or callback for showForm', data);
|
|
225
|
+
}
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (callback) {
|
|
231
|
+
callback(processedHTML);
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Post URL posts data to a specific url
|
|
238
|
+
* @param url
|
|
239
|
+
* @param data
|
|
240
|
+
* @param targetElement
|
|
241
|
+
* @param callback
|
|
242
|
+
*/
|
|
243
|
+
function postUrl(url, data, targetElement, callback= null) {
|
|
244
|
+
sendRequest(url, data, 'POST', function(data) {
|
|
245
|
+
let processedHTML = '';
|
|
246
|
+
if (data.message !== undefined) {
|
|
247
|
+
processedHTML = handleHtmlData ((data.message), targetElement);
|
|
248
|
+
} else {
|
|
249
|
+
if (document.getElementById(targetElement) !== null) {
|
|
250
|
+
processedHTML = handleHtmlData (data, targetElement);
|
|
251
|
+
} else {
|
|
252
|
+
if (callback) {
|
|
253
|
+
callback(data);
|
|
254
|
+
} else {
|
|
255
|
+
console.log('TINA4 - define targetElement or callback for postUrl', data);
|
|
256
|
+
}
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (callback) {
|
|
262
|
+
callback(processedHTML,data)
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Saves a form to a POST end point
|
|
269
|
+
* @param formId
|
|
270
|
+
* @param targetURL
|
|
271
|
+
* @param targetElement
|
|
272
|
+
* @param callback - optional
|
|
273
|
+
*/
|
|
274
|
+
function saveForm(formId, targetURL, targetElement, callback = null) {
|
|
275
|
+
if (targetElement === undefined) targetElement = 'message';
|
|
276
|
+
//compile a data model
|
|
277
|
+
let data = getFormData(formId);
|
|
278
|
+
|
|
279
|
+
postUrl(targetURL, data, targetElement, callback);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Alias of saveForm
|
|
284
|
+
* @param formId
|
|
285
|
+
* @param targetURL
|
|
286
|
+
* @param targetElement
|
|
287
|
+
* @param callback
|
|
288
|
+
*/
|
|
289
|
+
function postForm(formId, targetURL, targetElement, callback = null){
|
|
290
|
+
saveForm(formId, targetURL, targetElement, callback)
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Alias of saveForm
|
|
295
|
+
* @param formId
|
|
296
|
+
* @param targetURL
|
|
297
|
+
* @param targetElement
|
|
298
|
+
* @param callback
|
|
299
|
+
*/
|
|
300
|
+
function submitForm(formId, targetURL, targetElement, callback = null){
|
|
301
|
+
saveForm(formId, targetURL, targetElement, callback)
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Shows a message
|
|
306
|
+
* @param message
|
|
307
|
+
*/
|
|
308
|
+
function showMessage(message) {
|
|
309
|
+
document.getElementById('message').innerHTML = '<div class="alert alert-info alert-dismissible fade show"><strong>Info</strong> ' + message + '<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button></div>';
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Set cookie
|
|
314
|
+
* @param name
|
|
315
|
+
* @param value
|
|
316
|
+
* @param days
|
|
317
|
+
*/
|
|
318
|
+
function setCookie(name, value, days) {
|
|
319
|
+
let expires = "";
|
|
320
|
+
if (days) {
|
|
321
|
+
let date = new Date();
|
|
322
|
+
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
|
|
323
|
+
expires = "; expires=" + date.toUTCString();
|
|
324
|
+
}
|
|
325
|
+
document.cookie = name + "=" + (value || "") + expires + "; path=/";
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Get cookie
|
|
330
|
+
* @param name
|
|
331
|
+
* @returns {null|string}
|
|
332
|
+
*/
|
|
333
|
+
function getCookie(name) {
|
|
334
|
+
let nameEQ = name + "=";
|
|
335
|
+
let ca = document.cookie.split(';');
|
|
336
|
+
for (let i = 0; i < ca.length; i++) {
|
|
337
|
+
var c = ca[i];
|
|
338
|
+
while (c.charAt(0) == ' ') c = c.substring(1, c.length);
|
|
339
|
+
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
|
|
340
|
+
}
|
|
341
|
+
return null;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
//https://stackoverflow.com/questions/4068373/center-a-popup-window-on-screen
|
|
345
|
+
const popupCenter = ({url, title, w, h}) => {
|
|
346
|
+
// Fixes dual-screen position Most browsers Firefox
|
|
347
|
+
const dualScreenLeft = window.screenLeft !== undefined ? window.screenLeft : window.screenX;
|
|
348
|
+
const dualScreenTop = window.screenTop !== undefined ? window.screenTop : window.screenY;
|
|
349
|
+
|
|
350
|
+
const width = window.innerWidth ? window.innerWidth : document.documentElement.clientWidth ? document.documentElement.clientWidth : screen.width;
|
|
351
|
+
const height = window.innerHeight ? window.innerHeight : document.documentElement.clientHeight ? document.documentElement.clientHeight : screen.height;
|
|
352
|
+
|
|
353
|
+
const systemZoom = width / window.screen.availWidth;
|
|
354
|
+
const left = (width - w) / 2 / systemZoom + dualScreenLeft
|
|
355
|
+
const top = (height - h) / 2 / systemZoom + dualScreenTop
|
|
356
|
+
const newWindow = window.open(url, title,
|
|
357
|
+
`
|
|
358
|
+
directories=no,toolbar=no,location=no,status=no,menubar=no,scrollbars=no,resizable=no,
|
|
359
|
+
width=${w / systemZoom},
|
|
360
|
+
height=${h / systemZoom},
|
|
361
|
+
top=${top},
|
|
362
|
+
left=${left}
|
|
363
|
+
`
|
|
364
|
+
)
|
|
365
|
+
|
|
366
|
+
if (window.focus) newWindow.focus();
|
|
367
|
+
return newWindow;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Opens a popup window
|
|
372
|
+
* @param pdfReportPath
|
|
373
|
+
*/
|
|
374
|
+
function openReport(pdfReportPath){
|
|
375
|
+
if (pdfReportPath.indexOf("No data available") < 0){
|
|
376
|
+
open(pdfReportPath, "content", "target=_blank, toolbar=no, scrollbars=yes, resizable=yes, width=800, height=600, top=0, left=0");
|
|
377
|
+
}
|
|
378
|
+
else {
|
|
379
|
+
window.alert("Sorry , unable to print a report according to your selection!");
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
function getRoute(loadURL, callback) {
|
|
384
|
+
sendRequest(loadURL, null, 'GET', function(data) {
|
|
385
|
+
callback(handleHtmlData (data, null));
|
|
386
|
+
});
|
|
387
|
+
}
|