VvebOIDC/public/js/vvvebjs/section.js

710 lines
18 KiB
JavaScript

/**
* Vvveb
*
* Copyright (C) 2021 Ziadin Givan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* https://github.com/givanz/Vvveb
*/
let bgVideoTemplate = '<video playsinline loop muted autoplay src="../../media/demo/sample.webm" poster="../../media/demo/sample.webp"><video>';
let bgImageTemplate = '<img src="../../media/demo/sample.webp">';
let defaultSeparatorSvg = '<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 41" width="100%" height="300" fill="var(--bs-body-bg)" preserveAspectRatio="none"><defs><style>.cls-1{fill:inherit}</style></defs><title>rough-edges-bottom</title><path class="cls-1" d="M0,185l125-26,33,17,58-12s54,19,55,19,50-11,50-11l56,6,60-8,63,15v15H0Z" transform="translate(0 -159)"/></svg>';
let section_sort = 1;
let SectionContent = [{
name: "Label",
key: "label",
sort: section_sort++,
htmlAttr: "aria-label",
inputtype: TextInput
},{
name: "Container width",
key: "container-width",
sort: section_sort++,
child:":scope > .container, :scope > .container-fluid",
htmlAttr: "class",
validValues: ["container", "container-fluid"],
inputtype: RadioButtonInput,
data: {
extraclass:"btn-group-sm btn-group-fullwidth",
options: [{
value: "container",
icon:"la la-box",
text: "Boxed",
title: "Boxed"
},{
value: "container-fluid",
icon:"la la-arrows-alt-h",
title: "Full",
text: "Full"
}]
}
},{
name: "Container height",
key: "container-height",
sort: section_sort++,
child:":scope > .container:first-child, :scope > .container-fluid:first-child",
htmlAttr: "class",
validValues: ["", "vh-100"],
inputtype: RadioButtonInput,
data: {
extraclass:"btn-group-sm btn-group-fullwidth",
options: [{
value: "container",
icon:"la la-expand",
text: "Auto",
title: "Auto",
checked:true,
},{
value: "vh-100",
icon:"la la-arrows-alt-v",
title: "Full",
text: "Full"
}]
}
}
];
let SectionBackground = [{
key: "section_background_header",
inputtype: SectionInput,
name:false,
sort: section_sort++,
//section: style_section,
data: {header:"Background"},
},{
name: false,
key: "section-bg",
sort: section_sort++,
inputtype: RadioButtonInput,
data: {
inline: true,
extraclass:"btn-group-sm btn-group-fullwidth",
options: [{
value: "none",
text: "None",
title: "None",
checked:true,
},{
value: "bg-image",
icon:"la la-image",
text: "Image",
title: "Image",
},{/*
value: "gradient",
icon:"la la-palette",
text: "Gradient",
title: "Gradient",
},{*/
value: "bg-video",
icon:"la la-video",
text: "Video",
title: "Video",/*
},{
value: "slideshow",
icon:"la la-arrows-alt-h",
text: "Slider",
title: "Slider",*/
}],
},
hideGroups : function() {
document.querySelectorAll('.mb-2[data-group="bg-image"],.mb-2[data-group="bg-video"]').forEach(e => e.classList.add("d-none"));
},
onChange : function(node, value, input) {
this.hideGroups();
document.querySelectorAll('.mb-2[data-group="'+ input.value + '"].d-none').forEach((el, i) => {
el.classList.remove("d-none");
});
let container = node.querySelector(":scope > .background-container");
if (!container) {
container = generateElements('<div class="background-container"></div>')[0];
node.appendChild(container);
}
let img = node.querySelector(":scope > .background-container > img");
let video = node.querySelector(":scope > .background-container > video");
container.querySelectorAll(":scope > *").forEach((el, i) => {
el.classList.add("d-none");
});
switch (value) {
case "bg-image":
if (img) {
img.classList.remove("d-none");
} else {
container.append(generateElements(bgImageTemplate)[0]);
//reselect element to load image
node.click();
}
break;
case "bg-video":
if (video) {
video.classList.remove("d-none");
} else {
container.append(generateElements(bgVideoTemplate)[0]);
//reselect element to load video
node.click();
}
break;
}
return node;
},
init: function(node) {
let selected = "none";
let img = node.querySelector(":scope > .background-container > img");
let video = node.querySelector(":scope > .background-container > video");
if (img?.offsetParent) {
selected = "bg-image";
}
if (video?.offsetParent) {
selected = "bg-video";
}
this.hideGroups();
return selected;
},
},{
name: "Image",
key: "src",
sort: section_sort++,
htmlAttr: "src",
child:":scope > .background-container > img",
group:"bg-image",
inline:true,
inputtype: ImageInput
},{
name: "Video",
child: "source",
key: "src",
sort: section_sort++,
htmlAttr: "src",
child:":scope > .background-container > video",
group:"bg-video",
inline:true,
inputtype: VideoInput
},{
name: "Poster",
key: "poster",
sort: section_sort++,
htmlAttr: "poster",
child:":scope > .background-container > video",
group:"bg-video",
inline:true,
inputtype: ImageInput
}, {
name: "Parallax",
key: "parallax",
sort: section_sort++,
child:":scope > .background-container",
htmlAttr: "class",
validValues: ["", "parallax"],
inputtype: ToggleInput,
data: {
className: "",
on: 'parallax',
off: ''
},
},
];
let SectionOverlay = [{
key: "section_overlay",
inputtype: SectionInput,
name:false,
sort: section_sort++,
//section: style_section,
data: {header:"Overlay"},
},{
//name: "Enable",
name: false,
key: "overlay",
sort: section_sort++,
inline: true,
//validValues: ["", "active"],
inputtype: ToggleInput,
data: {
className: "",
on: 'true',
off: 'false'
},
onChange : function(node, value, input) {
let group = document.querySelectorAll('.mb-2[data-group="overlay"]');
let overlay = node.querySelector(":scope > .overlay");
if (value == 'true') {
group.forEach(e => e.classList.remove("d-none"));
if (!overlay) {
overlay = generateElements('<div class="overlay"></div>')[0];
node.appendChild(overlay);
} else {
overlay.classList.remove("d-none");
}
} else {
group.forEach(e => e.classList.add("d-none"));
if (overlay) overlay.classList.add("d-none");
}
return element;
},
init: function(node) {
let overlay = node.querySelector(":scope > .overlay");
let group = document.querySelectorAll('.mb-2[data-group="overlay"]');
if (overlay && overlay.offsetParent) {
group.forEach(e => e.classList.remove("d-none"));
return 'true';
} else {
group.forEach(e => e.classList.add("d-none"));
return 'false';
}
}
},{
name: "Color",
key: "background-color",
sort: section_sort++,
htmlAttr: "style",
child:":scope > .overlay",
group:"overlay",
inputtype: ColorInput
},{
name: "Opacity",
key: "opacity",
sort: section_sort++,
htmlAttr: "style",
inline:false,
group:"overlay",
child:":scope > .overlay",
inputtype: RangeInput,
data:{
max: 1, //max zoom level
min:0,
step:0.1
}
}];
function sectionSeparatorProperties(name, title) {
return [{
key: `section_${name}_separator`,
inputtype: SectionInput,
name:false,
sort: section_sort++,
//section: style_section,
data: {header:`${title} Separator`},
},{
//name: "Enable",
name: false,
key: `${name}_separator`,
sort: section_sort++,
inline: true,
inputtype: ToggleInput,
data: {
className: "",
on: 'true',
off: 'false'
},
onChange : function(node, value, input) {
let group = document.querySelectorAll(`[data-group="${name}_separator"]`);
let separator = node.querySelector(`:scope > .${name}.separator`);
if (value == 'true') {
group.forEach(e => e.classList.remove("d-none"));
if (!separator) {
separator = generateElements(`<div class="separator ${name}">${defaultSeparatorSvg}</div>`)[0];
node.appendChild(separator);
} else {
separator.classList.remove("d-none");
}
} else {
group.forEach(e => e.classList.add("d-none"));
separator.classList.add("d-none");
}
return element;
},
init: function(node) {
let group = node.querySelectorAll(`[data-group="${name}_separator"]`);
let separator = node.querySelector(`:scope > .${name}.separator`);
if (separator && separator.offsetParent) {
group.forEach(e => e.classList.remove("d-none"));
return 'true';
} else {
group.forEach(e => e.classList.add("d-none"));
return 'false';
}
}
},{
name: "Icon",
key: "icon",
sort: section_sort++,
inline:true,
group:`${name}_separator`,
child:`.separator.${name} > svg`,
inputtype: HtmlListSelectInput,
onChange:function(element, value, input, component) {
let newElement = generateElements(value)[0];
let attributes = element.attributes;
//keep old svg size and colors
for (let i = 0; i < attributes.length; i++) {
let attr = attributes[i];
if (attr.name && attr.name != "viewBox") {
newElement.setAttribute(attr.name, attr.value);
}
}
element.replaceWith(newElement);
return newElement;
},
data: {
url: Vvveb.baseUrl + "../../resources/svg/separators/{value}/index.html",
clickElement:"li",
insertElement:"svg",
elements: 'Loading ...',
options: [{
value: "digital-red-panther",
text: "Red panther"
}]
},
},{
name: "Width",
key: "width",
sort: section_sort++,
htmlAttr: "width",
group:`${name}_separator`,
child:`.separator.${name} > svg`,
inputtype: RangeInput,
data:{
max: 640,
min:6,
step:1
}
},{
name: "Height",
key: "height",
sort: section_sort++,
htmlAttr: "height",
group:`${name}_separator`,
child:`.separator.${name} > svg`,
inputtype: RangeInput,
data:{
max: 640,
min:6,
step:1
}
},{
name: "Stroke width",
key: "stroke-width",
sort: section_sort++,
htmlAttr: "stroke-width",
group:`${name}_separator`,
child:`.separator.${name} > svg`,
inputtype: RangeInput,
data:{
max: 512,
min:1,
step:1
}
},/*{
key: "separator_svg_style_header",
inputtype: SectionInput,
name:false,
group:`${name}_separator`,
sort: section_sort++,
//section: style_section,
data: {header:"Svg colors"},
},*/ {
name: "Fill Color",
key: "fill",
sort: section_sort++,
col:12,
inline:true,
//section: style_section,
group:`${name}_separator`,
child:`.separator.${name} > svg`,
htmlAttr: "fill",
inputtype: ColorInput,
},{
name: "Color",
key: "color",
sort: section_sort++,
col:12,
inline:true,
//section: style_section,
group:`${name}_separator`,
child:`.separator.${name} > svg`,
htmlAttr: "color",
inputtype: ColorInput,
},{
name: "Stroke",
key: "stroke",
sort: section_sort++,
col:12,
inline:true,
//section: style_section,
group:`${name}_separator`,
child:`.separator.${name} > svg`,
htmlAttr: "color",
inputtype: ColorInput,
}
];
}
let SectionBottomSeparator = [{
key: "section_bottom_separator",
inputtype: SectionInput,
name:false,
sort: section_sort++,
//section: style_section,
data: {header:"Bottom Separator"},
},{
//name: "Enable",
name: false,
key: "top_bottom",
sort: section_sort++,
inline: true,
validValues: ["", "active"],
inputtype: ToggleInput,
data: {
className: "",
on: "active",
off: ""
}
},
];
/* Section */
let ComponentSectionContent = [
...SectionContent,
...SectionBackground,
...SectionOverlay,
...sectionSeparatorProperties("top", "Top"),
...sectionSeparatorProperties("bottom", "Bottom"),
];
let ComponentSectionStyle = [];/*[{
key: "Section Style",
inputtype: SectionInput,
name:false,
//section: style_section,
data: {header:"Style"},
},{
name: "Text1 Style",
key: "text1",
htmlAttr: "innerHTML",
inputtype: TextInput,
//section: style_section,
},{
name: "Name1 Style",
key: "name1",
htmlAttr: "name",
inputtype: TextInput,
//section: style_section,
},{
name: "Type1 Style",
key: "type1",
htmlAttr: "type",
inputtype: SelectInput,
//section: style_section,
data: {
options: [{
value: "button",
text: "button"
},{
value: "reset",
text: "reset"
},{
value: "submit",
text: "submit"
}],
}
},{
name: "Autofocus1 Style",
key: "autofocus1",
htmlAttr: "autofocus",
inputtype: CheckboxInput,
inline:true,
col:6,
//section: style_section
},{
name: "Disabled1 Style",
key: "disabled1",
htmlAttr: "disabled",
inputtype: CheckboxInput,
inline:true,
col:6,
//section: style_section,
}];*/
let ComponentSectionAdvanced = [];/* [{
key: "Section Advanced",
inputtype: SectionInput,
name:false,
section: advanced_section,
data: {header:"Advanced"},
},{
name: "Text1 Advanced",
key: "text1",
htmlAttr: "innerHTML",
inputtype: TextInput,
section: advanced_section,
},{
name: "Name1 Advanced",
key: "name1",
htmlAttr: "name",
inputtype: TextInput,
section: advanced_section,
},{
name: "Type1 Advanced",
key: "type1",
htmlAttr: "type",
inputtype: SelectInput,
section: advanced_section,
data: {
options: [{
value: "button",
text: "button"
},{
value: "reset",
text: "reset"
},{
value: "submit",
text: "submit"
}],
}
},{
name: "Autofocus1 Advanced",
key: "autofocus1",
htmlAttr: "autofocus",
inputtype: CheckboxInput,
inline:true,
col:6,
section: advanced_section
},{
name: "Disabled1 Advanced",
key: "disabled1",
htmlAttr: "disabled",
inputtype: CheckboxInput,
inline:true,
col:6,
section: advanced_section,
}];*/
function componentsInit(node) {
document.querySelectorAll('.mb-2[data-group]').forEach(e => e.classList.add("d-none"));
let img = node.querySelector(":scope > .background-container img");
let video = node.querySelector(":scope > .background-container video");
let overlay = node.querySelector(":scope > .overlay");
let separatorTop = node.querySelector(":scope > .separator.top");
let separatorBottom = node.querySelector(":scope > .separator.bottom");
let bg = "";
if (img && img.offsetParent) {
bg = "bg-image";
}
if (video && video.offsetParent) {
bg = "bg-video";
}
let showSection = function (section) {
document.querySelectorAll('.mb-2[data-group="' + section + '"]').forEach(e => e.classList.remove("d-none"));
}
if (bg) {
showSection(bg);
}
if (overlay && overlay.offsetParent) {
showSection("overlay");
}
if (separatorTop && separatorTop.offsetParent) {
showSection("top_separator");
}
if (separatorBottom && separatorBottom.offsetParent) {
showSection("bottom_separator");
}
}
//Vvveb.Components.add("elements/section", {
Vvveb.Components.extend("_base", "elements/section", {
nodes: ["section"],
name: "Section",
image: "icons/section.svg",
html: `<section>
<div class="container">
<h1>Section</h1>
</div>
</section>`,
properties: [
...ComponentSectionContent,
...ComponentSectionStyle,
...ComponentSectionAdvanced
],
init: componentsInit
});
//Vvveb.Components.add("elements/header", {
Vvveb.Components.extend("_base", "elements/header", {
nodes: ["header"],
name: "Header",
image: "icons/section.svg",
html: `<header>
<div class="container">
<h1>Section</h1>
</div>
</header>`,
properties: [
...ComponentSectionContent,
...ComponentSectionStyle,
...ComponentSectionAdvanced
],
init: componentsInit
});
//Vvveb.Components.add("elements/footer", {
Vvveb.Components.extend("_base", "elements/footer", {
nodes: ["footer"],
name: "Footer",
image: "icons/section.svg",
html: `<footer>
<div class="container">
<h1>Section</h1>
</div>
</footer>`,
properties: [
...ComponentSectionContent,
...ComponentSectionStyle,
...ComponentSectionAdvanced
],
init: componentsInit
});