# NoccyLabs JSL This is a collection of libraries that make working with JavaScript and data. Each component is available in it's own file, and example/default stylesheets are available in separate files. ## Installing For now, clone this somewhere and copy the files to your project. Hopefully [Symfony Issue #53999](https://github.com/symfony/symfony/issues/53999) will be completed soon, in which case you will hopefully be able to import JSL using the AssetMapper CLI commands. ## Components ### date.js > [!WARNING] > **WORK IN PROGRESS! MOSTLY NOT WORKING!** This component makes working with dates less of a pain. ```javascript import { date, Timestamp } from "./date.js"; // now const now = date(); // nothing below here in this example works, to be implemented! // tomorrow const tomorrow = date().add({days:1}); // yesterday const yesterday = now.sub({ days:1 }); // sometime const custom = date("2025-09-01 15:00:42 +02:00"); // format dates, php style let ts = now.format("Y-m-d H:i:s P"); ``` ### dialog.js This component creates dialogs on the fly, and resolves a promise when the dialog is accepted. ```javascript import { dialog } from "./dialog.js"; // show a message box dialog.msgbox("Something"); // show a message box and do something when dismissed dialog.msgbox("Ready!").then( function (result) { // do something! } ); // show a confirmation in an async callback ... async () => { const result = await dialog.confirm("Are you sure about that?"); if (result === "ok") { // do it } } // show custom actions in a custom select style dialog dialog.select("Put in warehouse", "Select", { "none":"None", "1":"WH1", "2":"WH2" }).then(...) ``` * `dialog.TYPE(body, ?title, ?actions, ?options)` → `Promise` Options: - `showClose` - true to show close button in top left corner - `width` - valid CSS width definition ### dom.js This component offers `dom` and `el` that can be used to manipulate the DOM. ```javascript import { dom, el } from "./dom.js"; // build DOM const myDiv = el.div({ class: "form-row" }, [ el.label({ class:"form-label", for:"myInput" }, "Label"), el.input({ class:"form-control", id:"myInput", type:"text" }) ]); // update element attributes dom.apply(myDiv, { style:"font-weight:bold;" }); // append children dom.append(myDiv, [ "Some text", el.span() ]); ``` ### json.js This component contains tools to query and update data structures using simplified JSON paths. ```javascript import { jsonQuery, jsonPatch } from './json.js'; let model = { name: "Bob", info: { age: 42 } }; jsonQuery(model, ".name") // → "Bob" jsonPatch(model, ".name", "Bobby"); // → { name:"Bobby", info:{ age:42 }} let items = [ { "name": "cheese", "price": "5.99" }, { "name": "wine", "price": "2.99" } ]; jsonQuery(items, "[].name") // → [ "cheese", "wine" ] ``` ### jsonform.js This component not only builds forms and allow you to map it against paths in a model dataset, but it also allows you to do inline editing of your data, with type mapping. ```javascript import { JsonForm, TextField } from "./jsonform.js"; const productForm = new JsonForm(); productForm.layout.addRow() .append(new TextField({ label:"Product name", path:".product.name", width:70 })) .append(new TextField({ label:"Price", path:".price" })); myTargetEl.appendChild(productForm.dom()); productForm.model = { product: { name: "Swedish Fish" }, price: "9.99" }; // make it possible to edit the form productForm.editable = true; // when the user is done editing set editable = false and access the updated model productForm.editable = false; const newModel = productForm.model; // → { product:{ name:"Swedish Fish" }, price:"8.99" } // You can even put a form inside a dialog! dialog.dialog(productForm.dom(), "Title", {"ok":"Update"}, { showClose:true, width:'400px' }).then( (result) => { productForm.editable = false; if (result == 'ok') { // productForm.model is updated } } ) productForm.editable = true; ```