Resources
CDN
<div class="SmarkForm">
<section>
<div class='form-group h1'>Company</div>
<div class='input-group'>
<label data-smark>Corporate Name</label>
<input data-smark name='company' type='text' placeholder='Company Name'>
</div>
<div class='input-group'>
<label data-smark>Address</label>
<textarea data-smark name='address' placeholder='Address'></textarea>
</div>
<div class='form-group'>
<label data-smark>City,State,Zip</label>
<input data-smark name='city' placeholder='City' style='flex: 6'>
<input data-smark name='state' placeholder='State' style='flex:1'>
<input data-smark name='postCode' placeholder='Postal Code' style='flex:2'>
</div>
</section>
<section>
<div class='form-group h2'><span class='foldButton' data-smark='{"action":"fold","hotkey":"f","context":"employees","foldedClass":"folded"}'></span><span><span>Employees (</span><span data-smark='{"action":"count","context":"employees"}'></span><span>)</span></span>
<div class='form-group'>
<div class='spacer'></div>
<button data-smark='{"action":"addItem","hotkey":"+","context":"employees","autoscroll":"self"}' title='Add employee'><span role='img' aria-label='Append new employee'>➕</span></button>
<button data-smark='{"action":"removeItem","hotkey":"-","context":"employees","keep_non_empty":true}' title='Remove employees from bottom priorizing empties'><span role='img' aria-label='Wisely shrink employee list'>➖</span></button>
<button data-smark='{"action":"removeItem","hotkey":"*","context":"employees","target":"*","keep_non_empty":true}' title='Clear all empty employees'><span role='img' aria-label='Remove all empty employees'>🧹</span></button>
</div>
</div>
<div class='form-group'>
<div class='form-group' data-smark='{"name":"employees","type":"list","exportEmpties":true,"sortable":true}'>
<fieldset class='full-width form-group aside reverse' data-smark='{"exportEmpties":false}'>
<button class='inline' data-smark='{"action":"removeItem","hotkey":"-","failback":"clear"}' title='Remove this employee'><span role='img' aria-label='Remove this employee'>➖</span></button>
<div class='form-group spacer'>
<div class='form-group'>
<div class='input-group'>
<label data-smark>First Name</label>
<input data-smark name='name' placeholder='Name'>
</div>
<div class='input-group'>
<label data-smark>Last Name</label>
<input data-smark name='lastName' placeholder='Surnme'>
</div>
</div>
<div class='form-group'>
<label data-smark>Sex:</label>
<label>
<input data-smark type='radio' name='sex' value='male'>Male
</label>
<label>
<input data-smark type='radio' name='sex' value='female'>Female
</label>
<label>
<input data-smark type='radio' name='sex' value='other'>Other
</label>
</div>
<div class='form-group'>
<div class='input-group'>
<label data-smark>Date of Birth</label>
<input data-smark type='date' name='birth' placeholder='dd/mm/yyyy'>
</div>
<div class='input-group'>
<label data-smark>Salary</label>
<input data-smark type='number' name='salary' step='0.01' placeholder='Euros'>
</div>
</div>
<div class='form-group'>
<div class='input-group'>
<label data-smark='data-smark'>Telephones</label>
<div data-smark='{"name":"phones","type":"list","of":"input","max_items":4}'>
<div class='singleton'>
<button data-smark='{"action":"removeItem","hotkey":"-"}' title='Remove this item'><span role='img' aria-label='Remove this item'>➖</span></button>
<input data-smark='data-smark' type='tel' placeholder='Telephone'/>
<button data-smark='{"action":"addItem","hotkey":"+"}' title='Add new item below'><span role='img' aria-label='Add new item'>➕</span></button>
</div>
</div>
</div>
<div class='input-group'>
<label data-smark='data-smark'>Emails</label>
<div data-smark='{"name":"emails","type":"list","of":"input","max_items":4}'>
<div class='singleton'>
<button data-smark='{"action":"removeItem","hotkey":"-"}' title='Remove this item'><span role='img' aria-label='Remove this item'>➖</span></button>
<input data-smark='data-smark' type='email' placeholder='Email'/>
<button data-smark='{"action":"addItem","hotkey":"+"}' title='Add new item below'><span role='img' aria-label='Add new item'>➕</span></button>
</div>
</div>
</div>
</div>
</div>
</fieldset>
</div>
</div>
<div class='form-group f2'>
<div class='spacer'></div>
<button data-smark='{"action":"addItem","hotkey":"+","context":"employees","autoscroll":"elegant"}' title='Add employee'>➕</button>
<button data-smark='{"action":"removeItem","hotkey":"-","context":"employees","keep_non_empty":true,"autoscroll":"elegant","failback":"clear"}' title='Remove employees from bottom priorizing empties'><span role='img' aria-label='Wisely shrink employee list'>➖</span></button>
<button data-smark='{"action":"removeItem","hotkey":"*","context":"employees","target":"*","autoscroll":"elegant","keep_non_empty":true}' title='Clear all empty employees'><span role='img' aria-label=''>🧹</span></button>
</div>
</section>
<section>
<div class='form-group'>
<div class='spacer'></div>
<button data-smark='{"action":"import","hotkey":"i"}' title='Import (JSON) data'><span role='img' aria-label=''>📂</span> Import</button>
<button data-smark='{"action":"clear","hotkey":"x"}' title='Clear form data'><span role='img' aria-label=''>❌</span> Cancel</button>
<button data-smark='{"action":"export","hotkey":"s"}' title='Submit form data'><span role='img' aria-label=''>💾</span> Submit</button>
</div>
</section>
</div>
<div class="SmarkForm">
<section>
<div class='form-group h1 nowrap'>
<div class='spacer'></div>
<button data-smark='{"action":"import","context":"tasklist"}'><span role='img' aria-label=''>📂</span> Import (JSON)</button>
<button data-smark='{"action":"export","context":"tasklist"}'><span role='img' aria-label=''>💾</span> Export (JSON)</button>
</div>
<div data-smark='{"type":"list","name":"tasklist","sortable":true,"exportEmpties":true,"min_items":0}'>
<fieldset class='form-group aside reverse' data-smark='{"exportEmpties":false}'>
<button class='inline' data-smark='{"action":"removeItem"}' title='Remove task'><span role='img' aria-label='Remove task'>❌</span></button>
<div class='form-group spacer'>
<div class='form-group'><span data-smark='{"action":"position"}'>/</span><span> </span>
<input data-smark name='title' type='text' placeholder='Task title'>
</div>
<div class='form-group'>
<div class='input-group'>
<label data-smark='data-smark'>Goals</label>
<div data-smark='{"name":"goals","type":"list","of":"input","sortable":true,"max_items":100}'>
<div class='singleton'>
<button data-smark='{"action":"removeItem","failback":"clear","hotkey":"-"}' title='Remove this item'><span role='img' aria-label='Remove this item'>➖</span></button>
<input data-smark='data-smark' type='text' placeholder='New goal...'/>
<button data-smark='{"action":"addItem","hotkey":"+"}' title='Add new item below'><span role='img' aria-label='Add new item'>➕</span></button>
</div>
</div>
</div>
</div>
</div>
</fieldset>
</div>
<div class='form-group f1 nowrap' style='text-align: right'>
<div class='spacer'></div>
<button data-smark='{"action":"clear","context":"tasklist","autoscroll":"elegant"}' title='Clear form data'><span role='img' aria-label=''>❌</span> Clear all</button>
<button data-smark='{"action":"removeItem","context":"tasklist","target":"*","autoscroll":"elegant","keep_non_empty":true}' title='Clear all empty tasks'><span role='img' aria-label=''>🧹</span> Clear empty</button>
<button data-smark='{"action":"addItem","context":"tasklist"}'><span role='img' aria-label=''>➕</span> Add new task</button>
</div>
</section>
</div>
<div class="SmarkForm">
<section>
<h2>Activity</h2>
<div class='form-group'>
<label data-smark>Title</label>
<input data-smark name='activity_name' type='text' placeholder='Name your planned activity...'>
</div>
<div class='input-group'>
<label data-smark>Description</label>
<textarea data-smark name='activity_description' placeholder='Brief description of your activity'></textarea>
</div>
<h2>Planning</h2>
<label data-smark>Origin</label>
<div class='form-group' data-smark='{"type":"form","name":"origin"}'>
<label class='inline'><span>0</span><span role='img' aria-label=''> 📌</span></label>
<input data-smark name='coordinates' type='text' placeholder='Lat, Lng'>
<input data-smark name='date' type='date' placeholder='dd/mm/yyyy'>
<input data-smark name='time' type='time' placeholder='hh:mm'>
<input data-smark name='place' placeholder='Place name or address'>
<input data-smark name='city' placeholder='City'>
</div>
<label data-smark>Stops</label>
<div class='form-group' data-smark='{"type":"list","name":"stops","min_items":0,"exportEmpties":false}'>
<div class='full-width form-group aside'>
<label class='inline'><span data-smark='{"action":"position"}'></span><span role='img' aria-label=''> 📌</span></label>
<div class='form-group'>
<input data-smark name='coordinates' type='text' placeholder='Lat, Lng'>
<input data-smark name='date' type='date' placeholder='dd/mm/yyyy'>
<input data-smark name='time' type='time' placeholder='hh:mm'>
<input data-smark name='place' placeholder='Place name or address'>
<input data-smark name='city' placeholder='City'>
</div>
<button class='inline' data-smark='{"action":"removeItem","hotkey":"-"}' title='Remove stop place' style='margin-left:auto'><span role='img' aria-label='Remove stop place'>➖</span></button>
</div>
</div>
<div class='form-group'>
<div class='spacer'></div>
<button class='inline' data-smark='{"action":"addItem","hotkey":"+","context":"stops"}'><span role='img' aria-label=''>➕</span> Add Stop Place</button>
</div>
<label data-smark>Destination</label>
<div class='form-group' data-smark='{"type":"form","name":"destination"}'>
<label class='inline'><span data-smark='{"action":"count","context":"../stops","delta":1}'>N</span><span role='img' aria-label=''> 📌</span></label>
<input data-smark name='coordinates' type='text' placeholder='Lat, Lng'>
<input data-smark name='date' type='date' placeholder='dd/mm/yyyy'>
<input data-smark name='time' type='time' placeholder='hh:mm'>
<input data-smark name='place' placeholder='Place name or address'>
<input data-smark name='city' placeholder='City'>
</div>
</section>
<section>
<h2>Participants</h2>
<label data-smark>Organizers</label>
<div class='form-group' data-smark='{"type":"list","name":"organizers","exportEmpties":false}'>
<div class='full-width form-group aside'>
<label class='inline'><span data-smark='{"action":"position"}'></span><span role='img' aria-label=''> 🧑💼</span></label>
<div class='form-group spacer'>
<div class='form-group'>
<input style='flex: 6' data-smark name='name' placeholder='Name'>
<input style='flex: 2' data-smark name='phone' type='tel' placeholder='Phone number'>
</div>
</div>
<button class='inline' data-smark='{"action":"removeItem","hotkey":"-"}' title='Remove organizer' style='margin-left:auto'><span role='img' aria-label='Remove organizer'>➖</span></button>
</div>
</div>
<div class='form-group'>
<div class='spacer'></div>
<button class='inline' data-smark='{"action":"addItem","hotkey":"+","context":"organizers"}'><span role='img' aria-label=''>➕</span> Add Organizer</button>
</div>
<label data-smark>Participants:</label>
<div class='form-group' data-smark='{"type":"list","name":"participants","min_items":0,"exportEmpties":false}'>
<div class='full-width form-group aside'>
<label class='inline'><span data-smark='{"action":"position"}'></span><span role='img' aria-label=''> 🏃</span></label>
<div class='form-group spacer'>
<div class='form-group'>
<input style='flex: 6' data-smark name='name' placeholder='Name'>
<input style='flex: 2' data-smark name='phone' type='tel' placeholder='Phone number'>
</div>
</div>
<button class='inline' data-smark='{"action":"removeItem","hotkey":"-"}' title='Remove participant' style='margin-left:auto'><span role='img' aria-label='Remove participant'>➖</span></button>
</div>
</div>
<div class='form-group'>
<div class='spacer'></div>
<button class='inline' data-smark='{"action":"addItem","hotkey":"+","context":"participants"}'><span role='img' aria-label=''>➕</span> Add Participant</button>
</div>
</section>
<section>
<div class='form-group'>
<div class='spacer'></div>
<button data-smark='{"action":"import"}' title='Import (JSON) data'><span role='img' aria-label=''>📂</span> Import</button>
<button data-smark='{"action":"clear"}' title='Clear form data'><span role='img' aria-label=''>❌</span> Cancel</button>
<button data-smark='{"action":"export"}' title='Submit form data'><span role='img' aria-label=''>💾</span> Submit</button>
</div>
</section>
</div>
<div class="SmarkForm">
<h2>General data</h2>
<div class='form-group'>
<div class='form-group'>
<label data-smark>Name:</label>
<input data-smark type='text' name='name' placeholder='Beach Name'>
</div>
<div class='form-group'>
<label data-smark>Risk Level:</label>
<select data-smark name='risk' style='max-width: 8em'>
<option value='low'>Low</option>
<option value='medium'>Medium</option>
<option value='high'>High</option>
</select>
</div>
</div>
<div class='form-group'>
<div class='form-group'>
<label data-smark>Municipality:</label>
<input data-smark type='text' name='municipality'>
</div>
<div class='form-group'>
<label data-smark>Coordinates:</label>
<input data-smark type='text' name='coordinates' placeholder='Lat, Lng'>
</div>
</div>
<h2>Surveillance Periods</h2>
<div data-smark='{"type":"list","name":"periods","exportEmpties":true}'>
<section>
<div class='form-group aside'>
<h2>Period <span data-smark='{"action":"position"}'>N</span></h2>
<button class='inline' data-smark='{"action":"removeItem","hotkey":"-"}' title='Remove this period'><span role='img' aria-label='Remove this item'>➖</span></button>
</div>
<div class='form-group'>
<div class='form-group'>
<label data-smark>Start Date:</label>
<input data-smark type='date' name='start_date'>
</div>
<div class='form-group'>
<label data-smark>End Date:</label>
<input data-smark type='date' name='end_date'>
</div>
</div>
<h3>Schedule</h3>
<div class='form-group'>
<button data-smark='{"action":"removeItem","hotkey":"-","context":"surveillance_schedule"}' title='Less intervals'><span role='img' aria-label='Remove interval'>➖</span></button>
<button data-smark='{"action":"addItem","hotkey":"+","context":"surveillance_schedule"}' title='More intrevals'><span role='img' aria-label='Add new interval'>➕</span></button>
<label>Surveillance:</label><span data-smark='{"type":"list","name":"surveillance_schedule","min_items":0,"max_items":3}'><span>
<input class='small' data-smark type='time' name='start'>to
<input class='small' data-smark type='time' name='end'></span><span data-smark='{"role":"empty_list"}'>(No Surveillance)</span><span data-smark='{"role":"separator"}'>, </span><span data-smark='{"role":"last_separator"}'> and </span></span>
</div>
<div class='form-group'>
<button data-smark='{"action":"removeItem","hotkey":"-","context":"boat_schedule"}' title='Less intervals'><span role='img' aria-label='Remove interval'>➖</span></button>
<button data-smark='{"action":"addItem","hotkey":"+","context":"boat_schedule"}' title='More intrevals'><span role='img' aria-label='Add new interval'>➕</span></button>
<label>Boat:</label><span data-smark='{"type":"list","name":"boat_schedule","min_items":0,"max_items":3}'><span>
<input class='small' data-smark type='time' name='start'>-
<input class='small' data-smark type='time' name='end'></span><span data-smark='{"role":"empty_list"}'>(No Boat Service)</span><span data-smark='{"role":"separator"}'>, </span><span data-smark='{"role":"last_separator"}'> and </span></span>
</div>
<div class='form-group aside'>
<h3>Observation Points</h3>
<button class='inline' data-smark='{"action":"removeItem","hotkey":"-","context":"observers"}' title='Less points'><span role='img' aria-label='Remove observation point'>➖</span></button>
<button class='inline' data-smark='{"action":"addItem","hotkey":"+","context":"observers"}' title='More points'><span role='img' aria-label='Add new observation point'>➕</span></button>
</div>
<div class='form-group' data-smark='{"type":"list","name":"observers","sortable":true}'>
<fieldset class='form-group'>
<div class='form-group'>
<label data-smark>Type:</label>
<select data-smark name='type' style='max-width: 12em'>
<option value='tower'>Tower</option>
<option value='station'>Lifeguard Station</option>
<option value='post'>Surveillance Post</option>
<option value='other'>Other</option>
</select>
</div>
<div class='form-group'>
<label data-smark>Color:</label><span data-smark='{"type":"color","name":"color"}'>
<!-- ,'value':'#ffff00' (...won't work here YET)-->
<input data-smark>
<button data-smark='{"action":"clear"}'>❌</button></span>
<!-- input(data-smark='{'type':'color','name':'color','value':'#ffff00'}')-->
<!-- button(data-smark='{'action':'clear','context':'color'}') ❌-->
</div>
<div class='form-group'>
<label data-smark>Name:</label>
<input data-smark type='text' name='name' placeholder='(Optional)'>
</div>
<div class='form-group'>
<label data-smark>Position:</label>
<input data-smark type='text' name='position' placeholder='Latitude, Longitude'>
</div>
<div class='form-group full-width'>
<div style='display: block'>
<div class='input-group'>
<label data-smark='data-smark'>Telephones</label>
<div data-smark='{"name":"phones","type":"list","of":"input","max_items":3}'>
<div class='singleton'>
<button data-smark='{"action":"removeItem","hotkey":"-"}' title='Remove this item'><span role='img' aria-label='Remove this item'>➖</span></button>
<input data-smark='data-smark' type='tel' placeholder='Telephone'/>
<button data-smark='{"action":"addItem","hotkey":"+"}' title='Add new item below'><span role='img' aria-label='Add new item'>➕</span></button>
</div>
</div>
</div>
</div>
<div class='form-group'>
<label data-smark>Indications:</label>
<textarea rows='4' data-smark name='indications' placeholder='Where it is'></textarea>
</div>
</div>
</fieldset>
</div>
</section>
</div>
<div class='form-group aside reverse'>
<button class='inline' data-smark='{"action":"addItem","hotkey":"+","context":"periods"}'><span role='img' alt>➕</span> Add new Period</button>
</div>
<p> </p>
<div class='form-group aside reverse'>
<button class='inline' data-smark='{"action":"export"}'>💾 Submit</button>
<button class='inline' data-smark='{"action":"clear"}'>❌ Clear</button>
</div>
</div>
// Essential:
// ==========
// SmarkForm instantiation:
const myForm = new SmarkForm(document.querySelector("#main-form"));
// Import / Export data handling:
// ==============================
// Do Something on export action:
myForm.on("AfterAction_export"
, ({data})=>alert (JSON.stringify(data, null, 4))
);
// Fetching data on import action (example):
myForm.on("BeforeAction_import", (options) => {
let data = prompt('Provide JSON data');
try {
options.data = JSON.parse(data);
} catch (err) {
if (data.length) {
alert ('⚠️ Invalid JSON!!');
data = null; // Emulate prompt cancel.
} else {
data = {}; // Drop form contents
};
};
if (data === null) options.preventDefault();
});
// Aesthetic enhancements:
// =======================
// Ask for confirm on clear action
myForm.on("BeforeAction_clear", async ({context, preventDefault}) => {
// Ask for confirmation:
if (
context.getPath() == "/" // Only for the whole form
&& ! await context.isEmpty() // Don't even ask if already empty
&& ! confirm("Are you sure?")
) preventDefault(); // Abort if user cancelled
});
// Allow for list items addition/removal CSS animation:
// (Propperly and/remove "animated_item" and "ongoing" CSS classes)
const delay = ms=>new Promise(resolve=>setTimeout(resolve, ms));
myForm.onAll("addItem", function({
newItemTarget, /* the target of the future new item */
onRendered
}) {
newItemTarget.classList.add("animated_item");
onRendered(async (newItem)=>{
await delay(1); /* Allow for default .animated_item style to be applied */
newItem.targetNode.classList.add("ongoing");
/* Here we could have used newItemTarget instead */
});
});
myForm.onAll("removeItem", async function({
oldItemTarget,
onRemmoved
}) {
oldItemTarget.classList.remove("ongoing");
/* Await for transition to be finished before item removal: */
await delay(150);
});
// Essential:
// ==========
// SmarkForm instantiation:
const myForm = new SmarkForm(document.querySelector("#main-form"));
// Import / Export data handling:
// ==============================
// Do Something on export action:
myForm.on("AfterAction_export"
, ({data})=>alert (JSON.stringify(data, null, 4))
);
// Fetching data on import action (example):
myForm.on("BeforeAction_import", (options) => {
let data = prompt('Provide JSON data');
try {
options.data = JSON.parse(data);
} catch (err) {
if (data.length) {
alert ('⚠️ Invalid JSON!!');
data = null; // Emulate prompt cancel.
} else {
data = {}; // Drop form contents
};
};
if (data === null) options.preventDefault();
});
// Aesthetic enhancements:
// =======================
// Ask for confirm on clear action
myForm.on("BeforeAction_clear", async ({context, preventDefault}) => {
// Ask for confirmation:
if (
context.getPath() == "/" // Only for the whole form
&& ! await context.isEmpty() // Don't even ask if already empty
&& ! confirm("Are you sure?")
) preventDefault(); // Abort if user cancelled
});
// Allow for list items addition/removal CSS animation:
// (Propperly and/remove "animated_item" and "ongoing" CSS classes)
const delay = ms=>new Promise(resolve=>setTimeout(resolve, ms));
myForm.onAll("addItem", function({
newItemTarget, /* the target of the future new item */
onRendered
}) {
newItemTarget.classList.add("animated_item");
onRendered(async (newItem)=>{
await delay(1); /* Allow for default .animated_item style to be applied */
newItem.targetNode.classList.add("ongoing");
/* Here we could have used newItemTarget instead */
});
});
myForm.onAll("removeItem", async function({
oldItemTarget,
onRemmoved
}) {
oldItemTarget.classList.remove("ongoing");
/* Await for transition to be finished before item removal: */
await delay(150);
});
// Essential:
// ==========
// SmarkForm instantiation:
const myForm = new SmarkForm(document.querySelector("#main-form"));
// Import / Export data handling:
// ==============================
// Do Something on export action:
myForm.on("AfterAction_export"
, ({data})=>alert (JSON.stringify(data, null, 4))
);
// Fetching data on import action (example):
myForm.on("BeforeAction_import", (options) => {
let data = prompt('Provide JSON data');
try {
options.data = JSON.parse(data);
} catch (err) {
if (data.length) {
alert ('⚠️ Invalid JSON!!');
data = null; // Emulate prompt cancel.
} else {
data = {}; // Drop form contents
};
};
if (data === null) options.preventDefault();
});
// Aesthetic enhancements:
// =======================
// Ask for confirm on clear action
myForm.on("BeforeAction_clear", async ({context, preventDefault}) => {
// Ask for confirmation:
if (
context.getPath() == "/" // Only for the whole form
&& ! await context.isEmpty() // Don't even ask if already empty
&& ! confirm("Are you sure?")
) preventDefault(); // Abort if user cancelled
});
// Allow for list items addition/removal CSS animation:
// (Propperly and/remove "animated_item" and "ongoing" CSS classes)
const delay = ms=>new Promise(resolve=>setTimeout(resolve, ms));
myForm.onAll("addItem", function({
newItemTarget, /* the target of the future new item */
onRendered
}) {
newItemTarget.classList.add("animated_item");
onRendered(async (newItem)=>{
await delay(1); /* Allow for default .animated_item style to be applied */
newItem.targetNode.classList.add("ongoing");
/* Here we could have used newItemTarget instead */
});
});
myForm.onAll("removeItem", async function({
oldItemTarget,
onRemmoved
}) {
oldItemTarget.classList.remove("ongoing");
/* Await for transition to be finished before item removal: */
await delay(150);
});
// Essential:
// ==========
// SmarkForm instantiation:
const myForm = new SmarkForm(document.querySelector("#main-form"));
// Import / Export data handling:
// ==============================
// Do Something on export action:
myForm.on("AfterAction_export"
, ({data})=>alert (JSON.stringify(data, null, 4))
);
// Fetching data on import action (example):
myForm.on("BeforeAction_import", (options) => {
let data = prompt('Provide JSON data');
try {
options.data = JSON.parse(data);
} catch (err) {
if (data.length) {
alert ('⚠️ Invalid JSON!!');
data = null; // Emulate prompt cancel.
} else {
data = {}; // Drop form contents
};
};
if (data === null) options.preventDefault();
});
// Aesthetic enhancements:
// =======================
// Ask for confirm on clear action
myForm.on("BeforeAction_clear", async ({context, preventDefault}) => {
// Ask for confirmation:
if (
context.getPath() == "/" // Only for the whole form
&& ! await context.isEmpty() // Don't even ask if already empty
&& ! confirm("Are you sure?")
) preventDefault(); // Abort if user cancelled
});
// Allow for list items addition/removal CSS animation:
// (Propperly and/remove "animated_item" and "ongoing" CSS classes)
const delay = ms=>new Promise(resolve=>setTimeout(resolve, ms));
myForm.onAll("addItem", function({
newItemTarget, /* the target of the future new item */
onRendered
}) {
newItemTarget.classList.add("animated_item");
onRendered(async (newItem)=>{
await delay(1); /* Allow for default .animated_item style to be applied */
newItem.targetNode.classList.add("ongoing");
/* Here we could have used newItemTarget instead */
});
});
myForm.onAll("removeItem", async function({
oldItemTarget,
onRemmoved
}) {
oldItemTarget.classList.remove("ongoing");
/* Await for transition to be finished before item removal: */
await delay(150);
});