Docs

#### Translations

Return to domains Saving ... Save
Vvveb 0.2 is now available! Update now
You successfully read this important alert message.
You successfully read this important warning message.
You successfully read this important alert message.

Text | Translation
--- | ---
Text | Translation

Text </text> </div> <div class=""> <label for="translation-textarea" class="small py-1">Translation</label> <textarea id="translation-textarea" class="form-control" rows="4"></text> </div> </div> </div> </div> </div> <input type="hidden" name="csrf" id="csrf" data-v-csrf> <div id="main-footer"> Powered by <a href="https://www.vvveb.com" target="_blank">Vvveb</a> </div> </div> </div> <style> table[data-v-translations] thead th { resize:horizontal; overflow:auto } table[data-v-translations] tbody { cursor:pointer; } table[data-v-translations] tbody tr.active td { background-color: var(--bs-primary) !important; color: var(--bs-light); } table[data-v-translations] tbody tr.changed td { background-color: var(--bs-success-bg-subtle); } table[data-v-translations] tbody tr td:empty { background-color: rgba(var(--bs-warning-rgb), 0.1); } </style> <!-- <script id="jquery-js" src="js/jquery.min.js"></script> --> <script id="popper-js" src="js/popper.min.js"></script> <script id="bootstrap-js" src="js/bootstrap.min.js"></script> <script id="theme-js" src="js/theme.js"></script> <!-- vvveb modules code --> <script id="admin-js" type="module" src="/js/admin.js"></script> <script> var rbracket = /\[\]$/; function buildParams( prefix, obj, add ) { var name; if ( Array.isArray( obj ) ) { // Serialize array item. for(var key in obj) { let v = obj[key]; if ( rbracket.test( prefix ) ) { // Treat each array item as a scalar. add( prefix, v ); } else { // Item is non-scalar (array or object), encode its numeric index. buildParams( prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", v, add ); } } } else if ( typeof obj === "object" ) { // Serialize object item. for ( name in obj ) { buildParams( prefix + "[" + name + "]", obj[ name ], add ); } } else { // Serialize scalar item. add( prefix, obj ); } } // Serialize an array of form elements or a set of // key/values into a query string function nestedFormData( a ) { var prefix, s = [], add = function( key, valueOrFunction ) { // If value is a function, invoke it and use its return value var value = typeof valueOrFunction === "function" ? valueOrFunction() : valueOrFunction; s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value == null ? "" : value ); }; if ( a == null ) { return ""; } // If an array was passed in, assume that it is an array of form elements. if ( Array.isArray( a ) || ( Object.is( a ) ) ) { // Serialize the form elements for(var key in object) { let v = object[key]; //jQuery.each( a, function() { add( key, v ); }; } else { // If traditional, encode the "old" way (the way 1.3.2 or older // did it), otherwise encode params recursively. for ( prefix in a ) { buildParams( prefix, a[ prefix ], add ); } } // Return the resulting serialization return s.join( "&" ); }; let selectedTranslation; let selectedRow; document.querySelector("table[data-v-translations] tbody").addEventListener("click", function (e) { let element = e.target.closest("tr"); let columns; if (element) { columns = element.querySelectorAll("td"); document.getElementById("text-textarea").value = columns[0].innerHTML; document.getElementById("translation-textarea").value = columns[1].innerHTML; selectedTranslation = columns[1]; selectedRow = element; document.querySelectorAll("table[data-v-translations] tbody tr").forEach(e => e.classList.remove("active")); this.classList.add("active"); } }); let search = function (e) { let searchText = this.value; delay(() => { if (searchText.length) { document.querySelectorAll("table[data-v-translations] tbody tr").forEach(e => { e.style.display = "none"; if (e.innerHTML.indexOf(searchText) > -1) e.style.display = ""; }); } else { document.querySelectorAll("table[data-v-translations] tbody tr").forEach(e => e.style.display = ""); } }, 300); }; let filter = document.getElementById("filter"); filter.addEventListener("keyup", search); filter.addEventListener("search", search); let save = function (e) { let btn = this; let translations = {}; let saveUrl = this.href; let changedRows = document.querySelectorAll("table[data-v-translations] tbody tr.changed"); changedRows.forEach(function (e) { let columns = e.querySelectorAll("td"); translations[columns[0].innerHTML] = columns[1].innerHTML; }); btn.querySelector(".loading")?.classList.toggle("d-none"); btn.querySelector(".button-text")?.classList.toggle("d-none"); fetch(saveUrl, {method:"POST", headers: { "Content-Type": "application/x-www-form-urlencoded", }, body: nestedFormData({translations,csrf:document.getElementById("csrf")?.value})}) .then(response => { if (!response.ok) { return Promise.reject(response); } return response.json() }) .then(data => { btn.querySelector(".loading")?.classList.toggle("d-none"); btn.querySelector(".button-text")?.classList.toggle("d-none"); displayToast("bg-success", "Save", data.message ?? data); changedRows.forEach(e => e.classList.remove("changed")); }) .catch(error => { console.log(error.statusText); displayToast("bg-danger", "Error", "Error saving!\n" + error.responseText); //displayToast("bg-danger", "Revision", "Error!"); }); e.preventDefault(); return false; }; document.getElementById("save-btn").addEventListener("click", save); document.getElementById("add-text").addEventListener("click", function () { let text = prompt("Enter new text"); if (text) { document.querySelector("[data-v-translations] tbody").append(generateElements(`<tr class="changed"><td>${text}</td><td></td></tr>`)[0]); window.scrollTo(0, document.body.scrollHeight); } }); document.getElementById("translation-textarea").addEventListener("keyup", function (e) { if (selectedTranslation) { delay(() => { selectedTranslation.innerHTML = this.value; selectedRow.classList.add("changed"); }, 200); } }); </script> <!-- Modal --> <div class="modal fade" id="heartBeatLogin" data-bs-backdrop="static" tabindex="-1" aria-labelledby="heartBeatLogin" aria-hidden="true"> <div class="modal-dialog modal-dialog-centered"> <div class="modal-content"> <div class="modal-header"> <span class="modal-title" id="heartBeatLogin"> <h5>Session has expired</h5> <span>Login to resume your work</span> </span> <button type="button" class="btn-close me-2" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body p-5"> </div> </div> </div> </div> <!-- save toast --> <div class="toast-container position-fixed end-0 bottom-0 me-4 my-4"> <div class="toast " role="alert" aria-live="assertive" aria-atomic="true" id="bottom-toast"> <div class="toast-header bg-success bg-opacity-25 border-0"> <strong class="me-auto">Page save</strong> <!-- <small class="badge bg-success">status</small> --> <button type="button" class="btn-close me-1" data-bs-dismiss="toast" aria-label="Close"></button> </div> <div class="toast-body"> <div class="flex-grow-1"> <div class="message"> <div>Elements saved!</div> <div>Template backup was saved!</div> <div>Template was saved!</div> </div> <div> <!-- <a class="btn btn-success btn-icon btn-sm w-100 mt-2" href="">View page</a></div> --> </div> </div> </div> </div> <div class="toast-container position-fixed end-0 top-0 me-4 my-4"> <div class="toast " role="alert" aria-live="assertive" aria-atomic="true" id="top-toast"> <div class="toast-header bg-success bg-opacity-25 border-0"> <strong class="me-auto">Page save</strong> <!-- <small class="badge bg-success">status</small> --> <button type="button" class="btn-close me-1" data-bs-dismiss="toast" aria-label="Close"></button> </div> <div class="toast-body"> <div class="flex-grow-1"> <div class="message"> <div>Elements saved!</div> <div>Template backup was saved!</div> <div>Template was saved!</div> </div> <div> <!-- <a class="btn btn-success btn-icon btn-sm w-100 mt-2" href="">View page</a></div> --> </div> </div> </div> </div> </body> </html>