@forsakringskassan/devindex-menu 1.0.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.
- package/README.md +162 -0
- package/dist/Devindex.pageobject.d.ts +7 -0
- package/dist/cjs/menu.js +214 -0
- package/dist/cjs/pageobjects/pageobjects.js +39 -0
- package/dist/esm/menu.js +191 -0
- package/dist/esm/pageobjects/pageobjects.js +16 -0
- package/dist/pageobjects.d.ts +1 -0
- package/menu.d.ts +35 -0
- package/package.json +68 -0
- package/pageobjects.d.ts +1 -0
package/README.md
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# @forsakringskassan/devindex-menu
|
|
2
|
+
|
|
3
|
+
> npm install --save-dev @forsakringskassan/devindex-menu
|
|
4
|
+
|
|
5
|
+
Menu for development mode that can be used with advantage together with [fapimock-express](https://www.npmjs.com/package/@forsakringskassan/apimock-express).
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
The menu can be used in several types of applications. If you're using vue-cli, it can be used as follows:
|
|
10
|
+
|
|
11
|
+
```js
|
|
12
|
+
require("@forsakringskassan/devindex-menu")([
|
|
13
|
+
{
|
|
14
|
+
key: "slow-load",
|
|
15
|
+
title: "Delay",
|
|
16
|
+
reloadOnChange: true,
|
|
17
|
+
execOnChange: "aGlobalMethod",
|
|
18
|
+
options: [
|
|
19
|
+
{ title: "Normal loading", value: false },
|
|
20
|
+
{ title: "Slow loading", value: true },
|
|
21
|
+
],
|
|
22
|
+
},
|
|
23
|
+
]);
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
When execOnChange is set to a value, the global function with this name will be called on onChange of the dropdown list.
|
|
27
|
+
|
|
28
|
+
## API
|
|
29
|
+
|
|
30
|
+
```js
|
|
31
|
+
[
|
|
32
|
+
{
|
|
33
|
+
key: String,
|
|
34
|
+
title: String,
|
|
35
|
+
type: String (optional, default, "select")
|
|
36
|
+
description: String (optional),
|
|
37
|
+
reloadOnChange: Boolean (optional, default: true),
|
|
38
|
+
sessionStorage: Boolean (optional, default: false),
|
|
39
|
+
execOnChange: String (optional),
|
|
40
|
+
options: [], Array (see types below)
|
|
41
|
+
},
|
|
42
|
+
]
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Use mocks directly
|
|
46
|
+
|
|
47
|
+
It's also possible to use mocks for `@forsakringskassan/apimock-express` directly.
|
|
48
|
+
In the types `MockMatcher` and `Mock` from `apimock-express` there is support for metadata that is read by the devindex-menu.
|
|
49
|
+
|
|
50
|
+
When defining the mock, add `meta.title` and `responses[i].response.label`.
|
|
51
|
+
These correspond to the dropdown label and the name of each option respectively.
|
|
52
|
+
|
|
53
|
+
```diff
|
|
54
|
+
export default defineMock({
|
|
55
|
+
+ meta: {
|
|
56
|
+
+ title: "GET /dog",
|
|
57
|
+
+ },
|
|
58
|
+
responses: [
|
|
59
|
+
createResponseByCookie(
|
|
60
|
+
cookie,
|
|
61
|
+
"border-collie-200",
|
|
62
|
+
{
|
|
63
|
+
+ label: "Border collie (200)",
|
|
64
|
+
body: dogBorderCollie,
|
|
65
|
+
},
|
|
66
|
+
),
|
|
67
|
+
],
|
|
68
|
+
defaultResponse: {
|
|
69
|
+
+ label: "Default – dachshund (200)",
|
|
70
|
+
status: 200,
|
|
71
|
+
body: dogDachshund,
|
|
72
|
+
},
|
|
73
|
+
);
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Inside the application, the mock is then sent directly to `devindexMenu`.
|
|
77
|
+
|
|
78
|
+
```diff
|
|
79
|
+
import devindexMenu from "@forsakringskassan/devindex-menu";
|
|
80
|
+
+import getDogMock from "dog-api/dist/api/private/v1/dog_get.js";
|
|
81
|
+
|
|
82
|
+
devindexMenu([
|
|
83
|
+
{
|
|
84
|
+
key: "api-post-leash",
|
|
85
|
+
title: "POST /leash",
|
|
86
|
+
options: [{
|
|
87
|
+
title: "Tracking leash (200)",
|
|
88
|
+
value: "tracking-leash-200"
|
|
89
|
+
}],
|
|
90
|
+
},
|
|
91
|
+
+ getDogMock,
|
|
92
|
+
]);
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Type Definitions
|
|
96
|
+
|
|
97
|
+
#### select (default)
|
|
98
|
+
|
|
99
|
+
```json
|
|
100
|
+
{ title: String, value: String },
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
#### Links
|
|
104
|
+
|
|
105
|
+
```json
|
|
106
|
+
{ title: String, href: String },
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
#### SessionStorage - Pre-filling
|
|
111
|
+
|
|
112
|
+
If you specify `sessionStorage` as `true`, the value will be saved under `key` in `sessionStorage`.
|
|
113
|
+
|
|
114
|
+
In the example below, you'll get a `select` with the title `Pre-filling`. If you make a selection, `sessionStorage` will get a value `fk-dog-model`.
|
|
115
|
+
|
|
116
|
+
```js
|
|
117
|
+
import coco from "./tests/mock/prefilled/coco.json";
|
|
118
|
+
import fido from "./tests/mock/prefilled/fido.json";
|
|
119
|
+
|
|
120
|
+
require("@forsakringskassan/devindex-menu")([
|
|
121
|
+
{
|
|
122
|
+
key: "fk-dog-model",
|
|
123
|
+
title: "Pre-filling",
|
|
124
|
+
sessionStorage: true,
|
|
125
|
+
options: [
|
|
126
|
+
{ title: "None", value: "" },
|
|
127
|
+
{ title: "Coco", value: coco },
|
|
128
|
+
{ title: "Fido", value: fido },
|
|
129
|
+
],
|
|
130
|
+
},
|
|
131
|
+
]);
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Examples
|
|
135
|
+
|
|
136
|
+
```js
|
|
137
|
+
require("@forsakringskassan/devindex-menu")([
|
|
138
|
+
{
|
|
139
|
+
key: "disable-translate",
|
|
140
|
+
title: "Text",
|
|
141
|
+
options: [
|
|
142
|
+
{ title: "Translated text", value: "default" },
|
|
143
|
+
{ title: "Show text keys", value: "true" },
|
|
144
|
+
],
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
type: "links",
|
|
148
|
+
title: "Links",
|
|
149
|
+
options: [
|
|
150
|
+
{
|
|
151
|
+
title: "Applicant reviews application for additional cost",
|
|
152
|
+
href: "/#/review/8",
|
|
153
|
+
},
|
|
154
|
+
],
|
|
155
|
+
},
|
|
156
|
+
]);
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Development
|
|
160
|
+
|
|
161
|
+
To compile styling:
|
|
162
|
+
`npm run build`
|
package/dist/cjs/menu.js
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/menu.js
|
|
21
|
+
var menu_exports = {};
|
|
22
|
+
__export(menu_exports, {
|
|
23
|
+
default: () => menu_default
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(menu_exports);
|
|
26
|
+
|
|
27
|
+
// raw-loader:./client.js?raw
|
|
28
|
+
var client_default = '/**\n * @param {string} cookieName\n * @param {string} cookieValue\n * @param {number} exdays\n * @returns {void}\n */\nfunction setCookie(cookieName, cookieValue, exdays) {\n var d = new Date();\n d.setTime(d.getTime() + exdays * 24 * 60 * 60 * 1000);\n var expires = "expires=".concat(d.toUTCString());\n document.cookie = "".concat(cookieName, "=").concat(cookieValue, ";").concat(expires, ";path=/");\n}\n\n/**\n * @param {string} cookieName\n * @returns {string | undefined}\n */\nfunction getCookie(cookieName) {\n var name = "".concat(cookieName, "=");\n var decodedCookie = decodeURIComponent(document.cookie);\n var ca = decodedCookie.split(";");\n for (var i = 0; i < ca.length; i++) {\n var c = ca[i];\n while (c.charAt(0) === " ") {\n c = c.substring(1);\n }\n if (c.indexOf(name) === 0) {\n return c.substring(name.length, c.length);\n }\n }\n return undefined;\n}\n(function () {\n /** @type {NodeListOf<HTMLSelectElement>} */\n var selections = document.querySelectorAll(".secret-menu select");\n for (var i = 0; i < selections.length; i++) {\n var select = selections[i];\n select.value = getCookie(select.name) ? getCookie(select.name) : "default";\n if (select.getAttribute("data-sessionStorage") === "true") {\n var cookieValue = getCookie(select.name);\n if (cookieValue) {\n sessionStorage.setItem(select.name, atob(cookieValue));\n }\n }\n select.onchange = function (event) {\n var element = event.target;\n setCookie(element.name, element.value, 30);\n if (element.getAttribute("data-exec-on-change")) {\n window[element.getAttribute("data-exec-on-change")]();\n }\n if (element.getAttribute("data-reload") === "true") {\n location.reload(true);\n }\n if (element.getAttribute("data-sessionStorage") === "true") {\n var sessionKey = element.id;\n if (element.value) {\n var value = atob(element.value);\n console.log("Laddar sessionstorage ".concat(sessionKey, " med \\n ").concat(value));\n sessionStorage.setItem(sessionKey, value);\n } else {\n console.log("T\\xF6mmer sessionstorage");\n sessionStorage.removeItem(sessionKey);\n }\n location.reload(true);\n }\n };\n }\n var inputFields = document.querySelectorAll(".secret-menu input");\n for (var _i = 0; _i < inputFields.length; _i++) {\n var input = inputFields[_i];\n input.value = getCookie(input.name) ? getCookie(input.name) : "";\n input.oninput = function (event) {\n var element = event.target;\n setCookie(element.name, element.value, 30);\n };\n }\n\n /* Forcerar att sidan laddas om, \xE4ven n\xE4r l\xE4nken \xE4r av typen: /#/granska/8 */\n /** @type {NodeListOf<HTMLAnchorElement>} */\n var links = document.querySelectorAll(".secret-menu ul li a");\n for (var _i2 = 0; _i2 < links.length; _i2++) {\n var link = links[_i2];\n if (link.getAttribute("href").startsWith("/#")) {\n /**\n * @param {MouseEvent} event\n */\n link.onclick = function (event) {\n event.preventDefault();\n window.location.href = event.target.getAttribute("href");\n setTimeout(function () {\n console.log("Reload after click on hash-link.");\n location.reload();\n }, "500");\n };\n }\n }\n})();\nfunction toggleMenu() {\n var menu = document.querySelector(".secret-menu");\n menu.classList.toggle("open");\n}\nwindow.toggleMenu = toggleMenu;';
|
|
29
|
+
|
|
30
|
+
// src/style.scss
|
|
31
|
+
var style_default = `.secret-menu {
|
|
32
|
+
min-height: 100%;
|
|
33
|
+
background-color: #333;
|
|
34
|
+
top: 0;
|
|
35
|
+
left: 0;
|
|
36
|
+
bottom: 0;
|
|
37
|
+
width: 0;
|
|
38
|
+
z-index: 9999;
|
|
39
|
+
color: #efefef;
|
|
40
|
+
position: fixed;
|
|
41
|
+
}
|
|
42
|
+
.secret-menu .toggle {
|
|
43
|
+
border: 0;
|
|
44
|
+
position: fixed;
|
|
45
|
+
top: 20px;
|
|
46
|
+
left: 0px;
|
|
47
|
+
color: #fff;
|
|
48
|
+
background-color: #333;
|
|
49
|
+
border-radius: 0;
|
|
50
|
+
border-top-right-radius: 5px;
|
|
51
|
+
border-bottom-right-radius: 5px;
|
|
52
|
+
font-weight: bold;
|
|
53
|
+
z-index: 9999;
|
|
54
|
+
margin: 0;
|
|
55
|
+
padding: 10px;
|
|
56
|
+
box-shadow: none;
|
|
57
|
+
min-width: 40px;
|
|
58
|
+
}
|
|
59
|
+
.secret-menu .toggle span {
|
|
60
|
+
width: 20px;
|
|
61
|
+
height: 3px;
|
|
62
|
+
background-color: white;
|
|
63
|
+
margin: 3px 0;
|
|
64
|
+
display: block;
|
|
65
|
+
}
|
|
66
|
+
.secret-menu .menu {
|
|
67
|
+
width: 100%;
|
|
68
|
+
overflow: hidden;
|
|
69
|
+
}
|
|
70
|
+
.secret-menu.open {
|
|
71
|
+
width: 300px;
|
|
72
|
+
overflow: auto;
|
|
73
|
+
}
|
|
74
|
+
.secret-menu.open .toggle {
|
|
75
|
+
left: 300px;
|
|
76
|
+
}
|
|
77
|
+
.secret-menu.open .menu {
|
|
78
|
+
padding: 20px;
|
|
79
|
+
box-sizing: border-box;
|
|
80
|
+
}
|
|
81
|
+
.secret-menu label {
|
|
82
|
+
margin-bottom: 0.25rem;
|
|
83
|
+
}
|
|
84
|
+
.secret-menu label,
|
|
85
|
+
.secret-menu a {
|
|
86
|
+
color: #efefef;
|
|
87
|
+
display: block;
|
|
88
|
+
}
|
|
89
|
+
.secret-menu a:hover {
|
|
90
|
+
text-decoration: underline;
|
|
91
|
+
}
|
|
92
|
+
.secret-menu .sr-only {
|
|
93
|
+
position: absolute;
|
|
94
|
+
width: 1px;
|
|
95
|
+
height: 1px;
|
|
96
|
+
margin: -1px;
|
|
97
|
+
padding: 0;
|
|
98
|
+
overflow: hidden;
|
|
99
|
+
clip: rect(0, 0, 0, 0);
|
|
100
|
+
border: 0;
|
|
101
|
+
}
|
|
102
|
+
.secret-menu select {
|
|
103
|
+
color: #000;
|
|
104
|
+
margin-bottom: 1rem;
|
|
105
|
+
width: 100%;
|
|
106
|
+
height: 2.25rem;
|
|
107
|
+
font-size: 0.875rem;
|
|
108
|
+
}
|
|
109
|
+
.secret-menu input {
|
|
110
|
+
color: #000;
|
|
111
|
+
margin-bottom: 1rem;
|
|
112
|
+
width: 100%;
|
|
113
|
+
}`;
|
|
114
|
+
|
|
115
|
+
// src/menu.js
|
|
116
|
+
function generateOptionMarkupForSelect(setting) {
|
|
117
|
+
const reload = setting.reloadOnChange !== void 0 ? setting.reloadOnChange : true;
|
|
118
|
+
const description = setting.description ? `<p>${setting.description}</p>` : "";
|
|
119
|
+
const execOnChange = setting.execOnChange ? ` data-exec-on-change="${setting.execOnChange}"` : "";
|
|
120
|
+
let markup = `<label for="${setting.key}" class="label">${setting.title}</label>${description}<select id="${setting.key}" data-sessionStorage="${setting.sessionStorage}" data-reload="${reload}" ${execOnChange} name="${setting.key}" tabindex="-1">`;
|
|
121
|
+
setting.options.forEach((option) => {
|
|
122
|
+
const stateJson = typeof option.value === "string" ? option.value : JSON.stringify(option.value, null, 2);
|
|
123
|
+
const optionValue = setting.sessionStorage ? btoa(stateJson) : option.value;
|
|
124
|
+
markup += `<option value="${optionValue}">${option.title}</option>`;
|
|
125
|
+
});
|
|
126
|
+
markup = `${markup}</select>`;
|
|
127
|
+
return markup;
|
|
128
|
+
}
|
|
129
|
+
function generateOptionMarkupForLink(setting) {
|
|
130
|
+
const description = setting.description ? `<p>${setting.description}</p>` : "";
|
|
131
|
+
let markup = `${setting.title} ${description}<ul>`;
|
|
132
|
+
setting.options.forEach((option) => {
|
|
133
|
+
markup += `<li><a href="${option.href}">${option.title}</a></li>`;
|
|
134
|
+
});
|
|
135
|
+
markup = `${markup}</ul>`;
|
|
136
|
+
return markup;
|
|
137
|
+
}
|
|
138
|
+
function generateOptionMarkupForTextInput(setting) {
|
|
139
|
+
const description = setting.description ? `<p>${setting.description}</p>` : "";
|
|
140
|
+
return `${setting.title} ${description} <br /> <input name="${setting.key}" type="text"></input>`;
|
|
141
|
+
}
|
|
142
|
+
function generateOptionMarkup(setting) {
|
|
143
|
+
switch (setting.type) {
|
|
144
|
+
case "select":
|
|
145
|
+
return generateOptionMarkupForSelect(setting);
|
|
146
|
+
case "links":
|
|
147
|
+
return generateOptionMarkupForLink(setting);
|
|
148
|
+
case "text":
|
|
149
|
+
return generateOptionMarkupForTextInput(setting);
|
|
150
|
+
}
|
|
151
|
+
return "";
|
|
152
|
+
}
|
|
153
|
+
function isMock(userSettingsOrMock) {
|
|
154
|
+
return "responses" in userSettingsOrMock || "defaultResponse" in userSettingsOrMock;
|
|
155
|
+
}
|
|
156
|
+
function getFirstCookie(matcher) {
|
|
157
|
+
const entries = Object.entries(matcher.request.cookies);
|
|
158
|
+
const [key, value] = entries[0];
|
|
159
|
+
return { key, value };
|
|
160
|
+
}
|
|
161
|
+
function entryFromMock(mock) {
|
|
162
|
+
const { key } = getFirstCookie(mock.responses[0]);
|
|
163
|
+
const title = mock.meta.title ?? key;
|
|
164
|
+
const defaultEntry = {
|
|
165
|
+
title: mock.defaultResponse?.label ?? "Default",
|
|
166
|
+
value: "default"
|
|
167
|
+
};
|
|
168
|
+
return {
|
|
169
|
+
type: "select",
|
|
170
|
+
key,
|
|
171
|
+
title,
|
|
172
|
+
options: [
|
|
173
|
+
defaultEntry,
|
|
174
|
+
...mock.responses.map((entry) => {
|
|
175
|
+
const { value } = getFirstCookie(entry);
|
|
176
|
+
return {
|
|
177
|
+
title: entry.response.label ?? value,
|
|
178
|
+
value
|
|
179
|
+
};
|
|
180
|
+
})
|
|
181
|
+
]
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
var defaultSetting = {
|
|
185
|
+
type: "select"
|
|
186
|
+
};
|
|
187
|
+
var menu_default = (userSettingsAndMocks) => {
|
|
188
|
+
let settingsMarkup = "";
|
|
189
|
+
userSettingsAndMocks.map(
|
|
190
|
+
(userSettingOrMock) => isMock(userSettingOrMock) ? entryFromMock(userSettingOrMock) : userSettingOrMock
|
|
191
|
+
).forEach((userSetting) => {
|
|
192
|
+
const setting = { ...defaultSetting, ...userSetting };
|
|
193
|
+
settingsMarkup = settingsMarkup + generateOptionMarkup(setting);
|
|
194
|
+
});
|
|
195
|
+
document.head.insertAdjacentHTML("beforeend", `<style>${style_default}</style>`);
|
|
196
|
+
document.body.insertAdjacentHTML(
|
|
197
|
+
"beforeend",
|
|
198
|
+
`
|
|
199
|
+
<div class="secret-menu" aria-hidden="true">
|
|
200
|
+
<button type="button" class="toggle" onclick="toggleMenu()">
|
|
201
|
+
<span></span>
|
|
202
|
+
<span></span>
|
|
203
|
+
<span></span>
|
|
204
|
+
<span class="sr-only">Hemlig meny</span>
|
|
205
|
+
</button>
|
|
206
|
+
<div class="menu">
|
|
207
|
+
${settingsMarkup}
|
|
208
|
+
</div>
|
|
209
|
+
</div>`
|
|
210
|
+
);
|
|
211
|
+
const script = document.createElement("script");
|
|
212
|
+
script.innerText = client_default;
|
|
213
|
+
document.body.appendChild(script);
|
|
214
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/pageobjects/pageobjects.ts
|
|
21
|
+
var pageobjects_exports = {};
|
|
22
|
+
__export(pageobjects_exports, {
|
|
23
|
+
DevindexPageObject: () => DevindexPageObject
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(pageobjects_exports);
|
|
26
|
+
|
|
27
|
+
// src/pageobjects/Devindex.pageobject.ts
|
|
28
|
+
var DevindexPageObject = class {
|
|
29
|
+
constructor() {
|
|
30
|
+
this.selector = ".secret-menu";
|
|
31
|
+
this.el = () => cy.get(this.selector);
|
|
32
|
+
}
|
|
33
|
+
toggleMenu() {
|
|
34
|
+
cy.get(".secret-menu > button").click();
|
|
35
|
+
}
|
|
36
|
+
valj(id, value) {
|
|
37
|
+
cy.get(`#${id}`).select(value);
|
|
38
|
+
}
|
|
39
|
+
};
|
package/dist/esm/menu.js
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
// raw-loader:./client.js?raw
|
|
2
|
+
var client_default = '/**\n * @param {string} cookieName\n * @param {string} cookieValue\n * @param {number} exdays\n * @returns {void}\n */\nfunction setCookie(cookieName, cookieValue, exdays) {\n var d = new Date();\n d.setTime(d.getTime() + exdays * 24 * 60 * 60 * 1000);\n var expires = "expires=".concat(d.toUTCString());\n document.cookie = "".concat(cookieName, "=").concat(cookieValue, ";").concat(expires, ";path=/");\n}\n\n/**\n * @param {string} cookieName\n * @returns {string | undefined}\n */\nfunction getCookie(cookieName) {\n var name = "".concat(cookieName, "=");\n var decodedCookie = decodeURIComponent(document.cookie);\n var ca = decodedCookie.split(";");\n for (var i = 0; i < ca.length; i++) {\n var c = ca[i];\n while (c.charAt(0) === " ") {\n c = c.substring(1);\n }\n if (c.indexOf(name) === 0) {\n return c.substring(name.length, c.length);\n }\n }\n return undefined;\n}\n(function () {\n /** @type {NodeListOf<HTMLSelectElement>} */\n var selections = document.querySelectorAll(".secret-menu select");\n for (var i = 0; i < selections.length; i++) {\n var select = selections[i];\n select.value = getCookie(select.name) ? getCookie(select.name) : "default";\n if (select.getAttribute("data-sessionStorage") === "true") {\n var cookieValue = getCookie(select.name);\n if (cookieValue) {\n sessionStorage.setItem(select.name, atob(cookieValue));\n }\n }\n select.onchange = function (event) {\n var element = event.target;\n setCookie(element.name, element.value, 30);\n if (element.getAttribute("data-exec-on-change")) {\n window[element.getAttribute("data-exec-on-change")]();\n }\n if (element.getAttribute("data-reload") === "true") {\n location.reload(true);\n }\n if (element.getAttribute("data-sessionStorage") === "true") {\n var sessionKey = element.id;\n if (element.value) {\n var value = atob(element.value);\n console.log("Laddar sessionstorage ".concat(sessionKey, " med \\n ").concat(value));\n sessionStorage.setItem(sessionKey, value);\n } else {\n console.log("T\\xF6mmer sessionstorage");\n sessionStorage.removeItem(sessionKey);\n }\n location.reload(true);\n }\n };\n }\n var inputFields = document.querySelectorAll(".secret-menu input");\n for (var _i = 0; _i < inputFields.length; _i++) {\n var input = inputFields[_i];\n input.value = getCookie(input.name) ? getCookie(input.name) : "";\n input.oninput = function (event) {\n var element = event.target;\n setCookie(element.name, element.value, 30);\n };\n }\n\n /* Forcerar att sidan laddas om, \xE4ven n\xE4r l\xE4nken \xE4r av typen: /#/granska/8 */\n /** @type {NodeListOf<HTMLAnchorElement>} */\n var links = document.querySelectorAll(".secret-menu ul li a");\n for (var _i2 = 0; _i2 < links.length; _i2++) {\n var link = links[_i2];\n if (link.getAttribute("href").startsWith("/#")) {\n /**\n * @param {MouseEvent} event\n */\n link.onclick = function (event) {\n event.preventDefault();\n window.location.href = event.target.getAttribute("href");\n setTimeout(function () {\n console.log("Reload after click on hash-link.");\n location.reload();\n }, "500");\n };\n }\n }\n})();\nfunction toggleMenu() {\n var menu = document.querySelector(".secret-menu");\n menu.classList.toggle("open");\n}\nwindow.toggleMenu = toggleMenu;';
|
|
3
|
+
|
|
4
|
+
// src/style.scss
|
|
5
|
+
var style_default = `.secret-menu {
|
|
6
|
+
min-height: 100%;
|
|
7
|
+
background-color: #333;
|
|
8
|
+
top: 0;
|
|
9
|
+
left: 0;
|
|
10
|
+
bottom: 0;
|
|
11
|
+
width: 0;
|
|
12
|
+
z-index: 9999;
|
|
13
|
+
color: #efefef;
|
|
14
|
+
position: fixed;
|
|
15
|
+
}
|
|
16
|
+
.secret-menu .toggle {
|
|
17
|
+
border: 0;
|
|
18
|
+
position: fixed;
|
|
19
|
+
top: 20px;
|
|
20
|
+
left: 0px;
|
|
21
|
+
color: #fff;
|
|
22
|
+
background-color: #333;
|
|
23
|
+
border-radius: 0;
|
|
24
|
+
border-top-right-radius: 5px;
|
|
25
|
+
border-bottom-right-radius: 5px;
|
|
26
|
+
font-weight: bold;
|
|
27
|
+
z-index: 9999;
|
|
28
|
+
margin: 0;
|
|
29
|
+
padding: 10px;
|
|
30
|
+
box-shadow: none;
|
|
31
|
+
min-width: 40px;
|
|
32
|
+
}
|
|
33
|
+
.secret-menu .toggle span {
|
|
34
|
+
width: 20px;
|
|
35
|
+
height: 3px;
|
|
36
|
+
background-color: white;
|
|
37
|
+
margin: 3px 0;
|
|
38
|
+
display: block;
|
|
39
|
+
}
|
|
40
|
+
.secret-menu .menu {
|
|
41
|
+
width: 100%;
|
|
42
|
+
overflow: hidden;
|
|
43
|
+
}
|
|
44
|
+
.secret-menu.open {
|
|
45
|
+
width: 300px;
|
|
46
|
+
overflow: auto;
|
|
47
|
+
}
|
|
48
|
+
.secret-menu.open .toggle {
|
|
49
|
+
left: 300px;
|
|
50
|
+
}
|
|
51
|
+
.secret-menu.open .menu {
|
|
52
|
+
padding: 20px;
|
|
53
|
+
box-sizing: border-box;
|
|
54
|
+
}
|
|
55
|
+
.secret-menu label {
|
|
56
|
+
margin-bottom: 0.25rem;
|
|
57
|
+
}
|
|
58
|
+
.secret-menu label,
|
|
59
|
+
.secret-menu a {
|
|
60
|
+
color: #efefef;
|
|
61
|
+
display: block;
|
|
62
|
+
}
|
|
63
|
+
.secret-menu a:hover {
|
|
64
|
+
text-decoration: underline;
|
|
65
|
+
}
|
|
66
|
+
.secret-menu .sr-only {
|
|
67
|
+
position: absolute;
|
|
68
|
+
width: 1px;
|
|
69
|
+
height: 1px;
|
|
70
|
+
margin: -1px;
|
|
71
|
+
padding: 0;
|
|
72
|
+
overflow: hidden;
|
|
73
|
+
clip: rect(0, 0, 0, 0);
|
|
74
|
+
border: 0;
|
|
75
|
+
}
|
|
76
|
+
.secret-menu select {
|
|
77
|
+
color: #000;
|
|
78
|
+
margin-bottom: 1rem;
|
|
79
|
+
width: 100%;
|
|
80
|
+
height: 2.25rem;
|
|
81
|
+
font-size: 0.875rem;
|
|
82
|
+
}
|
|
83
|
+
.secret-menu input {
|
|
84
|
+
color: #000;
|
|
85
|
+
margin-bottom: 1rem;
|
|
86
|
+
width: 100%;
|
|
87
|
+
}`;
|
|
88
|
+
|
|
89
|
+
// src/menu.js
|
|
90
|
+
function generateOptionMarkupForSelect(setting) {
|
|
91
|
+
const reload = setting.reloadOnChange !== void 0 ? setting.reloadOnChange : true;
|
|
92
|
+
const description = setting.description ? `<p>${setting.description}</p>` : "";
|
|
93
|
+
const execOnChange = setting.execOnChange ? ` data-exec-on-change="${setting.execOnChange}"` : "";
|
|
94
|
+
let markup = `<label for="${setting.key}" class="label">${setting.title}</label>${description}<select id="${setting.key}" data-sessionStorage="${setting.sessionStorage}" data-reload="${reload}" ${execOnChange} name="${setting.key}" tabindex="-1">`;
|
|
95
|
+
setting.options.forEach((option) => {
|
|
96
|
+
const stateJson = typeof option.value === "string" ? option.value : JSON.stringify(option.value, null, 2);
|
|
97
|
+
const optionValue = setting.sessionStorage ? btoa(stateJson) : option.value;
|
|
98
|
+
markup += `<option value="${optionValue}">${option.title}</option>`;
|
|
99
|
+
});
|
|
100
|
+
markup = `${markup}</select>`;
|
|
101
|
+
return markup;
|
|
102
|
+
}
|
|
103
|
+
function generateOptionMarkupForLink(setting) {
|
|
104
|
+
const description = setting.description ? `<p>${setting.description}</p>` : "";
|
|
105
|
+
let markup = `${setting.title} ${description}<ul>`;
|
|
106
|
+
setting.options.forEach((option) => {
|
|
107
|
+
markup += `<li><a href="${option.href}">${option.title}</a></li>`;
|
|
108
|
+
});
|
|
109
|
+
markup = `${markup}</ul>`;
|
|
110
|
+
return markup;
|
|
111
|
+
}
|
|
112
|
+
function generateOptionMarkupForTextInput(setting) {
|
|
113
|
+
const description = setting.description ? `<p>${setting.description}</p>` : "";
|
|
114
|
+
return `${setting.title} ${description} <br /> <input name="${setting.key}" type="text"></input>`;
|
|
115
|
+
}
|
|
116
|
+
function generateOptionMarkup(setting) {
|
|
117
|
+
switch (setting.type) {
|
|
118
|
+
case "select":
|
|
119
|
+
return generateOptionMarkupForSelect(setting);
|
|
120
|
+
case "links":
|
|
121
|
+
return generateOptionMarkupForLink(setting);
|
|
122
|
+
case "text":
|
|
123
|
+
return generateOptionMarkupForTextInput(setting);
|
|
124
|
+
}
|
|
125
|
+
return "";
|
|
126
|
+
}
|
|
127
|
+
function isMock(userSettingsOrMock) {
|
|
128
|
+
return "responses" in userSettingsOrMock || "defaultResponse" in userSettingsOrMock;
|
|
129
|
+
}
|
|
130
|
+
function getFirstCookie(matcher) {
|
|
131
|
+
const entries = Object.entries(matcher.request.cookies);
|
|
132
|
+
const [key, value] = entries[0];
|
|
133
|
+
return { key, value };
|
|
134
|
+
}
|
|
135
|
+
function entryFromMock(mock) {
|
|
136
|
+
const { key } = getFirstCookie(mock.responses[0]);
|
|
137
|
+
const title = mock.meta.title ?? key;
|
|
138
|
+
const defaultEntry = {
|
|
139
|
+
title: mock.defaultResponse?.label ?? "Default",
|
|
140
|
+
value: "default"
|
|
141
|
+
};
|
|
142
|
+
return {
|
|
143
|
+
type: "select",
|
|
144
|
+
key,
|
|
145
|
+
title,
|
|
146
|
+
options: [
|
|
147
|
+
defaultEntry,
|
|
148
|
+
...mock.responses.map((entry) => {
|
|
149
|
+
const { value } = getFirstCookie(entry);
|
|
150
|
+
return {
|
|
151
|
+
title: entry.response.label ?? value,
|
|
152
|
+
value
|
|
153
|
+
};
|
|
154
|
+
})
|
|
155
|
+
]
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
var defaultSetting = {
|
|
159
|
+
type: "select"
|
|
160
|
+
};
|
|
161
|
+
var menu_default = (userSettingsAndMocks) => {
|
|
162
|
+
let settingsMarkup = "";
|
|
163
|
+
userSettingsAndMocks.map(
|
|
164
|
+
(userSettingOrMock) => isMock(userSettingOrMock) ? entryFromMock(userSettingOrMock) : userSettingOrMock
|
|
165
|
+
).forEach((userSetting) => {
|
|
166
|
+
const setting = { ...defaultSetting, ...userSetting };
|
|
167
|
+
settingsMarkup = settingsMarkup + generateOptionMarkup(setting);
|
|
168
|
+
});
|
|
169
|
+
document.head.insertAdjacentHTML("beforeend", `<style>${style_default}</style>`);
|
|
170
|
+
document.body.insertAdjacentHTML(
|
|
171
|
+
"beforeend",
|
|
172
|
+
`
|
|
173
|
+
<div class="secret-menu" aria-hidden="true">
|
|
174
|
+
<button type="button" class="toggle" onclick="toggleMenu()">
|
|
175
|
+
<span></span>
|
|
176
|
+
<span></span>
|
|
177
|
+
<span></span>
|
|
178
|
+
<span class="sr-only">Hemlig meny</span>
|
|
179
|
+
</button>
|
|
180
|
+
<div class="menu">
|
|
181
|
+
${settingsMarkup}
|
|
182
|
+
</div>
|
|
183
|
+
</div>`
|
|
184
|
+
);
|
|
185
|
+
const script = document.createElement("script");
|
|
186
|
+
script.innerText = client_default;
|
|
187
|
+
document.body.appendChild(script);
|
|
188
|
+
};
|
|
189
|
+
export {
|
|
190
|
+
menu_default as default
|
|
191
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// src/pageobjects/Devindex.pageobject.ts
|
|
2
|
+
var DevindexPageObject = class {
|
|
3
|
+
constructor() {
|
|
4
|
+
this.selector = ".secret-menu";
|
|
5
|
+
this.el = () => cy.get(this.selector);
|
|
6
|
+
}
|
|
7
|
+
toggleMenu() {
|
|
8
|
+
cy.get(".secret-menu > button").click();
|
|
9
|
+
}
|
|
10
|
+
valj(id, value) {
|
|
11
|
+
cy.get(`#${id}`).select(value);
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
export {
|
|
15
|
+
DevindexPageObject
|
|
16
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./Devindex.pageobject";
|
package/menu.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type Mock } from "@forsakringskassan/apimock-express";
|
|
2
|
+
|
|
3
|
+
export interface SelectOption {
|
|
4
|
+
title: string;
|
|
5
|
+
value: unknown;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface SelectSettings {
|
|
9
|
+
type?: "select";
|
|
10
|
+
key: string;
|
|
11
|
+
title: string;
|
|
12
|
+
reloadOnChange?: boolean;
|
|
13
|
+
execOnChange?: string;
|
|
14
|
+
description?: string;
|
|
15
|
+
sessionStorage?: boolean;
|
|
16
|
+
options: SelectOption[];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface LinkOption {
|
|
20
|
+
title: string;
|
|
21
|
+
href: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface LinkSettings {
|
|
25
|
+
type: "links";
|
|
26
|
+
title: string;
|
|
27
|
+
description?: string;
|
|
28
|
+
options: LinkOption[];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export type Settings = SelectSettings | LinkSettings;
|
|
32
|
+
|
|
33
|
+
export default function devindexMenu(
|
|
34
|
+
userSettingsAndMocks: Array<Settings | Mock>,
|
|
35
|
+
): void;
|
package/package.json
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@forsakringskassan/devindex-menu",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"license": "ISC",
|
|
6
|
+
"author": "FK",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./menu.d.ts",
|
|
10
|
+
"require": "./dist/cjs/menu.js",
|
|
11
|
+
"import": "./dist/esm/menu.js"
|
|
12
|
+
},
|
|
13
|
+
"./pageobjects": {
|
|
14
|
+
"types": "./pageobjects.d.ts",
|
|
15
|
+
"require": "./dist/cjs/pageobjects/pageobjects.js",
|
|
16
|
+
"import": "./dist/esm/pageobjects/pageobjects.js"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"main": "dist/cjs/menu.js",
|
|
20
|
+
"module": "dist/esm/menu.js",
|
|
21
|
+
"types": "./menu.d.ts",
|
|
22
|
+
"files": [
|
|
23
|
+
"dist",
|
|
24
|
+
"pageobjects",
|
|
25
|
+
"./pageobjects.d.ts",
|
|
26
|
+
"./pageobjects.js",
|
|
27
|
+
"./menu.d.ts"
|
|
28
|
+
],
|
|
29
|
+
"scripts": {
|
|
30
|
+
"prebuild": "rimraf dist && tsc",
|
|
31
|
+
"build": "node generate.mjs",
|
|
32
|
+
"eslint": "eslint --cache .",
|
|
33
|
+
"prettier:check": "prettier --check .",
|
|
34
|
+
"prettier:write": "prettier --write .",
|
|
35
|
+
"test": "npm run prettier:check && npm run eslint"
|
|
36
|
+
},
|
|
37
|
+
"commitlint": {
|
|
38
|
+
"extends": "@forsakringskassan/commitlint-config/no-jira"
|
|
39
|
+
},
|
|
40
|
+
"prettier": "@forsakringskassan/prettier-config",
|
|
41
|
+
"release": {
|
|
42
|
+
"extends": "@forsakringskassan/semantic-release-config"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@babel/core": "7.28.4",
|
|
46
|
+
"@babel/preset-env": "7.28.3",
|
|
47
|
+
"@forsakringskassan/apimock-express": "2.9.0",
|
|
48
|
+
"@forsakringskassan/commitlint-config": "3.1.2",
|
|
49
|
+
"@forsakringskassan/eslint-config": "13.1.0",
|
|
50
|
+
"@forsakringskassan/eslint-config-cli": "13.1.0",
|
|
51
|
+
"@forsakringskassan/eslint-config-cypress": "13.1.0",
|
|
52
|
+
"@forsakringskassan/eslint-config-jest": "13.1.0",
|
|
53
|
+
"@forsakringskassan/eslint-config-typescript": "13.1.0",
|
|
54
|
+
"@forsakringskassan/eslint-config-typescript-typeinfo": "13.1.0",
|
|
55
|
+
"@forsakringskassan/prettier-config": "3.1.7",
|
|
56
|
+
"@tsconfig/node16": "16.1.5",
|
|
57
|
+
"@types/node": "16.18.126",
|
|
58
|
+
"cypress": "15.4.0",
|
|
59
|
+
"esbuild": "0.25.10",
|
|
60
|
+
"esbuild-sass-plugin": "3.3.1",
|
|
61
|
+
"rimraf": "6.0.1",
|
|
62
|
+
"sass": "1.93.2",
|
|
63
|
+
"typescript": "5.9.3"
|
|
64
|
+
},
|
|
65
|
+
"engines": {
|
|
66
|
+
"node": ">= 16"
|
|
67
|
+
}
|
|
68
|
+
}
|
package/pageobjects.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./dist/pageobjects";
|