Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...






const container = document.querySelector("#inputContainer");
if (null != container) {
const countryList = [
{
country : "Austria",
continent: "Europe",
},
/* more country objects */
];
const structureDetail = {
value : "",
placeholder: "Choose a country",
label : "Country",
name : "country",
};
const structureMaster = {
elementList : countryList,
sectionElement: { continent: "All" },
focusObject : {},
};
const detailController = ChoiceDetailController(structureDetail);
const masterController = ChoiceMasterController("continent", "country")(structureMaster);
const view = projectChoiceInput(detailController, masterController, "countryInput");
container.append(...view);
}selectedselectedautocompleteautofocussizeselect-Attribute – ausser der size. Die meisten Mobile-Browser supporten die Grösse nicht.minlengthpatternsizenumberpatternurltelemailsizedatetimedatetime-localurltelemailpasswordemail immer sichtbar, oder bei tel sind die Zahlen besser dargestellt
[9] pattern
[11] blinkender Strich in einem Eingabefeld<option value="dog" > Dog </option>
<option label="Cat" selected> cat </option>
<option disabled> Mouse </option><select name="animal" disabled>
<option value="dog" > Dog </option>
<option value="cat" > Cat </option>
<option value="mouse"> Mouse </option>
</select><select name="animal">
<optgroup label="Big animal">
<option value="dog"> Dog </option>
<option value="cat"> Cat </option>
</optgroup>
<optgroup label="Small animal" disabled>
<option value="mouse". > Mouse </option>
<option value="hamster"> Hamster </option>
</optgroup>
</select><input type="text" name="animal"
list="data" placeholder="Animal" />
<datalist id="data">
<option> Dog </option>
<option> Cat </option>
<option> Mouse </option>
</datalist>









@import "../../../css/kolibri-base.css";
@import "../../../css/kolibri-light-colors.css";/* animation */
@keyframes open {
0% { transform: scaleY(0); }
100% { transform: scaleY(1); }
}
/* popover closed */
[popover] {
display: none;
animation: open 300ms ease-in-out;
transform-origin: top center;
}
@starting-style {
[popover]:popover-open {
height: 0;
}
}
/* popover opened */
[popover]:popover-open {
display: flex;
height: fit-content;
}optionsContainer.addEventListener("toggle", (event) => {
if (event.newState === "open") {
optionsContainer.classList.toggle("opened", true);
selectController.setOptionsVisibility(true);
} else {
optionsContainer.classList.toggle("opened", false);
selectController.setOptionsVisibility(false);
}
// more code to update scrollbars in columns
});.cursor-position::before {
content: '';
position: absolute;
left: 7px;
top: 0.5em;
bottom: 0.4em;
transform: translateX(-50%);
background: var(--kb-hsla-warning-dark);
border-radius: 1px;
width: 2px;
}const selectOptionItem = (root) => (newOption, oldOption) => {
const oldItem = getHtmlElementByOption(oldOption, root);
if (oldItem) {
oldItem.classList.remove("selected");
}
const newItem = getHtmlElementByOption(newOption, root);
if (newItem) {
newItem.classList.add("selected");
}
}; 





<div popover="auto"
id="select-component-0-options"
class="options-component"
> <!-- content --> </div>try {
/* code block with
`popoverContainer.showPopover();`
or `popoverContainer.hidePopover();`
*/
} catch (e) {
/* inform user about unsupported popover
the first time an alert popup appears */
}










/** @private @returns { OptionType } */
const reset = () => {
return Option(null, null);
};
/** @public @type { OptionType } */
const nullOption = reset();const SelectComponentByTableValues = (
selectAttributes,
optionsTable,
sortColumnOptionsAlphabetical = false
) => {
/* code for mapping between table and callbacks */
const component = SelectComponentByCallbacks(selectAttributes, callbacks);
return {
...component,
};
};




































const addAllOptions = (options) => {
const placeHolder = createHolder();
columnView.replaceWith(placeHolder);
if (options.length > 50) {
// same work as else but async
} else {
options.forEach((option) => {
optionsController.addOption(option);
});
updateScrollbar(columnView);
placeHolder.replaceWith(columnView);
}
};inputElement.setAttribute(
"style", "all: unset !important; " +
"z-index: -1 !important; " +
"position: absolute !important; " +
"inset: 5px !important; " +
"color: transparent !important; " +
"pointer-events: none !important; "
);




































































import { SelectComponent, pageCss } from "https://fhnw-ramonamarti.github.io/Kolibri/src/examples/select-new/selectComponent.js";
import * as Service from "./dataService.js";
// load styles for new component
const style = document.createElement("style");
style.textContent = pageCss;
document.querySelector("head").append(style);
/**
* helper to replace elements to form
* @param {*} id - id of the html element to place the projected elements in
* @param {*} labelElement - new label to relape in the form
* @param {*} inputElement - new input element to relape in the form
* @example
addSelectViewToUi("task1", lunchLabelElement, lunchInputElement);
*/
const addSelectViewToUi = (id, labelElement, inputElement) => {
const inputContainer = document.getElementById(id);
const labelContainer = document.getElementById(id + "-label");
labelContainer.replaceWith(labelElement);
inputContainer.replaceWith(inputElement);
}
// NOTE: You can read about our project in README.md file.
// Please follow the TODO's for the five tasks.
// The tasks are structured in the UI as follows:
// 1. Demo container with the usage of an existing way to create a selection input.
// 2. Task container with TODO's placeholder is positioned in the form
// where the new componenent should be fit in.
// ----- TASK 1 ----------
/*
TODO: Create a selection input using our new component.
The label should be 'Lunch' and the name 'lunch'.
The resulting component should provide 1 column with the data.
The data is provided by the function `Service.getLunchTypes()`
and can be used to fulfill the task.
To add the created view elements to the form you can use
the function `addSelectViewToUi` from the top.
The id of the container to fill the view elements in is 'task1-lunch'.
*/
// TODO: SOLUTION TASK 1 HERE
// ----- TASK 2 ----------
// ----- TASK 2.1 --------
/*
TODO: Create a selection input using our new component.
The label should be 'Home region' and the name 'home-region'.
The resulting component should provide 2 column with the value data and categories.
The value data is provided by the function `Service.getRegionsByCountryChDeAt()`,
the categories are provided by the function `Service.getCountriesChDeAt()`
and they can be used to fulfill the task.
To add the created view elements to the form you can use
the function `addSelectViewToUi` from the top.
The id of the container to fill the data view elements is 'task2-home-region'.
*/
// TODO: SOLUTION TASK 2.1 HERE
// ----- TASK 2.2 --------
/*
TODO: Create a selection input using our new component.
The label should be 'Birth region' and the name 'birth-region'.
The resulting component should provide 2 column with the value data and categories.
The value data is provided by the function `Service.getRegionsByCountry()`,
the categories are provided by the function `Service.getCountries()`
and they can be used to fulfill the task.
To add the created view elements to the form you can use
the function `addSelectViewToUi` from the top.
The id of the container to fill the data view elements is 'task2-birth-region'.
*/
// TODO: SOLUTION TASK 2.2 HERE
// ----- TASK 2.3 --------
/*
TODO: Create a selection input using our new component.
The label should be 'Birth year' and the name 'birth-year'.
The resulting component should provide 2 column with the value data and categories.
The value data is provided by the function `Service.getYearsByDecade()`,
the categories are provided by the function `Service.getDecades()`
and they can be used to fulfill the task.
To add the created view elements to the form you can use
the function `addSelectViewToUi` from the top.
The id of the container to fill the data view elements is 'task2-birth-year'.
*/
// TODO: SOLUTION TASK 2.3 HERE
// ------------------------
// Please fill out the question form to give us feedback about how the tasks worked.
// Please send your solution as a zip back to Ramona Marti on MS Teams.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Auswahlkomponente User Test</title>
<link
rel="shortcut icon"
type="image/png"
href="https://fhnw-ramonamarti.github.io/Kolibri/img/logo/logo-60x54.png"
/>
<link
rel="stylesheet"
href="https://fhnw-ramonamarti.github.io/Kolibri/css/kolibri-base.css"
/>
<style>
.newComponent {
color: red;
font-weight: bold;
}
label {
display: flex;
align-items: center;
}
select,
input {
border: #ccc solid 1px;
font-size: 1rem;
height: 2rem;
border-radius: 4px;
}
.task .select-input-component {
width: 320px;
}
</style>
</head>
<body>
<div class="demo" id="demo1"></div>
<div class="task" id="task1"></div>
<div class="demo" id="demo2"></div>
<div class="task" id="task2"></div>
<div class="demo" id="demo3"></div>
<div class="task" id="task3"></div>
<script type="module" src="starter.js"></script>
<script type="module" src="userTesting.js"></script>
</body>
</html>
import { projectForm, FORM_CSS } from "https://fhnw-ramonamarti.github.io/Kolibri/src/kolibri/projector/simpleForm/simpleFormProjector.js"
import { SimpleFormController } from "https://fhnw-ramonamarti.github.io/Kolibri/src/kolibri/projector/simpleForm/simpleFormController.js"
import { TEXT, CHOICE, COMBOBOX } from "https://fhnw-ramonamarti.github.io/Kolibri/src/kolibri/util/dom.js";
import * as Service from "./dataService.js";
// load style
const style = document.createElement("style");
style.textContent = FORM_CSS;
document.querySelector("head").append(style);
// prepare filling container
const fillContainer = (id, title, buildForm) => {
const formHolder = document.getElementById(id);
if (null != formHolder) {
const [fieldset] = buildForm();
formHolder.innerHTML = `<h3>${title}</h3>`;
formHolder.append(fieldset);
}
};
// prepare containes to do the tasks in
const replaceField = (id, name) => {
const inputElement = document.getElementById(id).querySelector(`[name=${name}]`);
const inputId = inputElement.id;
const fieldset = inputElement.closest("fieldset")
const labelElement = fieldset.querySelector(`[for="${inputId}"]`);
const spanElement = fieldset.querySelector(`span[data-id="${inputId}"]`);
const containerLabel = document.createElement("span");
containerLabel.id = id + "-" + name + "-label";
const container = document.createElement("span");
container.id = id + "-" + name;
container.textContent = "TODO";
container.classList.add("newComponent");
spanElement.replaceWith(container);
labelElement.replaceWith(containerLabel);
return [containerLabel, container];
};
// ----- DEMO 1 --------
const demo1 = () => {
/** @type { Array<OptionType> } */
const types = Service.getLunchTypes().map((types) => ({ value: types }));
const formStructure = [
{ value: "", label: "Name", name: "name", type: TEXT },
{ value: "", label: "Lunch", name: "lunch", type: COMBOBOX, list: types },
];
const controller = SimpleFormController(formStructure);
return projectForm(controller);
};
fillContainer("demo1", "Demo 1 - Short datalist", demo1);
// ----- TASK 1 --------
const task1 = () => {
const formStructure = [
{ value: "", label: "Name", name: "name", type: TEXT },
{ value: "", label: "Lunch", name: "lunch", type: "hidden" },
];
const controller = SimpleFormController(formStructure);
return projectForm(controller);
};
fillContainer("task1", "Task 1 - 1 column layout", task1);
replaceField("task1", "lunch");
// ----- DEMO --------
const demo2 = () => {
/** @type { Array<OptionType> } */
const years = Service.getYearsByDecade().map((year) => ({ value: year }));
/** @type { Array<OptionType> } */
const filterRegionsChDeAt = (...countryCode) =>
Service.getRegionsByCountryChDeAt(...countryCode).map((region) => ({ value: region }));
/** @type { Array<OptionType> } */
const filterRegions = (...countryCode) =>
Service.getRegionsByCountry(...countryCode).map((region) => ({ value: region }));
const formStructure = [
{ value: "", label: "Name", name: "name", type: TEXT },
{
value: "Aargau",
label: "Home region",
name: "home-region",
type: CHOICE,
list: filterRegionsChDeAt(),
},
{
value: "",
label: "Birth region",
name: "birth-region",
type: CHOICE,
list: filterRegions(),
},
{ value: "", label: "Birth year", name: "birth-year", type: CHOICE, list: years },
];
const controller = SimpleFormController(formStructure);
return projectForm(controller);
};
fillContainer("demo2", "Demo 2 - Long selects", demo2);
// ----- TASK 2 --------
const task2 = () => {
const formStructure = [
{ value: "", label: "Name", name: "name", type: TEXT },
{ value: "", label: "Home region", name: "home-region", type: "hidden" },
{ value: "", label: "Birth region", name: "birth-region", type: "hidden" },
{ value: "", label: "Birth year", name: "birth-year", type: "hidden" },
];
const controller = SimpleFormController(formStructure);
return projectForm(controller);
};
fillContainer("task2", "Task 2 - 2 column layout", task2);
replaceField("task2", "home-region");
replaceField("task2", "birth-region");
replaceField("task2", "birth-year");
export {
getAllContinents,
getCountries,
getCountriesChDeAt,
getRegionsByCountry,
getRegionsByCountryChDeAt,
getYearsByDecade,
getDecades,
getLunchTypes,
};
/** @type { () => String } */
const getAllContinents = () => {allCountriesWithContinent.map((country) => country.continent);return [
...new Set(allCountriesWithContinent.map((country) => country.continent)),
]};
/** @type { (...String) => String } */
const getCountries = (...continents) =>
allCountriesWithContinent
.filter((e) => allRegionsWithCountry.map((c) => c.country).includes(e.country))
.filter((e) => continents.length === 0 || continents.includes(e.continent))
.map((country) => country.country);
/** @type { (...String) => String } */
const getRegionsByCountry = (...countries) =>
allRegionsWithCountry
.filter((e) => countries.length === 0 || countries.includes(e.country))
.map((region) => region.region).sort();
/** @type { () => String } */
const getCountriesChDeAt = () => ["Switzerland", "Germany", "Austria"];
/** @type { (...String) => String } */
const getRegionsByCountryChDeAt = (...countries) =>
allRegionsWithCountry
.filter(
(e) => countries.length === 0 && ["CH", "DE", "AT"].includes(e.code) || countries.includes(e.country)
)
.map((region) => region.region).sort();
/** @type { (...String) => String } */
const getYearsByDecade = (...decades) => {
const decadeStarts = decades.map(decade => decade.slice(0, 3));
const data = [...Array(90).keys()].map((e) => e + 1930 + "");
return data.filter((e) => (e) => decadeStarts.length === 0 || decadeStarts.includes(e.slice(0, 3)));
};
/** @type { () => String } */
const getDecades = () => [...Array(9).keys()].map((e) => e * 10 + 1930 + "'s");
/** @type { () => String } */
const getLunchTypes = () => ["all", "vegetarian", "vegan", "flexetarian", "gluten-free", "lactose-free"];
/* data tables for 'allCountriesWithContinent' and 'allRegionsWithCountry' */
/* Link: https://github.com/fhnw-ramonamarti/fhnw-ramonamarti.github.io/blob/main/ip6/userTest/dataService_old.js */





