diff --git a/CHANGELOG.md b/CHANGELOG.md index 37bea20164ffdaad59fa7e4714b15ab665835f14..bf6d063e86c058218268207ff5afec270c9d2e85 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## 2024-03-06 +## Add Features +- Neues CustomControl Switch [#159](https://gitlab.schukai.com/oss/libraries/javascript/monster/-/issues/159) + +## 2024-03-05 +## Bugfixes +- Updater Methode getControlEventHandler the Function `retrieveAndSetValue` is called with settimeout [#158](https://gitlab.schukai.com/oss/libraries/javascript/monster/-/issues/158) +- Updater Methode addObjectWithUpdaterToElement the Function `updaterTransformerMethodsSymbol` is called with `call` so that the `this` pointer is available ## [3.57.0] - 2024-03-02 diff --git a/example/components/form/toggle-switch.mjs b/example/components/form/toggle-switch.mjs new file mode 100644 index 0000000000000000000000000000000000000000..7b23a82e8bb9e193fe455c047d9bb0759054b0e6 --- /dev/null +++ b/example/components/form/toggle-switch.mjs @@ -0,0 +1,7 @@ +import {Switch} from '@schukai/component-form/source/toggle-switch.js'; + +// create element +const toggleSwitch = document.createElement('monster-toggle-switch'); + +// insert element into the DOM +document.body.appendChild(toggleSwitch); \ No newline at end of file diff --git a/playground/bind-with-datasource/index.html b/playground/bind-with-datasource/index.html index 1c289f47eab28f9408294d272f7e04c8a902e734..04d7362c4527136c4a4eaf8a5544ca448a9e4603 100644 --- a/playground/bind-with-datasource/index.html +++ b/playground/bind-with-datasource/index.html @@ -10,120 +10,118 @@ </head> <body> -<main> - <div> - <!-- + <main> + <div> + <!-- Datasource mit fest definieren Daten --> - <monster-datasource-rest id="data1" - data-monster-option-write-url="/demo/bind-with-datasource/data.json" - data-monster-option-read-url="/demo/bind-with-datasource/data.json"></monster-datasource-rest> + <monster-datasource-rest id="data1" data-monster-option-write-url="/demo/bind-with-datasource/data.json" data-monster-option-read-url="/demo/bind-with-datasource/data.json"></monster-datasource-rest> - <h1>Bestellungen</h1> + <h1>Bestellungen</h1> - <!-- + <!-- Datatable stellt diese Daten dar mit "data-monster-datasource-selector" wird die Datenquelle "#data1" definiert --> - <monster-datatable id="test-datatable" data-monster-datasource-selector="#data1"> - - <monster-datasource-save-button slot="bar" data-monster-option-datasource-selector="#data1"> - </monster-datasource-save-button> - <monster-datasource-status slot="bar" data-monster-option-datasource-selector="#data1"> - </monster-datasource-status> - - <template id="test-datatable-row"> - - <div data-monster-head="erpName" data-monster-replace="path:test-datatable-row.erpName "></div> - <div data-monster-head="OID" data-monster-mode="fixed" data-monster-sortable="oid" - data-monster-replace="path:test-datatable-row.oid | tostring"></div> - <div data-monster-head="orderLastStatusChange" - data-monster-replace="path:test-datatable-row.orderLastStatusChange"></div> - <div data-monster-head="customerUID" data-monster-replace="path:test-datatable-row.customerUID"></div> - <div data-monster-head="resubmissionDate" - data-monster-replace="path:test-datatable-row.resubmissionDate"></div> - <div data-monster-head="billingAddressAID" - data-monster-replace="path:test-datatable-row.billingAddressAID"></div> - <div data-monster-head="deliveryAddressAID" - data-monster-replace="path:test-datatable-row.deliveryAddressAID"></div> - - <div data-monster-head=" " data-alvine-role="actionHolder" class="actionButtons"> - - <monster-datatable-change-button - style="height:100%;display:flex;margin-right:0.1rem;" - data-monster-option-dataset-selector="#dataset1" - data-monster-option-overlay-selector="#overlay1"> - - </monster-datatable-change-button> - <monster-datatable-change-button - style="height:100%;;display:flex;" - data-monster-option-labels-button="o2" - data-monster-option-dataset-selector="#dataset1" - data-monster-option-overlay-selector="#overlay2"> - - </monster-datatable-change-button> - - - <!--monster-button - data-alvine-role="changeButton" - data-monster-option-actions-click="" - data-monster-attributes="data-alvine-oid path:test-datatable-row.index"> - <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" - class="bi bi-grid" viewBox="0 0 16 16"> - <path d="M1 2.5A1.5 1.5 0 0 1 2.5 1h3A1.5 1.5 0 0 1 7 2.5v3A1.5 1.5 0 0 1 5.5 7h-3A1.5 1.5 0 0 1 1 5.5zM2.5 2a.5.5 0 0 0-.5.5v3a.5.5 0 0 0 .5.5h3a.5.5 0 0 0 .5-.5v-3a.5.5 0 0 0-.5-.5zm6.5.5A1.5 1.5 0 0 1 10.5 1h3A1.5 1.5 0 0 1 15 2.5v3A1.5 1.5 0 0 1 13.5 7h-3A1.5 1.5 0 0 1 9 5.5zm1.5-.5a.5.5 0 0 0-.5.5v3a.5.5 0 0 0 .5.5h3a.5.5 0 0 0 .5-.5v-3a.5.5 0 0 0-.5-.5zM1 10.5A1.5 1.5 0 0 1 2.5 9h3A1.5 1.5 0 0 1 7 10.5v3A1.5 1.5 0 0 1 5.5 15h-3A1.5 1.5 0 0 1 1 13.5zm1.5-.5a.5.5 0 0 0-.5.5v3a.5.5 0 0 0 .5.5h3a.5.5 0 0 0 .5-.5v-3a.5.5 0 0 0-.5-.5zm6.5.5A1.5 1.5 0 0 1 10.5 9h3a1.5 1.5 0 0 1 1.5 1.5v3a1.5 1.5 0 0 1-1.5 1.5h-3A1.5 1.5 0 0 1 9 13.5zm1.5-.5a.5.5 0 0 0-.5.5v3a.5.5 0 0 0 .5.5h3a.5.5 0 0 0 .5-.5v-3a.5.5 0 0 0-.5-.5z"/> - </svg> - </monster-button --> - </div> - </template> - </monster-datatable> + <monster-datatable id="test-datatable" data-monster-datasource-selector="#data1"> - <monster-overlay id="overlay1" data-monster-option-features-openbutton="false"> + <monster-datasource-save-button slot="bar" data-monster-option-datasource-selector="#data1"> + </monster-datasource-save-button> + <monster-datasource-status slot="bar" data-monster-option-datasource-selector="#data1"> + </monster-datasource-status> + <template id="test-datatable-row"> - <monster-dataset id="dataset1" data-monster-datasource-selector="#data1"> + <div data-monster-head="erpName" data-monster-replace="path:test-datatable-row.erpName "></div> + <div data-monster-head="OID" data-monster-mode="fixed" data-monster-sortable="oid" data-monster-replace="path:test-datatable-row.oid | tostring"></div> + <div data-monster-head="erpLastUpdate" data-monster-replace="path:test-datatable-row.erpLastUpdate"></div> + <div data-monster-head="type" data-monster-replace="path:test-datatable-row.type"></div> + <div data-monster-head="customerUID" data-monster-replace="path:test-datatable-row.customerUID"></div> + <div data-monster-head="resubmissionDate" data-monster-replace="path:test-datatable-row.resubmissionDate"></div> + <div data-monster-head="billingAddressAID" data-monster-replace="path:test-datatable-row.billingAddressAID"></div> + <div data-monster-head="deliveryAddressAID" data-monster-replace="path:test-datatable-row.deliveryAddressAID"></div> - <div class="form-container"> - <h2>OVERLAY 1</h2> - <div class="inner-form"> - <label>test - <input data-monster-bind="path:data.oid" data-monster-bind-type="integer" - data-monster-attributes="value path:data.oid "></label> - <label>test - <input data-monster-bind="path:data.erpName" - data-monster-attributes="value path:data.erpName "></label> - <label>test - <input data-monster-bind="path:data.erpName" - data-monster-attributes="value path:data.erpNumber "></label> + <div data-monster-head=" " data-alvine-role="actionHolder" class="actionButtons"> - <div data-monster-replace="path:data.oid ">xx</div> - <div data-monster-replace="path:data.orderState ">xx</div> - <div data-monster-replace="path:data.orderLastStatusChange ">xx</div> + <monster-datatable-change-button style="height:100%;display:flex;margin-right:0.1rem;" data-monster-option-dataset-selector="#dataset1" data-monster-option-overlay-selector="#overlay1"> - <select data-monster-bind="path:data.type" data-monster-attributes="value path:data.type"> - <option value="">bitte wählen</option> - <option value="order">order</option> - <option value="22">22</option> - <option value="33">33</option> - </select> + </monster-datatable-change-button> + <monster-datatable-change-button style="height:100%;;display:flex;" data-monster-option-labels-button="o2" data-monster-option-dataset-selector="#dataset1" data-monster-option-overlay-selector="#overlay2"> - <!-- Ckeckbox wird ausgewählt wenn archived den Wert TRUE hat --> - <label>Checkbox - <input type="checkbox" value="true" data-monster-bind="path:data.archived" data-monster-bind-type="boolean" - data-monster-defaultvalue="false" data-monster-attributes="checked path:data.archived | ?:true: "></label> + </monster-datatable-change-button> - <div class="buttons"> - <monster-button - data-monster-role="saveButton" - id="saveButton" - style="display:block;width:200px;">save - </monster-button> - <monster-button - data-monster-role="cancelButton" - id="cancelButton" - style="display:block;width:200px;">cancel - </monster-button> + + <!--monster-button + data-alvine-role="changeButton" + data-monster-option-actions-click="" + data-monster-attributes="data-alvine-oid path:test-datatable-row.index"> + <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" + class="bi bi-grid" viewBox="0 0 16 16"> + <path d="M1 2.5A1.5 1.5 0 0 1 2.5 1h3A1.5 1.5 0 0 1 7 2.5v3A1.5 1.5 0 0 1 5.5 7h-3A1.5 1.5 0 0 1 1 5.5zM2.5 2a.5.5 0 0 0-.5.5v3a.5.5 0 0 0 .5.5h3a.5.5 0 0 0 .5-.5v-3a.5.5 0 0 0-.5-.5zm6.5.5A1.5 1.5 0 0 1 10.5 1h3A1.5 1.5 0 0 1 15 2.5v3A1.5 1.5 0 0 1 13.5 7h-3A1.5 1.5 0 0 1 9 5.5zm1.5-.5a.5.5 0 0 0-.5.5v3a.5.5 0 0 0 .5.5h3a.5.5 0 0 0 .5-.5v-3a.5.5 0 0 0-.5-.5zM1 10.5A1.5 1.5 0 0 1 2.5 9h3A1.5 1.5 0 0 1 7 10.5v3A1.5 1.5 0 0 1 5.5 15h-3A1.5 1.5 0 0 1 1 13.5zm1.5-.5a.5.5 0 0 0-.5.5v3a.5.5 0 0 0 .5.5h3a.5.5 0 0 0 .5-.5v-3a.5.5 0 0 0-.5-.5zm6.5.5A1.5 1.5 0 0 1 10.5 9h3a1.5 1.5 0 0 1 1.5 1.5v3a1.5 1.5 0 0 1-1.5 1.5h-3A1.5 1.5 0 0 1 9 13.5zm1.5-.5a.5.5 0 0 0-.5.5v3a.5.5 0 0 0 .5.5h3a.5.5 0 0 0 .5-.5v-3a.5.5 0 0 0-.5-.5z"/> + </svg> + </monster-button --> + </div> + </template> + </monster-datatable> + + <monster-overlay id="overlay1" data-monster-option-features-openbutton="false"> + + + <monster-dataset id="dataset1" data-monster-datasource-selector="#data1"> + + <div class="form-container"> + <h2>OVERLAY 1</h2> + <div class="inner-form"> + <label>test + <input data-monster-bind="path:data.oid" data-monster-bind-type="integer" data-monster-attributes="value path:data.oid "></label> + <label>test + <input data-monster-bind="path:data.erpName" data-monster-attributes="value path:data.erpName "></label> + <label>test + <input data-monster-bind="path:data.erpName" data-monster-attributes="value path:data.erpNumber "></label> + + <div data-monster-replace="path:data.oid ">xx</div> + <div data-monster-replace="path:data.orderState ">xx</div> + <div data-monster-replace="path:data.orderLastStatusChange ">xx</div> + + <label>select + <select data-monster-bind="path:data.type" data-monster-attributes="value path:data.type"> + <option value="">bitte wählen</option> + <option value="order">order</option> + <option value="22">22</option> + <option value="33">33</option> + </select> + </label> + + <label>monster select + <monster-select data-monster-bind="path:data.type" data-monster-attributes="value path:data.type"> + <div data-monster-value="order">Bestellung</div> + <div data-monster-value="test">label-2</div> + <div data-monster-value="wewe">label-3</div> + </monster-select> + </label> + + <label><!-- data-monster-option-values-on="true" data-monster-option-values-off="false" --> + toggle Switch + <monster-toggle-switch data-monster-bind="path:data.archived" data-monster-option-values-on="true" data-monster-option-values-off="false" data-monster-bind-type="boolean" data-monster-attributes="value path:data.archived | ?:true:false "></monster-toggle-switch> + </label> + + <!-- Ckeckbox wird ausgewählt wenn archived den Wert TRUE hat --> + <label>Checkbox + <input type="checkbox" value="true" data-monster-bind="path:data.archived" data-monster-bind-type="boolean" data-monster-defaultvalue="false" data-monster-attributes="checked path:data.archived | ?:true: "></label> + + <label>Datum erpLastUpdate + <input type="datetime-local" data-monster-bind="path:data.erpLastUpdate" data-monster-attributes="value path:data.erpLastUpdate" /> + </label> + + <div class="buttons"> + <monster-button data-monster-role="saveButton" id="saveButton" style="display:block;width:200px;">save + </monster-button> + <monster-button data-monster-role="cancelButton" id="cancelButton" style="display:block;width:200px;">cancel + </monster-button> + + </div> </div> @@ -170,18 +168,45 @@ </monster-button> </div> + </div> + </monster-dataset> + </monster-overlay> + + + <monster-overlay id="overlay2" data-monster-option-features-openbutton="false"> + + + <monster-dataset id="dataset2" data-monster-datasource-selector="#data1"> + + <div class="form-container"> + <h2>OVERLAY 2</h2> + <div class="inner-form"> + <label>test + <input data-monster-bind="path:data.oid" data-monster-bind-type="integer" data-monster-attributes="value path:data.oid "></label> + <label>test + <input data-monster-bind="path:data.erpName" data-monster-attributes="value path:data.erpName "></label> + + + <div class="buttons"> + <monster-button data-monster-role="saveButton" id="saveButton" style="display:block;width:200px;">save + </monster-button> + <monster-button data-monster-role="cancelButton" id="cancelButton" style="display:block;width:200px;">cancel + </monster-button> + + </div> + + </div> </div> - </div> - - </monster-dataset> - </monster-overlay> - </div> + + </monster-dataset> + </monster-overlay> + </div> -</main> + </main> </body> </html> \ No newline at end of file diff --git a/playground/bind-with-datasource/main.mjs b/playground/bind-with-datasource/main.mjs index 340f425986a76acfff4fa475b679646214052418..c836edc54691311a35dbfef431798d11bcc44ddd 100644 --- a/playground/bind-with-datasource/main.mjs +++ b/playground/bind-with-datasource/main.mjs @@ -1,5 +1,5 @@ -import "../../source/components/form/button.mjs"; + import "../../source/components/host/overlay.mjs"; import "../../source/components/datatable/datatable.mjs"; import "../../source/components/datatable/dataset.mjs"; @@ -7,10 +7,14 @@ import "../../source/components/datatable/datasource/dom.mjs"; import "../../source/components/datatable/datasource/rest.mjs"; import "../../source/components/datatable/save-button.mjs"; +import "../../source/components/form/button.mjs"; +import "../../source/components/form/select.mjs"; +import "../../source/components/form/toggle-switch.mjs"; + +import "../../source/components/style/common.pcss"; import "../../source/components/style/color.pcss"; import "../../source/components/style/theme.pcss"; import "../../source/components/style/table.pcss"; -import "../../source/components/style/property.pcss"; import "../../source/components/style/badge.pcss"; import "../../source/components/style/button.pcss"; import "../../source/components/style/link.pcss"; @@ -18,6 +22,7 @@ import "../../source/components/style/data-grid.pcss"; import "../../source/components/style/property.pcss"; import "../../source/components/style/typography.pcss"; import "../../source/components/style/display.pcss"; + import "../../source/components/datatable/datasource/rest.mjs"; import "../../source/components/datatable/filter.mjs"; import "../../source/components/datatable/filter-button.mjs"; @@ -53,6 +58,17 @@ let callbacks = { }}; data.setOption('write.mapping.callbacks', callbacks); +data.setOption('read.mapping.transformer', 'call:agenorFormater'); +let readCallbacks = { + agenorFormater: function (data) { + for (const [key, value] of Object.entries(data.dataset)) { + data.dataset[key].erpLastUpdate = '2020-01-16T10:27:18'; + } + return data; + } +}; +data.setOption('read.mapping.callbacks', readCallbacks); + let dataset1 = document.getElementById('dataset1'); //let dataset2 = document.getElementById('dataset2'); diff --git a/playground/toggle-switch/index.html b/playground/toggle-switch/index.html new file mode 100644 index 0000000000000000000000000000000000000000..c25526dbf93c797522e3608b06718214ea188269 --- /dev/null +++ b/playground/toggle-switch/index.html @@ -0,0 +1,41 @@ +<!doctype html> +<html lang="en"> + +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0"> + + <title>Switch</title> + <script src="main.mjs" type="module"></script> + + <script id="translations" type="application/json" data-monster-role="translations"> + { + "toggle-switch-on": "an", + "toggle-switch-off": "aus" + } + </script> + +</head> + +<body style="display:flex;justify-content: center"> + + <main style="width: 600px"> + + <h1 class="deco">Switch</h1> + + <p class="deco"></p> + + <div class="container"> + <form class="monster-form"> + <label>monster-switch + <monster-toggle-switch id="monsterToggleSwitch" name="agb" ></monster-toggle-switch> + </label> + <button>Submit</button> + </form> + </div> + + </main> + +</body> + +</html> \ No newline at end of file diff --git a/playground/toggle-switch/main.mjs b/playground/toggle-switch/main.mjs new file mode 100644 index 0000000000000000000000000000000000000000..117b82573d96e7ebb374a58eafacf7886351a98b --- /dev/null +++ b/playground/toggle-switch/main.mjs @@ -0,0 +1,36 @@ +import "./main.pcss"; + +import "../../source/components/style/common.pcss"; +import "../../source/components/form/toggle-switch.mjs"; +import "../../source/components/style/form.pcss"; +import "../../source/components/style/color.pcss"; +import "../../source/components/style/property.pcss"; + +import { Embed } from "../../source/i18n/providers/embed.mjs"; + +Embed.assignTranslationsToElement().then(() => { + let toggleSwitch = document.getElementById('monsterToggleSwitch'); + toggleSwitch.updateI18n(); + +}); + + + +// debugger + //let toggleSwitch = document.createElement('monster-toggle-switch'); + +// /** +// * define the values for on and off +// */ +// toggleSwitch.setOption('values.on', 'true'); +// toggleSwitch.setOption('values.off', 'false'); + +// /** +// * This value is not "true" and not "false" +// */ + //toggleSwitch.value = "on"; + + //document.body.appendChild(toggleSwitch); + +// let a = toggleSwitch.hasAttribute('disabled'); + diff --git a/playground/toggle-switch/main.pcss b/playground/toggle-switch/main.pcss new file mode 100644 index 0000000000000000000000000000000000000000..4a5405cb767c3d95ac67bc4ffcbfb342433fa74f --- /dev/null +++ b/playground/toggle-switch/main.pcss @@ -0,0 +1,9 @@ +@import"../../source/components/style/mixin/form.pcss"; + + +.container{ + font-size: 12px; + display: flex; + flex-direction: column; +} + diff --git a/source/components/form/style/toggle-switch.pcss b/source/components/form/style/toggle-switch.pcss new file mode 100644 index 0000000000000000000000000000000000000000..6c5814e3159eb19aecab4eb9e28a4f3bef559095 --- /dev/null +++ b/source/components/form/style/toggle-switch.pcss @@ -0,0 +1,74 @@ +@import "../../style/color.pcss"; +@import "../../style/theme.pcss"; +@import "../../style/border.pcss"; + +[data-monster-role=control] { + + font-family: inherit; + font-size: 100%; + padding: 0.4rem 0.6rem; + margin: 0; + outline: none; + box-sizing: border-box; +} + +[data-monster-role=control]:focus { + outline: 1px dashed var(--monster-color-selection-3); + outline-offset: 2px; +} + +.switch { + position: relative; + display: inline-block; + width: 60px; + height: 34px; + + border-color: var(--monster-bg-color-primary-3); + border-width: thin; + border-style: var(--monster-border-style); + transition: background-color 0.2s; + display: grid; + grid-template-columns: 1fr 1fr; +} + +.switch-radio input[type="radio"] { + display: none; +} + +.label{ + height: 34px; + display: block; + text-align: center; + line-height: 34px; + user-select: none; +} + +.switch-slider { + position: absolute; + top: 4px; + bottom: 4px; + left: 4px; + right: 28px; + background-color: var(--monster-bg-color-primary-4); + transition: 0.2s; +} + +.switch[data-monster-state="on"] .label.off { + visibility: hidden; +} +.switch[data-monster-state="on"] .label.on { + visibility: visible; +} +.switch[data-monster-state="off"] .label.off { + visibility: visible; +} +.switch[data-monster-state="off"] .label.on { + visibility: hidden; +} + + +.switch[data-monster-state="on"] .switch-slider { + transform: translateX(24px); + +} + diff --git a/source/components/form/stylesheet/toggle-switch.mjs b/source/components/form/stylesheet/toggle-switch.mjs new file mode 100644 index 0000000000000000000000000000000000000000..b2b7318bdc72c290d3f121848434db3d6b4bcb4a --- /dev/null +++ b/source/components/form/stylesheet/toggle-switch.mjs @@ -0,0 +1,27 @@ + +/** + * Copyright schukai GmbH and contributors 2024. All Rights Reserved. + * Node module: @schukai/monster + * This file is licensed under the AGPLv3 License. + * License text available at https://www.gnu.org/licenses/agpl-3.0.en.html + */ + +import {addAttributeToken} from "../../../dom/attributes.mjs"; +import {ATTRIBUTE_ERRORMESSAGE} from "../../../dom/constants.mjs"; + +export {ToggleSwitchStyleSheet} + +/** + * @private + * @type {CSSStyleSheet} + */ +const ToggleSwitchStyleSheet = new CSSStyleSheet(); + +try { + ToggleSwitchStyleSheet.insertRule(` +@layer toggleswitch { +:after,:before,:root{--monster-color-gray-1:#f6f6f6;--monster-color-gray-2:#e2e2e2;--monster-color-gray-3:#8b8b8b;--monster-color-gray-4:#6f6f6f;--monster-color-gray-5:#3e3e3e;--monster-color-gray-6:#222;--monster-color-rose-1:#fff7f9;--monster-color-rose-2:#ffdce5;--monster-color-rose-3:#ff3b8d;--monster-color-rose-4:#db0072;--monster-color-rose-5:#800040;--monster-color-rose-6:#4c0023;--monster-color-raspberry-1:#fff8f8;--monster-color-raspberry-2:#ffdddf;--monster-color-raspberry-3:#ff426c;--monster-color-raspberry-4:#de0051;--monster-color-raspberry-5:#82002c;--monster-color-raspberry-6:#510018;--monster-color-red-1:#fff8f6;--monster-color-red-2:#ffddd8;--monster-color-red-3:#ff4647;--monster-color-red-4:#e0002b;--monster-color-red-5:#830014;--monster-color-red-6:#530003;--monster-color-orange-1:#fff8f5;--monster-color-orange-2:#ffded1;--monster-color-orange-3:#fd4d00;--monster-color-orange-4:#cd3c00;--monster-color-orange-5:#752100;--monster-color-orange-6:#401600;--monster-color-cinnamon-1:#fff8f3;--monster-color-cinnamon-2:#ffdfc6;--monster-color-cinnamon-3:#d57300;--monster-color-cinnamon-4:#ac5c00;--monster-color-cinnamon-5:#633300;--monster-color-cinnamon-6:#371d00;--monster-color-amber-1:#fff8ef;--monster-color-amber-2:#ffe0b2;--monster-color-amber-3:#b98300;--monster-color-amber-4:#926700;--monster-color-amber-5:#523800;--monster-color-amber-6:#302100;--monster-color-yellow-1:#fff9e5;--monster-color-yellow-2:#ffe53e;--monster-color-yellow-3:#9c8b00;--monster-color-yellow-4:#7d6f00;--monster-color-yellow-5:#463d00;--monster-color-yellow-6:#292300;--monster-color-lime-1:#f7ffac;--monster-color-lime-2:#d5f200;--monster-color-lime-3:#819300;--monster-color-lime-4:#677600;--monster-color-lime-5:#394100;--monster-color-lime-6:#222600;--monster-color-chartreuse-1:#e5ffc3;--monster-color-chartreuse-2:#98fb00;--monster-color-chartreuse-3:#5c9b00;--monster-color-chartreuse-4:#497c00;--monster-color-chartreuse-5:#264500;--monster-color-chartreuse-6:#182600;--monster-color-green-1:#e0ffd9;--monster-color-green-2:#72ff6c;--monster-color-green-3:#00a21f;--monster-color-green-4:#008217;--monster-color-green-5:#004908;--monster-color-green-6:#062800;--monster-color-emerald-1:#dcffe6;--monster-color-emerald-2:#5dffa2;--monster-color-emerald-3:#00a05a;--monster-color-emerald-4:#008147;--monster-color-emerald-5:#004825;--monster-color-emerald-6:#002812;--monster-color-aquamarine-1:#daffef;--monster-color-aquamarine-2:#42ffc6;--monster-color-aquamarine-3:#009f78;--monster-color-aquamarine-4:#007f5f;--monster-color-aquamarine-5:#004734;--monster-color-aquamarine-6:#00281b;--monster-color-teal-1:#d7fff7;--monster-color-teal-2:#00ffe4;--monster-color-teal-3:#009e8c;--monster-color-teal-4:#007c6e;--monster-color-teal-5:#00443c;--monster-color-teal-6:#002722;--monster-color-cyan-1:#c4fffe;--monster-color-cyan-2:#00fafb;--monster-color-cyan-3:#00999a;--monster-color-cyan-4:#007a7b;--monster-color-cyan-5:#004344;--monster-color-cyan-6:#002525;--monster-color-powder-1:#dafaff;--monster-color-powder-2:#8df0ff;--monster-color-powder-3:#0098a9;--monster-color-powder-4:#007987;--monster-color-powder-5:#004048;--monster-color-powder-6:#002227;--monster-color-sky-1:#e3f7ff;--monster-color-sky-2:#aee9ff;--monster-color-sky-3:#0094b4;--monster-color-sky-4:#007590;--monster-color-sky-5:#00404f;--monster-color-sky-6:#001f28;--monster-color-cerulean-1:#e8f6ff;--monster-color-cerulean-2:#b9e3ff;--monster-color-cerulean-3:#0092c5;--monster-color-cerulean-4:#00749d;--monster-color-cerulean-5:#003c54;--monster-color-cerulean-6:#001d2a;--monster-color-azure-1:#e8f2ff;--monster-color-azure-2:#c6e0ff;--monster-color-azure-3:#008fdb;--monster-color-azure-4:#0071af;--monster-color-azure-5:#003b5e;--monster-color-azure-6:#001c30;--monster-color-blue-1:#f0f4ff;--monster-color-blue-2:#d4e0ff;--monster-color-blue-3:#0089fc;--monster-color-blue-4:#006dca;--monster-color-blue-5:#00386d;--monster-color-blue-6:#001a39;--monster-color-indigo-1:#f3f3ff;--monster-color-indigo-2:#deddff;--monster-color-indigo-3:#657eff;--monster-color-indigo-4:#0061fc;--monster-color-indigo-5:#00328a;--monster-color-indigo-6:#001649;--monster-color-violet-1:#f7f1ff;--monster-color-violet-2:#e8daff;--monster-color-violet-3:#9b70ff;--monster-color-violet-4:#794aff;--monster-color-violet-5:#2d0fbf;--monster-color-violet-6:#0b0074;--monster-color-purple-1:#fdf4ff;--monster-color-purple-2:#f7d9ff;--monster-color-purple-3:#d150ff;--monster-color-purple-4:#b01fe3;--monster-color-purple-5:#660087;--monster-color-purple-6:#3a004f;--monster-color-magenta-1:#fff3fc;--monster-color-magenta-2:#ffd7f6;--monster-color-magenta-3:#f911e0;--monster-color-magenta-4:#ca00b6;--monster-color-magenta-5:#740068;--monster-color-magenta-6:#44003c;--monster-color-pink-1:#fff7fb;--monster-color-pink-2:#ffdcec;--monster-color-pink-3:#ff2fb2;--monster-color-pink-4:#d2008f;--monster-color-pink-5:#790051;--monster-color-pink-6:#4b0030}.monster-theme-primary-1{background-color:var(--monster-bg-color-primary-1);color:var(--monster-color-primary-1)}.monster-theme-primary-disabled-1{background-color:var(--monster-bg-color-primary-disabled-1);color:var(--monster-color-primary-disabled-1)}.monster-theme-secondary-1{background-color:var(--monster-bg-color-secondary-1);color:var(--monster-color-secondary-1)}.monster-theme-tertiary-1{background-color:var(--monster-bg-color-tertiary-1);color:var(--monster-color-tertiary-1)}.monster-theme-destructive-1{background-color:var(--monster-bg-color-destructive-1);color:var(--monster-color-destructive-1)}.monster-theme-success-1{background-color:var(--monster-bg-color-success-1);color:var(--monster-color-success-1)}.monster-theme-warning-1{background-color:var(--monster-bg-color-warning-1);color:var(--monster-color-warning-1)}.monster-theme-error-1{background-color:var(--monster-bg-color-error-1);color:var(--monster-color-error-1)}.monster-theme-selection-1{background-color:var(--monster-bg-color-selection-1);color:var(--monster-color-selection-1)}.monster-border-color-1{border-color:var(--monster-color-border-1)}.monster-color-neutral-1{color:var(--monster-color-primary-1)}.monster-bg-color-primary-1{background-color:var(--monster-bg-color-primary-1)}.monster-bg-color-secondary-1{background-color:var(--monster-bg-color-secondary-1)}.monster-bg-color-tertiary-1{background-color:var(--monster-bg-color-tertiary-1)}.monster-color-primary-1{background-color:var(--monster-bg-color-primary-1);color:var(--monster-color-primary-1)}.monster-color-secondary-1{background-color:var(--monster-bg-color-secondary-1);color:var(--monster-color-secondary-1)}.monster-color-tertiary-1{background-color:var(--monster-bg-color-tertiary-1);color:var(--monster-color-tertiary-1)}.monster-color-destructive-1{background-color:var(--monster-bg-color-destructive-1);color:var(--monster-color-destructive-1)}.monster-color-success-1{background-color:var(--monster-bg-color-success-1);color:var(--monster-color-success-1)}.monster-color-warning-1{background-color:var(--monster-bg-color-warning-1);color:var(--monster-color-warning-1)}.monster-color-error-1{background-color:var(--monster-bg-color-error-1);color:var(--monster-color-error-1)}.monster-color-selection-1{background-color:var(--monster-bg-color-selection-1);color:var(--monster-color-selection-1)}.monster-theme-primary-2{background-color:var(--monster-bg-color-primary-2);color:var(--monster-color-primary-2)}.monster-theme-primary-disabled-2{background-color:var(--monster-bg-color-primary-disabled-2);color:var(--monster-color-primary-disabled-2)}.monster-theme-secondary-2{background-color:var(--monster-bg-color-secondary-2);color:var(--monster-color-secondary-2)}.monster-theme-tertiary-2{background-color:var(--monster-bg-color-tertiary-2);color:var(--monster-color-tertiary-2)}.monster-theme-destructive-2{background-color:var(--monster-bg-color-destructive-2);color:var(--monster-color-destructive-2)}.monster-theme-success-2{background-color:var(--monster-bg-color-success-2);color:var(--monster-color-success-2)}.monster-theme-warning-2{background-color:var(--monster-bg-color-warning-2);color:var(--monster-color-warning-2)}.monster-theme-error-2{background-color:var(--monster-bg-color-error-2);color:var(--monster-color-error-2)}.monster-theme-selection-2{background-color:var(--monster-bg-color-selection-2);color:var(--monster-color-selection-2)}.monster-border-color-2{border-color:var(--monster-color-border-2)}.monster-color-neutral-2{color:var(--monster-color-primary-2)}.monster-bg-color-primary-2{background-color:var(--monster-bg-color-primary-2)}.monster-bg-color-secondary-2{background-color:var(--monster-bg-color-secondary-2)}.monster-bg-color-tertiary-2{background-color:var(--monster-bg-color-tertiary-2)}.monster-color-primary-2{background-color:var(--monster-bg-color-primary-2);color:var(--monster-color-primary-2)}.monster-color-secondary-2{background-color:var(--monster-bg-color-secondary-2);color:var(--monster-color-secondary-2)}.monster-color-tertiary-2{background-color:var(--monster-bg-color-tertiary-2);color:var(--monster-color-tertiary-2)}.monster-color-destructive-2{background-color:var(--monster-bg-color-destructive-2);color:var(--monster-color-destructive-2)}.monster-color-success-2{background-color:var(--monster-bg-color-success-2);color:var(--monster-color-success-2)}.monster-color-warning-2{background-color:var(--monster-bg-color-warning-2);color:var(--monster-color-warning-2)}.monster-color-error-2{background-color:var(--monster-bg-color-error-2);color:var(--monster-color-error-2)}.monster-color-selection-2{background-color:var(--monster-bg-color-selection-2);color:var(--monster-color-selection-2)}.monster-theme-primary-3{background-color:var(--monster-bg-color-primary-3);color:var(--monster-color-primary-3)}.monster-theme-primary-disabled-3{background-color:var(--monster-bg-color-primary-disabled-3);color:var(--monster-color-primary-disabled-3)}.monster-theme-secondary-3{background-color:var(--monster-bg-color-secondary-3);color:var(--monster-color-secondary-3)}.monster-theme-tertiary-3{background-color:var(--monster-bg-color-tertiary-3);color:var(--monster-color-tertiary-3)}.monster-theme-destructive-3{background-color:var(--monster-bg-color-destructive-3);color:var(--monster-color-destructive-3)}.monster-theme-success-3{background-color:var(--monster-bg-color-success-3);color:var(--monster-color-success-3)}.monster-theme-warning-3{background-color:var(--monster-bg-color-warning-3);color:var(--monster-color-warning-3)}.monster-theme-error-3{background-color:var(--monster-bg-color-error-3);color:var(--monster-color-error-3)}.monster-theme-selection-3{background-color:var(--monster-bg-color-selection-3);color:var(--monster-color-selection-3)}.monster-border-color-3{border-color:var(--monster-color-border-3)}.monster-color-neutral-3{color:var(--monster-color-primary-3)}.monster-bg-color-primary-3{background-color:var(--monster-bg-color-primary-3)}.monster-bg-color-secondary-3{background-color:var(--monster-bg-color-secondary-3)}.monster-bg-color-tertiary-3{background-color:var(--monster-bg-color-tertiary-3)}.monster-color-primary-3{background-color:var(--monster-bg-color-primary-3);color:var(--monster-color-primary-3)}.monster-color-secondary-3{background-color:var(--monster-bg-color-secondary-3);color:var(--monster-color-secondary-3)}.monster-color-tertiary-3{background-color:var(--monster-bg-color-tertiary-3);color:var(--monster-color-tertiary-3)}.monster-color-destructive-3{background-color:var(--monster-bg-color-destructive-3);color:var(--monster-color-destructive-3)}.monster-color-success-3{background-color:var(--monster-bg-color-success-3);color:var(--monster-color-success-3)}.monster-color-warning-3{background-color:var(--monster-bg-color-warning-3);color:var(--monster-color-warning-3)}.monster-color-error-3{background-color:var(--monster-bg-color-error-3);color:var(--monster-color-error-3)}.monster-color-selection-3{background-color:var(--monster-bg-color-selection-3);color:var(--monster-color-selection-3)}.monster-theme-primary-4{background-color:var(--monster-bg-color-primary-4);color:var(--monster-color-primary-4)}.monster-theme-primary-disabled-4{background-color:var(--monster-bg-color-primary-disabled-4);color:var(--monster-color-primary-disabled-4)}.monster-theme-secondary-4{background-color:var(--monster-bg-color-secondary-4);color:var(--monster-color-secondary-4)}.monster-theme-tertiary-4{background-color:var(--monster-bg-color-tertiary-4);color:var(--monster-color-tertiary-4)}.monster-theme-destructive-4{background-color:var(--monster-bg-color-destructive-4);color:var(--monster-color-destructive-4)}.monster-theme-success-4{background-color:var(--monster-bg-color-success-4);color:var(--monster-color-success-4)}.monster-theme-warning-4{background-color:var(--monster-bg-color-warning-4);color:var(--monster-color-warning-4)}.monster-theme-error-4{background-color:var(--monster-bg-color-error-4);color:var(--monster-color-error-4)}.monster-theme-selection-4{background-color:var(--monster-bg-color-selection-4);color:var(--monster-color-selection-4)}.monster-border-color-4{border-color:var(--monster-color-border-4)}.monster-color-neutral-4{color:var(--monster-color-primary-4)}.monster-bg-color-primary-4{background-color:var(--monster-bg-color-primary-4)}.monster-bg-color-secondary-4{background-color:var(--monster-bg-color-secondary-4)}.monster-bg-color-tertiary-4{background-color:var(--monster-bg-color-tertiary-4)}.monster-color-primary-4{background-color:var(--monster-bg-color-primary-4);color:var(--monster-color-primary-4)}.monster-color-secondary-4{background-color:var(--monster-bg-color-secondary-4);color:var(--monster-color-secondary-4)}.monster-color-tertiary-4{background-color:var(--monster-bg-color-tertiary-4);color:var(--monster-color-tertiary-4)}.monster-color-destructive-4{background-color:var(--monster-bg-color-destructive-4);color:var(--monster-color-destructive-4)}.monster-color-success-4{background-color:var(--monster-bg-color-success-4);color:var(--monster-color-success-4)}.monster-color-warning-4{background-color:var(--monster-bg-color-warning-4);color:var(--monster-color-warning-4)}.monster-color-error-4{background-color:var(--monster-bg-color-error-4);color:var(--monster-color-error-4)}.monster-color-selection-4{background-color:var(--monster-bg-color-selection-4);color:var(--monster-color-selection-4)}.monster-border-primary-1,.monster-border-primary-2,.monster-border-primary-3,.monster-border-primary-4{border-radius:var(--monster-border-radius);border-style:var(--monster-border-style);border-width:var(--monster-border-width);border-shadow:var(--monster-box-shadow-1)}.monster-border-0{border-radius:0;border-style:none;border-width:0;border-shadow:none}.monster-border-primary-1{border-color:var(--monster-bg-color-primary-1)}.monster-border-primary-2{border-color:var(--monster-bg-color-primary-2)}.monster-border-primary-3{border-color:var(--monster-bg-color-primary-3)}.monster-border-primary-4{border-color:var(--monster-bg-color-primary-4)}.monster-border-secondary-1,.monster-border-secondary-2,.monster-border-secondary-3,.monster-border-secondary-4{border-radius:var(--monster-border-radius);border-style:var(--monster-border-style);border-width:var(--monster-border-width);border-shadow:var(--monster-box-shadow-1)}.monster-border-secondary-1{border-color:var(--monster-bg-color-secondary-1)}.monster-border-secondary-2{border-color:var(--monster-bg-color-secondary-2)}.monster-border-secondary-3{border-color:var(--monster-bg-color-secondary-3)}.monster-border-secondary-4{border-color:var(--monster-bg-color-secondary-4)}.monster-border-tertiary-1,.monster-border-tertiary-2,.monster-border-tertiary-3,.monster-border-tertiary-4{border-radius:var(--monster-border-radius);border-style:var(--monster-border-style);border-width:var(--monster-border-width);border-shadow:var(--monster-box-shadow-1)}.monster-border-tertiary-1{border-color:var(--monster-bg-color-tertiary-1)}.monster-border-tertiary-2{border-color:var(--monster-bg-color-tertiary-2)}.monster-border-tertiary-3{border-color:var(--monster-bg-color-tertiary-3)}.monster-border-tertiary-4{border-color:var(--monster-bg-color-tertiary-4)}[data-monster-role=control]{box-sizing:border-box;font-family:inherit;font-size:100%;margin:0;outline:none;padding:.4rem .6rem}[data-monster-role=control]:focus{outline:1px dashed var(--monster-color-selection-3);outline-offset:2px}.switch{border-color:var(--monster-bg-color-primary-3);border-style:var(--monster-border-style);border-width:thin;display:inline-block;display:grid;grid-template-columns:1fr 1fr;height:34px;position:relative;transition:background-color .2s;width:60px}.switch-radio input[type=radio]{display:none}.label{display:block;height:34px;line-height:34px;text-align:center;-webkit-user-select:none;-moz-user-select:none;user-select:none}.switch-slider{background-color:var(--monster-bg-color-primary-4);bottom:4px;left:4px;position:absolute;right:28px;top:4px;transition:.2s}.switch[data-monster-state=on] .label.off{visibility:hidden}.switch[data-monster-state=off] .label.off,.switch[data-monster-state=on] .label.on{visibility:visible}.switch[data-monster-state=off] .label.on{visibility:hidden}.switch[data-monster-state=on] .switch-slider{transform:translateX(24px)} +}`, 0); +} catch (e) { + addAttributeToken(document.getRootNode().querySelector('html'), ATTRIBUTE_ERRORMESSAGE, e + ""); +} diff --git a/source/components/form/toggle-switch.mjs b/source/components/form/toggle-switch.mjs new file mode 100644 index 0000000000000000000000000000000000000000..aa2a4a90c28c11fc46e3898af2a110a6b0c8088d --- /dev/null +++ b/source/components/form/toggle-switch.mjs @@ -0,0 +1,427 @@ +/** + * Copyright schukai GmbH and contributors 2024. All Rights Reserved. + * Node module: @schukai/monster + * This file is licensed under the AGPLv3 License. + * License text available at https://www.gnu.org/licenses/agpl-3.0.en.html + */ +import { instanceSymbol } from "../../constants.mjs"; +import { internalSymbol } from "../../constants.mjs"; +import { CustomControl } from "../../dom/customcontrol.mjs"; +import { Observer } from "../../types/observer.mjs"; +import { ProxyObserver } from "../../types/proxyobserver.mjs"; + +import { addAttributeToken } from "../../dom/attributes.mjs"; +import { + assembleMethodSymbol, + registerCustomElement, + updaterTransformerMethodsSymbol +} from "../../dom/customelement.mjs"; +import { + isObject +} from "../../types/is.mjs"; +import { ToggleSwitchStyleSheet } from "./stylesheet/toggle-switch.mjs"; +import { + ATTRIBUTE_ERRORMESSAGE, + ATTRIBUTE_ROLE, +} from "../../dom/constants.mjs"; +export { ToggleSwitch }; + +/** + * @private + * @type {symbol} + */ +const switchElementSymbol = Symbol("switchElement"); + +/** + * @private + * @type {symbol} + */ +const switchElementSymbolOn = Symbol("switchElementOn"); + +/** + * @private + * @type {symbol} + */ +const switchElementSymbolOff = Symbol("switchElementOff"); + +/** + * @type {string} + */ +export const STATE_ON = 'on'; + +/** + * @type {string} + */ +export const STATE_OFF = 'off'; + +/** + * This CustomControl creates a ToggleSwitch element + * + * <img src="./images/switch.png"> + * + * + * @startuml toggleswitch.png + * skinparam monochrome true + * skinparam shadowing false + * HTMLElement <|-- CustomElement + * CustomElement <|-- CustomControl + * CustomControl <|-- ToggleSwitch + * @enduml + * + * @since 3.57.0 + * @copyright schukai GmbH + * @memberOf Monster.Components.Form + * @summary A simple Switch + */ +class ToggleSwitch extends CustomControl { + + /** + * This method is called by the `instanceof` operator. + * @returns {symbol} + * @since 2.1.0 + */ + static get [instanceSymbol]() { + return Symbol.for("@schukai/monster/components/form/toggle-switch@@instance"); + } + + static getTag() { + return "monster-toggle-switch"; + } + + /** + * To set the options via the html tag the attribute `data-monster-options` must be used. + * @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control} + * + * The individual configuration values can be found in the table. + * + * @property {string} value=current value of the element + * @property {Boolean} disabled=disabled=false Disabled state + * @property {Object} classes + * @property {string} classes.on=specifies the class for the on state. + * @property {string} classes.off=specifies the class for the off state. + * @property {Object} values + * @property {string} values.off=specifies the value of the element if it is not selected + * @property {Object} labels + * @property {string} labels.on=specifies the label for the on state. + * @property {string} labels.off=specifies the label for the off state. + * @property {Object} templates + * @property {string} templates.main=specifies the main template used by the control. + * + * @since 3.57.0 + */ + get defaults() { + return Object.assign({}, super.defaults, { + value: null, + disabled: false, + classes: { + "on": "monster-theme-primary-3", + "off": "monster-theme-primary-2" + }, + values: { + on: "on", + off: "off" + }, + labels: { + "toggle-switch-on": "ON", + "toggle-switch-off": "OFF", + }, + templates: { + main: getTemplate() + } + }) + } + + /** + * + * @return {Monster.Components.Form.Button} + */ + [assembleMethodSymbol]() { + const self = this; + super[assembleMethodSymbol](); + initControlReferences.call(this); + initEventHandler.call(this); + + /** + * init value to off + * if the value was not defined before inserting it into the HTML + */ + if (self.getOption("value") === null) { + self.setOption('value', self.getOption("values.off")); + } + + /** + * value from attribute + */ + if (self.hasAttribute("value")) { + self.setOption('value', self.getAttribute("value")); + } + + /** + * validate value + */ + validateAndSetValue.call(self); + + if(this.state === STATE_ON) { + toggleClassOn.call(self); + }else{ + toggleClassOff.call(self); + } + + /** + * is called when options changed + */ + self[internalSymbol].attachObserver( + new Observer(function () { + if (isObject(this) && this instanceof ProxyObserver) { + validateAndSetValue.call(self); + toggleClass.call(self); + } + }), + ); + + return this; + } + + /** + * updater transformer methods for pipe + * + * @return {function} + */ + [updaterTransformerMethodsSymbol]() { + const self = this; + return { + "state-callback": (Wert) => { + return self.state; + } + } + } + + /** + * @return [SwitchStyleSheet] + */ + static getCSSStyleSheet() { + return [ToggleSwitchStyleSheet]; + } + + /** + * toggle switch + * + * ``` + * e = document.querySelector('monster-toggle-switch'); + * e.click() + * ``` + */ + click() { + toggleValues.call(this); + } + + /** + * toggle switch on/off + * + * ``` + * e = document.querySelector('monster-toggle-switch'); + * e.toggle() + * ``` + * + * @return {ToggleSwitch} + */ + toggle() { + this.click(); + return this; + } + + /** + * toggle switch on + * + * ``` + * e = document.querySelector('monster-toggle-switch'); + * e.toggleOn() + * ``` + * + * @return {ToggleSwitch} + */ + toggleOn() { + this.setOption('value', this.getOption('values.on')); + return this; + }; + + /** + * toggle switch off + * + * ``` + * e = document.querySelector('monster-toggle-switch'); + * e.toggleOff() + * ``` + * + * @return {ToggleSwitch} + */ + toggleOff() { + this.setOption('value', this.getOption('values.off')); + return this; + }; + + /** + * returns the status of the element + * + * ``` + * e = document.querySelector('monster-toggle-switch'); + * console.log(e.state) + * // ↦ off + * ``` + * + * @return {string} + */ + get state() { + return this.getOption('value') === this.getOption('values.on') ? STATE_ON : STATE_OFF; + } + + /** + * The current value of the Switch + * + * ``` + * e = document.querySelector('monster-toggle-switch'); + * console.log(e.value) + * // ↦ on + * ``` + * + * @return {string} + */ + get value() { + return this.state === STATE_ON ? this.getOption('values.on') : this.getOption('values.off'); + } + + /** + * Set value + * + * ``` + * e = document.querySelector('monster-toggle-switch'); + * e.value="on" + * ``` + * + * @property {string} value + */ + set value(value) { + this.setOption('value', value); + } + +} + +/** + * @private + */ +function initControlReferences() { + this[switchElementSymbol] = this.shadowRoot.querySelector( + `[${ATTRIBUTE_ROLE}=switch]`, + ); +} + +/** +* @private +*/ +function toggleClassOn() { + this[switchElementSymbol].classList.remove(this.getOption('classes.off')); // change color + this[switchElementSymbol].classList.add(this.getOption('classes.on'));// change color +} + +/** +* @private +*/ +function toggleClassOff() { + this[switchElementSymbol].classList.remove(this.getOption('classes.on'));// change color + this[switchElementSymbol].classList.add(this.getOption('classes.off'));// change color +} + +/** +* @private +*/ +function toggleClass() { + const self = this; + if (self.getOption('value') === self.getOption('values.on')) { + toggleClassOn.call(self); + } else { + toggleClassOff.call(self); + } +} + +/** + * @private + */ +function toggleValues() { + const self = this; + + if (self.getOption('disabled') === true) { + return; + } + + if (self.getOption('value') === self.getOption('values.on')) { + self.setOption('value', this.getOption('values.off')); + self?.setFormValue(self.getOption('value')); // set form value + } else { + self.setOption('value', this.getOption('values.on')); + self?.setFormValue(self.getOption('values.off')); // set form value + } + + self.setOption('state', self.state); +} + +/** +* @private +*/ +function validateAndSetValue() { + let self = this; + let value = self.getOption('value'); + + let validatedValues = []; + validatedValues.push(this.getOption('values.on')); + validatedValues.push(this.getOption('values.off')); + + if (validatedValues.includes(value) === false) { + addAttributeToken( + this, + ATTRIBUTE_ERRORMESSAGE, + 'The value "' + value + '" must be "' + self.getOption("values.on") + '" or "' + self.getOption("values.off"), + ); + self.setOption('disabled', true); + self.formDisabledCallback(true); + } else { + self.setOption('disabled', false); + self.formDisabledCallback(false); + } +} + +/** + * @private + * @return {initEventHandler} + */ +function initEventHandler() { + const self = this; + self.addEventListener("keyup", function (event) { + if (event.code === 'Space') { + self[switchElementSymbol].click(); + } + }); + self.addEventListener("click", function (event) { + toggleValues.call(self); + }); + return this; +} + +/** + * @private + * @return {string} + */ +function getTemplate() { + // language=HTML + return ` + <div data-monster-role="control" part="control" tabindex="0"> + + <div class="switch" data-monster-role="switch" data-monster-attributes="data-monster-state path:value | call:state-callback " > + <div class="label on" data-monster-replace="path:labels.toggle-switch-on"></div> + <div class="label off" data-monster-replace="path:labels.toggle-switch-off"></div> + <div class="switch-slider"></div> + </div> + + </div>`; +} + +registerCustomElement(ToggleSwitch); \ No newline at end of file diff --git a/test/cases/components/form/toggle-switch.mjs b/test/cases/components/form/toggle-switch.mjs new file mode 100644 index 0000000000000000000000000000000000000000..bcd50923038d3a397e7cfffd3cca2a3a2f4340b1 --- /dev/null +++ b/test/cases/components/form/toggle-switch.mjs @@ -0,0 +1,310 @@ +import { getGlobal } from "../../../../source/types/global.mjs"; +import chai from "chai" +import { chaiDom } from "../../../util/chai-dom.mjs"; +import { initJSDOM } from "../../../util/jsdom.mjs"; + +let expect = chai.expect; +chai.use(chaiDom); + +const global = getGlobal(); + +let html1 = ` + <div id="test1"> + </div> +`; + +let html2 = ` + <div id="test2"> + <monster-toggle-switch></monster-toggle-switch> + </div> +`; + +let ToggleSwitch; + +describe('ToggleSwitch', function () { + + before(function (done) { + initJSDOM().then(() => { + + import("element-internals-polyfill").catch(e => done(e)); + + import("../../../../source/components/form/toggle-switch.mjs").then((m) => { + ToggleSwitch = m['ToggleSwitch']; + done() + }).catch(e => done(e)) + + + }); + }) + + describe('new ToggleSwitch', function () { + + beforeEach(() => { + let mocks = document.getElementById('mocks'); + mocks.innerHTML = html1; + }) + + afterEach(() => { + let mocks = document.getElementById('mocks'); + mocks.innerHTML = ""; + }) + + describe('create from template', function () { + beforeEach(() => { + let mocks = document.getElementById('mocks'); + mocks.innerHTML = html2; + }); + + afterEach(() => { + let mocks = document.getElementById('mocks'); + mocks.innerHTML = ""; + + }) + + describe('create from template', function () { + it('should contains monster-toggle-switch', function () { + expect(document.getElementById('test2')).contain.html('<monster-toggle-switch'); + }); + }); + + }); + + describe('document.createElement', function () { + it('should instance of monster-toggle-switch', function () { + expect(document.createElement('monster-toggle-switch')).is.instanceof(ToggleSwitch); + }); + }); + + }); + + describe('toggle', function () { + beforeEach(() => { + let mocks = document.getElementById('mocks'); + mocks.innerHTML = html1; + }); + + afterEach(() => { + let mocks = document.getElementById('mocks'); + mocks.innerHTML = ""; + }) + + it('toggle to on', function () { + + const toggleSwitch = document.createElement('monster-toggle-switch'); + + expect(toggleSwitch.value).is.equal('off'); + expect(toggleSwitch.state).is.equal('off'); + + toggleSwitch.toggle(); + + expect(toggleSwitch.value).is.equal('on'); + expect(toggleSwitch.state).is.equal('on'); + + toggleSwitch.toggle(); + + expect(toggleSwitch.value).is.equal('off'); + expect(toggleSwitch.state).is.equal('off'); + }); + + it('toggle on to off', function () { + + const toggleSwitch = document.createElement('monster-toggle-switch'); + + toggleSwitch.toggleOn(); + + expect(toggleSwitch.value).is.equal('on'); + expect(toggleSwitch.state).is.equal('on'); + + toggleSwitch.toggleOff(); + + expect(toggleSwitch.value).is.equal('off'); + expect(toggleSwitch.state).is.equal('off'); + + }); + + + }); + + describe('describe css', function () { + + beforeEach(() => { + let mocks = document.getElementById('mocks'); + mocks.innerHTML = html1; + }); + + afterEach(() => { + let mocks = document.getElementById('mocks'); + mocks.innerHTML = ""; + }) + + it('css toggle', function (done) { + + /** + * new Control + */ + const toggleSwitch = document.createElement('monster-toggle-switch'); + + /** + * set init value to on + */ + toggleSwitch.value = "on"; + + /** + * insert DOM + */ + document.getElementById('mocks').appendChild(toggleSwitch); + + /** + * expect that classes.on is set to Element Switch + */ + let hasClassA = toggleSwitch.shadowRoot.querySelectorAll('[data-monster-role="switch"]')[0].classList.contains(toggleSwitch.getOption('classes.on')); + expect(hasClassA).is.true; + + /** + * switch off + */ + toggleSwitch.value = "off"; + + /** + * Updater prozess runs in setTimeout + * self[internalSymbol].attachObserver(); + */ + setTimeout(() => { + + /** + * expect that classes.on is removed from Element Switch + */ + let hasClassB = toggleSwitch.shadowRoot.querySelectorAll('[data-monster-role="switch"]')[0].classList.contains(toggleSwitch.getOption('classes.on')); + expect(hasClassB).is.false; + + /** + * expect that classes.off is set to Element Switch + */ + let hasClassC = toggleSwitch.shadowRoot.querySelectorAll('[data-monster-role="switch"]')[0].classList.contains(toggleSwitch.getOption('classes.off')); + expect(hasClassC).is.true; + + + done(); + }, 0); + + }) + + }); + + describe('describe value', function () { + + beforeEach(() => { + let mocks = document.getElementById('mocks'); + mocks.innerHTML = html1; + }); + + afterEach(() => { + let mocks = document.getElementById('mocks'); + mocks.innerHTML = ""; + + }) + + it('the default value is off', function () { + + /** + * new Control + */ + let toggleSwitch = document.createElement('monster-toggle-switch'); + + /** + * the switch is off and provides the value for off + */ + expect(toggleSwitch.value).is.equal('off'); + + /** + * the switch is off + */ + expect(toggleSwitch.state).is.equal('off'); + + }); + + it('incorrect values are not accepted', function () { + + let toggleSwitch = document.createElement('monster-toggle-switch'); + + /** + * define the values for on and off + */ + toggleSwitch.setOption('values.on', 'true'); + toggleSwitch.setOption('values.off', 'false'); + + /** + * This value is not "true" and not "false" + */ + toggleSwitch.value = "test"; + + /** + * the switch is off and provides the value for off + */ + expect(toggleSwitch.value).is.equal('false'); + + /** + * the switch is off + */ + expect(toggleSwitch.state).is.equal('off'); + + /** + * disabled attribute is only set when the element has been mounted in the DOM + */ + expect(toggleSwitch.hasAttribute('disabled')).is.false; + + /** + * insert DOM + */ + document.getElementById('mocks').appendChild(toggleSwitch); + + /** + * now the element is disabled + */ + expect(toggleSwitch.hasAttribute('disabled')).is.true; + + + }); + + it('correct values are accepted', function () { + + const toggleSwitch = document.createElement('monster-toggle-switch'); + + /** + * define the values for on and off + */ + toggleSwitch.setOption('values.on', 'true'); + toggleSwitch.setOption('values.off', 'false'); + + /** + * This value is correct + */ + toggleSwitch.value = "true"; + + /** + * the switch is on and provides the value for on + */ + expect(toggleSwitch.value).is.equal('true'); + + /** + * the switch is on + */ + expect(toggleSwitch.state).is.equal('on'); + + /** + * insert DOM + */ + document.getElementById('mocks').appendChild(toggleSwitch); + + /** + * disabled attribute is not set + */ + expect(toggleSwitch.hasAttribute('disabled')).is.false; + + }); + + }); + + + +}); \ No newline at end of file