<?php ########################################################### ## Implement a copy form section button ########################################################### XLSDV('fr',array( 'Add' => 'Ajouter', 'Delete' => 'Supprimer' )); Markup('foxsectionend','<if','/\(:foxsectionend\\s*:\)/i', Keep("</div></div>")); Markup('foxsection','<if','/\(:foxsection\\s+([\\w]+)\\s?(.*?):\)/i', "FoxSection"); Markup('foxsectioncopybutton','<if','/\(:foxsectioncopybutton\\s+([\\w]+)\\s?(.*?):\)/i', "FoxSectionCopyButton"); Markup('foxsectiondeletebutton','<if','/\(:foxsectiondeletebutton\\s?(.*?):\)/i', "FoxSectionDeleteButton"); Markup('foxsectionmoveicon','<if','/\(:foxsectionmoveicon\\s?(.*?):\)/i', "FoxSectionMoveIcon"); Markup('foxsectionnumber','<if','/\(:foxsectionnumber\\s*:\)/i', Keep("<span class='foxsectionnumber'></span>")); function FoxSection($m) { global $HTMLHeaderFmt, $HTMLFooterFmt, $HTMLStylesFmt;; $sClassName = $m[1]; $args = ParseArgs($m[2]); $dep = $args['dep']; $value = $args['value']; SDV($HTMLHeaderFmt['foxsection'], "<script type='text/javascript'> var gSectionNb = []; var gInsertAfterSection = []; var gSectionToCopy = []; function sectionCopyInit(sClassName) { sections = document.getElementsByClassName(sClassName); if (sections && sections.length > 0) { sections[0].style.maxHeight = '10000px'; sections[0].style.transition = 'max-height 1s, opacity 1s'; gSectionToCopy[sClassName] = sections[0].cloneNode(true); gSectionToCopy[sClassName].style.opacity = 0; gSectionToCopy[sClassName].style.maxHeight = '0px'; gSectionNb[sClassName] = [1, 1]; reNumberSection(sections[0], gSectionNb[sClassName][0], sClassName); } } function getSectionName(el){ let section = el.closest('.foxsection'); return section.className.split(' ')[1]; } function copySection(sClassName, sMaxCopy) { gSectionNb[sClassName] = [gSectionNb[sClassName][0], sMaxCopy] if (gSectionNb[sClassName][0] < gSectionNb[sClassName][1]) { gSectionNb[sClassName][0]++; if (gInsertAfterSection[sClassName] === undefined) { gInsertAfterSection[sClassName] = document.getElementsByClassName(sClassName)[0]; } newSection = gSectionToCopy[sClassName].cloneNode(true); gInsertAfterSection[sClassName].parentNode.insertBefore(newSection, gInsertAfterSection[sClassName].nextSibling); window.setTimeout(function() { newSection.style.maxHeight = '10000px'; newSection.style.opacity = 1; }, 50); reNumberAllSections(sClassName); showHideSectionByElement(newSection); } } function deleteSection(el) { sClassName = getSectionName(el); if (gSectionNb[sClassName][0] > 1) { toDelete = el.closest('.' + sClassName); window.setTimeout(function() { toDelete.style.maxHeight = '0px'; toDelete.style.opacity = 0; }, 50); window.setTimeout(function() { toDelete.remove(); gSectionNb[sClassName][0]--; reNumberAllSections(sClassName); }, 1000); } } function reNumberAllSections(sClassName) { sections = document.getElementsByClassName(sClassName); for (let i = 0; i < sections.length; i++) { reNumberSection(sections[i], i + 1, sClassName); gInsertAfterSection[sClassName] = sections[i]; } copyButton = document.getElementById(sClassName + 'copybutton'); if (copyButton) { copyButton.disabled = (gSectionNb[sClassName][0] == gSectionNb[sClassName][1]); } } function reNumberSection(section, number, sClassName) { numberSpans = section.getElementsByClassName('foxsectionnumber'); for (let i = 0; i < numberSpans.length; i++) { numberSpans[i].textContent = number.toString(); } renameInputNames(section, '_fsnumber_', '_fsn' + number.toString()); renameInputNames(section, /_fsn[0-9]+/g, '_fsn' + number.toString()); deleteButtons = section.getElementsByClassName('deletesectionbutton'); for (let i = 0; i < deleteButtons.length; i++) { deleteButtons[i].style.display = (gSectionNb[sClassName][0] > 1 ? 'inline-block' : 'none') } moveIcons = section.getElementsByClassName('movesectionicon'); for (let i = 0; i < moveIcons.length; i++) { if (gSectionNb[sClassName][0] > 1) { moveIcons[i].style.display = 'inline-block'; var style = window.getComputedStyle(moveIcons[i], null); var fontSize = parseFloat(style.getPropertyValue('font-size')); var svg = moveIcons[i].getElementsByTagName('svg')[0]; svg.style.width = (fontSize) + 'px'; svg.style.height = (fontSize*0.8) + 'px'; var color = style.getPropertyValue('color'); var g = svg.children.item('g'); g.style.fill = color; } else { moveIcons[i].style.display = 'none'; } } } function renameInputNames(el, from, to) { var elementsClassNameToRename = ['input', 'select', 'textarea']; for (name of elementsClassNameToRename) { inputElems = el.getElementsByTagName(name); for (let i = 0; i < inputElems.length; i++) { var name = inputElems[i].getAttribute('name'); if (name != null) { inputElems[i].name = name.replaceAll(from, to); } } } } function showHideSectionByElement(el) { var inputElems = el.querySelectorAll('input[value=\"foxshowhide\"]'); for (let i = 0; i < inputElems.length; i++) { var thisEl = inputElems[i]; var depName = thisEl.name.substring(0, thisEl.name.indexOf('=')); if (depName != null) { var depValue = thisEl.name.substring(thisEl.name.indexOf('=') + 1); var depElem = document.querySelectorAll('select[name=\"' + depName + '\"]'); var height = thisEl.parentNode.getBoundingClientRect().height; thisEl.parentNode.style.transition = 'max-height 0.5s, opacity 0.5s'; depElem[0].addEventListener('change', (e) => { var show = e.currentTarget.value == depValue; window.setTimeout(function() { thisEl.parentNode.style.opacity = (show ? 1 : 0); }, show ? 500 : 50); window.setTimeout(function() { thisEl.parentNode.style.maxHeight = (show ? height+'px' : '0px'); }, show ? 50 : 500); window.setTimeout(function() { thisEl.parentNode.style.display = (show ? 'block' : 'none'); }, show || e.init ? 0 : 1000); }); var event = new Event('change'); event.init = true; depElem[0].dispatchEvent(event); } } } function showHideSectionBySectionName(sClassName) { sections = document.getElementsByClassName(sClassName); if (sections && sections.length > 0) { showHideSectionByElement(sections[0]); } } function addRemoveDragEvents(section, remove=false, touch=false){ var eventFct = remove ? 'removeEventListener' : 'addEventListener'; section.setAttribute('draggable', remove ? 'false' : 'true'); section[eventFct]('dragstart', dragStartHandler); section[eventFct]('dragend', dragEndHandler); const sectionList = section.closest('div#section-list'); let siblings = [...sectionList.querySelectorAll(':scope > div.foxsection')]; for (const sibling of siblings){ sibling[eventFct](touch ? 'touchmove' : 'dragover', dragOverHandler); } } function dragMouseDown(el, touch=false) { section = el.closest('.foxsection'); addRemoveDragEvents(section, false, touch); if (touch) { setTimeout(() => section.classList.add('dragging'), 0); } } function dragMouseUp(el, touch=false) { section = el.closest('.foxsection'); addRemoveDragEvents(section, true, touch); if (touch) { finishDrag(section); } } function dragStartHandler(ev) { setTimeout(() => this.classList.add('dragging'), 0); }; function dragEndHandler(ev) { finishDrag(ev.currentTarget); }; function finishDrag(section) { section.classList.remove('dragging'); addRemoveDragEvents(section, true); const sClassName = section.className.split(' ')[1]; reNumberAllSections(sClassName); }; function dragOverHandler(ev) { const sectionList = ev.currentTarget.closest('div#section-list'); const draggingItem = sectionList.querySelector('.dragging'); let siblings = [...sectionList.querySelectorAll(':scope > div:not(.dragging)')]; let nextSibling = siblings.find(sibling => { const rect = sibling.getBoundingClientRect(); const cursorY = ev.clientY || ev.targetTouches[0].clientY; return cursorY <= (rect.top + rect.bottom) / 2; }); sectionList.insertBefore(draggingItem, nextSibling); } </script>"); $HTMLStylesFmt['draggable'] = " .dragging * {opacity:0 !important;} .movesectionicon {min-width:unset; cursor: grab; display:none; touch-action: none;} .movesectionicon svg {width:0px; height:0px;} .deletesectionbutton {display:none;} "; $ret = "<div id=\"section-list\" class=\"section-list-".$sClassName."\"><div class=\"foxsection ".$sClassName."\">"; if ($dep && $value) { // section must be shown or hidden when: // 1) the page display the section is copied (by reNumber which set the section display based on the value of the source input element) // 2) the source input element is changed $ret .= "<input type=hidden name=\"".$dep."=".$value."\" value=\"foxshowhide\">"; $HTMLFooterFmt[$sClassName] = "<script type='text/javascript' language='JavaScript1.2'>showHideSectionBySectionName('".$sClassName."')</script>"; } else { $HTMLFooterFmt[$sClassName] = "<script type='text/javascript' language='JavaScript1.2'>sectionCopyInit('".$sClassName."')</script>"; } return Keep($ret); } function FoxSectionCopyButton($m) { $args = ParseArgs($m[2]); $text = isset($args['text']) ? $args['text'] : XL("Add"); $class = isset($args['class']) ? $args['class'] : ""; $sMaxCopy = isset($args['maxcopy']) ? $args['maxcopy'] : ""; $ret = "<input id=\"$m[1]copybutton\" type=button value=\"$text\" class=\"$class\" onclick=\"copySection('$m[1]', $sMaxCopy)\">"; return Keep($ret); } function FoxSectionDeleteButton($m) { $args = ParseArgs($m[1]); $text = isset($args['text']) ? $args['text'] : XL("Delete"); $class = isset($args['class']) ? $args['class'] : ""; $ret = "<input type=button value=\"$text\" class=\"$class deletesectionbutton\" style=\"display: none;\" onclick=\"deleteSection(this)\">"; return Keep($ret); } function FoxSectionMoveIcon($m) { $args = ParseArgs($m[1]); $size = isset($args['size']) ? ("width: ".$args['size']."px;") : ""; $class = isset($args['class']) ? $args['class'] : ""; $text = isset($args['text']) ? $args["text"] : ""; $ret = "<button type=button class=\"$class movesectionicon\" style=\"$size\" onmousedown=\"dragMouseDown(this)\" ontouchstart=\"dragMouseDown(this, true)\" onmouseup=\"dragMouseUp(this)\" ontouchend=\"dragMouseUp(this, true)\"> <svg viewBox=\"0,0,100,100\" preserveAspectRatio=\"none\"> <g fill=\"grey\"> <rect x=\"20%\" y=\"10%\" width=\"20%\" height=\"20%\"/> <rect x=\"20%\" y=\"45%\" width=\"20%\" height=\"20%\"/> <rect x=\"20%\" y=\"80%\" width=\"20%\" height=\"20%\"/> <rect x=\"50%\" y=\"10%\" width=\"20%\" height=\"20%\"/> <rect x=\"50%\" y=\"45%\" width=\"20%\" height=\"20%\"/> <rect x=\"50%\" y=\"80%\" width=\"20%\" height=\"20%\"/> </g> </svg><span>$text</span></button>"; return Keep($ret); } ?>