/* * Copyright 2021, GFXFundamentals. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of GFXFundamentals. nor the names of his * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ (function(root, factory) { // eslint-disable-line if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. define([], function() { return factory.call(root); }); } else { // Browser globals root.webglLessonsUI = factory.call(root); } }(this, function() { 'use strict'; const gopt = getQueryParams(); function setupSlider(selector, options) { var parent = document.querySelector(selector); if (!parent) { // like jquery don't fail on a bad selector return; } if (!options.name) { options.name = selector.substring(1); } return createSlider(parent, options); // eslint-disable-line } function createSlider(parent, options) { var precision = options.precision || 0; var min = options.min || 0; var step = options.step || 1; var value = options.value || 0; var max = options.max || 1; var fn = options.slide; var name = gopt["ui-" + options.name] || options.name; var uiPrecision = options.uiPrecision === undefined ? precision : options.uiPrecision; var uiMult = options.uiMult || 1; min /= step; max /= step; value /= step; parent.innerHTML = `
`; var valueElem = parent.querySelector(".gman-widget-value"); var sliderElem = parent.querySelector(".gman-widget-slider"); function updateValue(value) { valueElem.textContent = (value * step * uiMult).toFixed(uiPrecision); } updateValue(value); function handleChange(event) { var value = parseInt(event.target.value); updateValue(value); fn(event, { value: value * step }); } sliderElem.addEventListener('input', handleChange); sliderElem.addEventListener('change', handleChange); return { elem: parent, updateValue: (v) => { v /= step; sliderElem.value = v; updateValue(v); }, }; } function makeSlider(options) { const div = document.createElement("div"); return createSlider(div, options); } var widgetId = 0; function getWidgetId() { return "__widget_" + widgetId++; } function makeCheckbox(options) { const div = document.createElement("div"); div.className = "gman-widget-outer"; const label = document.createElement("label"); const id = getWidgetId(); label.setAttribute('for', id); label.textContent = gopt["ui-" + options.name] || options.name; label.className = "gman-checkbox-label"; const input = document.createElement("input"); input.type = "checkbox"; input.checked = options.value; input.id = id; input.className = "gman-widget-checkbox"; div.appendChild(label); div.appendChild(input); input.addEventListener('change', function(e) { options.change(e, { value: e.target.checked, }); }); return { elem: div, updateValue: function(v) { input.checked = !!v; }, }; } function makeOption(options) { const div = document.createElement("div"); div.className = "gman-widget-outer"; const label = document.createElement("label"); const id = getWidgetId(); label.setAttribute('for', id); label.textContent = gopt["ui-" + options.name] || options.name; label.className = "gman-widget-label"; const selectElem = document.createElement("select"); options.options.forEach((name, ndx) => { const opt = document.createElement("option"); opt.textContent = gopt["ui-" + name] || name; opt.value = ndx; opt.selected = ndx === options.value; selectElem.appendChild(opt); }); selectElem.className = "gman-widget-select"; div.appendChild(label); div.appendChild(selectElem); selectElem.addEventListener('change', function(e) { options.change(e, { value: selectElem.selectedIndex, }); }); return { elem: div, updateValue: function(v) { selectElem.selectedIndex = v; }, }; } function noop() { } function genSlider(object, ui) { const changeFn = ui.change || noop; ui.name = ui.name || ui.key; ui.value = object[ui.key]; ui.slide = ui.slide || function(event, uiInfo) { object[ui.key] = uiInfo.value; changeFn(); }; return makeSlider(ui); } function genCheckbox(object, ui) { const changeFn = ui.change || noop; ui.value = object[ui.key]; ui.name = ui.name || ui.key; ui.change = function(event, uiInfo) { object[ui.key] = uiInfo.value; changeFn(); }; return makeCheckbox(ui); } function genOption(object, ui) { const changeFn = ui.change || noop; ui.value = object[ui.key]; ui.name = ui.name || ui.key; ui.change = function(event, uiInfo) { object[ui.key] = uiInfo.value; changeFn(); }; return makeOption(ui); } const uiFuncs = { slider: genSlider, checkbox: genCheckbox, option: genOption, }; function setupUI(parent, object, uiInfos) { const widgets = {}; uiInfos.forEach(function(ui) { const widget = uiFuncs[ui.type](object, ui); parent.appendChild(widget.elem); widgets[ui.key] = widget; }); return widgets; } function updateUI(widgets, data) { Object.keys(widgets).forEach(key => { const widget = widgets[key]; widget.updateValue(data[key]); }); } function getQueryParams() { var params = {}; if (window.hackedParams) { Object.keys(window.hackedParams).forEach(function(key) { params[key] = window.hackedParams[key]; }); } if (window.location.search) { window.location.search.substring(1).split("&").forEach(function(pair) { var keyValue = pair.split("=").map(function(kv) { return decodeURIComponent(kv); }); params[keyValue[0]] = keyValue[1]; }); } return params; } return { setupUI: setupUI, updateUI: updateUI, setupSlider: setupSlider, makeSlider: makeSlider, makeCheckbox: makeCheckbox, }; }));