Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mapp.ui.elements.alert/ confirm methods #1484

Merged
merged 42 commits into from
Sep 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
1b5eb34
mapp.ui.elements.alert method;
cityremade Sep 18, 2024
59003a3
Alert - now uses dictionary.
cityremade Sep 18, 2024
d7f2a43
mapp.ui.elements.confirm
cityremade Sep 18, 2024
a6ea29c
alert css - moved to ui stylesheet.
cityremade Sep 19, 2024
3e4121d
Confirm - css from ui stylesheet;
cityremade Sep 19, 2024
b53da60
Alert - media queries added;
cityremade Sep 19, 2024
fe7374b
Alert changes;
cityremade Sep 23, 2024
74dc8fe
Merge branch 'main' into mapp_ui_elements_alert
cityremade Sep 23, 2024
7366022
Alert - issues addressed;
cityremade Sep 23, 2024
d521f64
Confirm using dialog ui element;
cityremade Sep 23, 2024
d35ace9
Merge branch 'main' into mapp_ui_elements_confirm
cityremade Sep 23, 2024
0ff9f96
Confirm dialog included;
cityremade Sep 23, 2024
411b0ed
format /ui/elements/confirm
dbauszus-glx Sep 23, 2024
f02e480
Merge branch 'main' into mapp_ui_elements_alert
dbauszus-glx Sep 24, 2024
8d4cb31
Fix for unsaved changes exit;
cityremade Sep 24, 2024
0581da7
Class renamed;
cityremade Sep 24, 2024
65320f8
View - exiting unsaved changes fix;
cityremade Sep 24, 2024
96d716c
Merge branch 'main' into mapp_ui_elements_alert
simon-leech Sep 25, 2024
22d06e0
Information Term to a dictionary definition
simon-leech Sep 25, 2024
da03a8a
Confirm Term to a dictionary definition; OK button on the left not right
simon-leech Sep 25, 2024
02670c5
Slider Test - correct spelling
simon-leech Sep 25, 2024
811e629
New Alert and Confirm Tests
simon-leech Sep 25, 2024
d6fa376
update dialog construction
dbauszus-glx Sep 25, 2024
a3380d9
remove double property
dbauszus-glx Sep 25, 2024
5de6c6d
remove empty row
dbauszus-glx Sep 25, 2024
5540bad
remove test alert
dbauszus-glx Sep 25, 2024
e4167c5
Merge branch 'main' into pr/cityremade/1484
RobAndrewHurst Sep 25, 2024
5adf408
Dialog test
RobAndrewHurst Sep 25, 2024
0731ca9
Merge branch 'main' into mapp_ui_elements_alert
cityremade Sep 26, 2024
49d55e2
Requested changes to close function;
cityremade Sep 26, 2024
6afc699
test updates
RobAndrewHurst Sep 27, 2024
e218095
Merge branch 'main' into pr/cityremade/1484
RobAndrewHurst Sep 27, 2024
eb8e76a
Click propagation changes;
cityremade Sep 27, 2024
529586a
Merge branch 'main' into mapp_ui_elements_alert
cityremade Sep 27, 2024
b99beb5
Merge branch 'main' into mapp_ui_elements_alert
dbauszus-glx Sep 27, 2024
7bb0b49
closeBtn
dbauszus-glx Sep 27, 2024
6fe6ead
propagation rodeo
dbauszus-glx Sep 27, 2024
320d826
Update tests
RobAndrewHurst Sep 27, 2024
800aab7
Update dialog test
RobAndrewHurst Sep 27, 2024
5d0a22f
close dialog
dbauszus-glx Sep 27, 2024
a360f2a
Merge branch 'mapp_ui_elements_alert' of https://github.com/cityremad…
dbauszus-glx Sep 27, 2024
21d4c7d
dialog.node.remove
dbauszus-glx Sep 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions lib/dictionaries/en.mjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
export default {
save: 'Save',
cancel: 'Cancel',
ok: 'OK',
confirm: 'Confirm',
information: 'Information',
confirm_delete: 'Are you sure you want to delete this feature? This cannot be undone.',
invalid_geometry: 'Invalid geometry',
no_results: 'No results for this search',
Expand Down
4 changes: 3 additions & 1 deletion lib/location/decorate.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,9 @@ function flyTo(maxZoom) {

async function trash() {

if (!confirm(mapp.dictionary.confirm_delete)) return;
const confirm = await mapp.ui.elements.confirm({text: mapp.dictionary.confirm_delete})

if (!confirm) return;

await mapp.utils.xhr(`${this.layer.mapview.host}/api/query?` +
mapp.utils.paramString({
Expand Down
6 changes: 6 additions & 0 deletions lib/ui/elements/_elements.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import dropdown_multi from './dropdown_multi.mjs';
import btnPanel from './btnPanel.mjs';
import legendIcon from './legendIcon.mjs';
import dialog from './dialog.mjs';
import alert from './alert.mjs';
import confirm from './confirm.mjs';
import helpDialog from './helpDialog.mjs';
import searchbox from './searchbox.mjs';
import slider from './slider.mjs';
Expand All @@ -35,6 +37,8 @@ UI elements object containing various UI components.
@property {Function} dropdown_multi - Multi-select dropdown component.
@property {Function} legendIcon - Legend icon component.
@property {Function} dialog - Dialog component.
@property {Function} alert - Alert component.
@property {Function} confirm - Confirm component.
@property {Function} helpDialog - Help Dialog component.
@property {Function} searchbox - Searchbox component.
@property {Function} slider - Slider component.
Expand All @@ -57,6 +61,8 @@ export default {
layerStyle,
legendIcon,
dialog,
alert,
confirm,
pills,
helpDialog,
searchbox,
Expand Down
52 changes: 52 additions & 0 deletions lib/ui/elements/alert.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/**
### /ui/elements/alert

Exports the alert dialog method as mapp.ui.elements.alert()

@requires /ui/elements/dialog

@module /ui/elements/alert
*/

/**
@function alert

@description
This is an alert element to display information to the user.

It is a framework alternative way to using window.alert() browser function.

```js
mapp.ui.elements.alert({
text: "Drivetimes have been created."
})
```
@param {Object} params Params for the alert dialog.
@property {string} [params.data_id='alert'] The data-id attribute value for the dialog.
@property {string} [params.title] Text to display in the alert header. Defaults to 'Information'.
@property {string} [params.text] Text to display in the alert content.
@returns {HTMLElement} alert The alert element.
*/
export default function alert(params) {

params.title ??= `${mapp.dictionary.information}`;

params.data_id ??= 'alert'

params.class ??= 'alert-confirm'

params.header = mapp.utils.html`
<h4>${params.title}`

params.content = mapp.utils.html`
<p>${params.text}</p>
<div class="buttons">
<button
class="raised primary-colour bold"
style="grid-column: 1/3; margin: 0 5em;"
onclick=${e => {
e.target.closest('dialog').close();
}}>${mapp.dictionary.ok}`

return mapp.ui.elements.dialog(params)
}
72 changes: 72 additions & 0 deletions lib/ui/elements/confirm.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/**
## /ui/elements/confirm

Exports the confirm dialog method as mapp.ui.elements.confirm()

@requires /ui/elements/dialog

@module /ui/elements/confirm
*/

/**
@function confirm

@description
This is a confirm element to display information to the user and resolving to yes/no response.

It is a framework alternative way to using window.confirm() browser function.

```js
const confirm = await mapp.ui.elements.confirm({
text: "Please confim changes."
})
if(confirm) {
// proceed
} else {
// prevent
}
```

@param {Object} params Params for the configuration dialog.
@property {string} [params.data_id='confirm'] The data-id attribute value for the dialog.
@property {string} [params.title] Text to display in the confirm header. Defaults to 'Confirm'.
@property {string} [params.text] Text to display in the confirm content.
@returns {Promise<boolean>} Returns promise which resolves to true or false whether the question was confirmed.
*/
export default function confirm(params) {

return new Promise((resolve, reject) => {

params.title ??= `${mapp.dictionary.confirm}`;

params.data_id ??= 'confirm'

params.header = mapp.utils.html`<h4>${params.title}`

const btn_true = mapp.utils.html`<button
onclick=${e => {
e.target.closest('dialog').close();
resolve(true);
}}
class="raised primary-colour bold">
${mapp.dictionary.ok}`;

const btn_false = mapp.utils.html`<button
onclick=${e => {
e.target.closest('dialog').close();
resolve(false);
}}
class="raised primary-colour bold">
${mapp.dictionary.cancel}`

params.content ??= mapp.utils.html`
<p>${params.text}</p>
<div class="buttons">
${btn_true}
${btn_false}`

params.class ??= 'alert-confirm'

mapp.ui.elements.dialog(params)
});
}
60 changes: 34 additions & 26 deletions lib/ui/elements/dialog.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,16 @@ const dialog = mapp.ui.elements.dialog({
@property {string} [dialog.header] The HTML content for the dialog header.
@property {string} [dialog.content] The HTML content for the dialog body.
@property {boolean} [dialog.modal] A flag to determine if its a Modal or Dialog.
@property {Function} [dialog.close] A function to be called when the dialog is closed. Boolean to indicate whether there should be a close method.
@property {boolean} [dialog.closeBtn] The flag property will become the closeBtn element.
@property {Function} [dialog.close] A function called by default when the dialog is closed. The dialog element is closed and removed from DOM.
@property {Function} [dialog.onClose] Optional function to run after dialog element is closed - uses onclose dialog event and overrides dialog.close().
@property {number} [dialog.top] The top position of the dialog.
@property {number} [dialog.left] The left position of the dialog.
@property {number} [dialog.right] The right position of the dialog (used to calculate left position).
@property {boolean} [dialog.contained] A flag indicating whether to keep the dialog within the target element's boundaries.
@property {boolean} [dialog.containedCentre] A flag indicating whether to keep the dialog centered within the target element's boundaries.
@property {boolean} [dialog.headerDrag] A flag indicating whether the dialog can be dragged only by the header.By default, the dialog can be dragged from anywhere.
@returns {HTMLElement} dialog.node The dialog element.
@returns {Object} Decorated dialog configuration object
*/

export default function dialog(dialog) {
Expand All @@ -47,35 +49,45 @@ export default function dialog(dialog) {
// The dialog must be modal if no target is provided.
dialog.modal = true;

// Ensure the target is an HTMLElement before proceeding
// Ensure the target is an HTMLElement before proceeding
} else if (!(dialog.target instanceof HTMLElement)) return;

// Close existing modal.
document.querySelector('dialog.modal')?.close()

dialog.closeBtn ??= dialog.close && mapp.utils.html.node`
<button
data-id=close
class="mask-icon close"
onclick=${closeDialog}>`

dialog.data_id ??= 'dialog'

// If headerDrag is true - add the headerDrag class to the dialog header
dialog.headerDrag && (dialog.header = mapp.utils.html.node`<header class="headerDrag">${dialog.header}</header>`);
if (dialog.headerDrag) {

let classList = `${dialog.modal ? 'modal' : 'dialog'} ${dialog.class || ''}`
dialog.header = mapp.utils.html.node`
<header class="headerDrag">${dialog.header}`
}

dialog.node = mapp.utils.html.node`
<dialog
style=${dialog.css_style}
data-id=${dialog.data_id}
class="${classList}">
${dialog.closeBtn}
${dialog.header}
${dialog.content}`
const classList = `${dialog.modal ? 'modal' : 'dialog'} ${dialog.class || ''}`

function closeDialog(e) {
if (dialog.onClose instanceof Function) {
dialog.onClose(e)
}
dialog.node.remove()
}

dialog.close = closeDialog

dialog.closeBtn &&= mapp.utils.html`<button
data-id=close
class="mask-icon close"
onclick=${closeDialog}>`

dialog.node = mapp.utils.html.node`<dialog
onclose=${closeDialog}
style=${dialog.css_style}
data-id=${dialog.data_id}
class="${classList}">
${dialog.closeBtn}
${dialog.header}
${dialog.content}`

if (dialog.modal) {

document.body.append(dialog.node)
Expand Down Expand Up @@ -103,12 +115,6 @@ export default function dialog(dialog) {
resizeObserver.observe(dialog.target);
}

// Function to handle the dialog closure
function closeDialog() {
if (dialog.close instanceof Function) dialog.close()
dialog.node.close();
}

// Function to handle the start of a drag event, setting up the necessary event listeners for moving and ending the drag
function handleStartEvent(e) {

Expand Down Expand Up @@ -200,6 +206,8 @@ export default function dialog(dialog) {
// top shift
dialog.node.style.top = `${dialog.node.offsetTop + topShift}px`
}

return dialog
};

/**
Expand Down
5 changes: 4 additions & 1 deletion lib/ui/locations/entries/cloudinary.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ mapp.utils.merge(mapp.dictionaries, {
en: {
image_upload_failed: 'Image upload failed.',
document_upload_failed: 'Document upload failed.',
remove_item_confirm: 'Remove item?'
},
de: {
image_upload_failed: 'Hochladen des Bildes gescheitert.',
Expand Down Expand Up @@ -275,7 +276,9 @@ async function docLoad(e, entry) {

async function trash(e, entry) {

if (!confirm('Remove item?')) return;
const confirm = await mapp.ui.elements.confirm({text: mapp.dictionary.remove_item_confirm});

if (!confirm) return;

// Send request to cloudinary to destroy resource.
await mapp.utils.xhr(`${entry.location.layer.mapview.host}/api/provider/cloudinary?${mapp.utils.paramString({
Expand Down
49 changes: 32 additions & 17 deletions lib/ui/locations/view.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -147,17 +147,29 @@ export default function view(location) {

// Clear selection.
header.push(mapp.utils.html`<button
title = ${mapp.dictionary.location_remove}
class = "mask-icon close no"
onclick = ${() => {
title= ${mapp.dictionary.location_remove}
class= "mask-icon close no"
onclick= ${location_remove}>`)

if (location.infoj.some(entry => typeof entry.newValue !== 'undefined')) {
/**
@function location_remove

if (!confirm(`${mapp.dictionary.location_close_without_save}`)) return;
}
@description
The method checks whether a location.infoj has some unsaved changes. A confirm dialog will be shown to confirm the location.remove() without saving changes.
*/
async function location_remove() {

const changesUnsaved = location.infoj.some(entry => typeof entry.newValue !== 'undefined');

location.remove()
}}>`)
if(changesUnsaved) {

const confirm = await mapp.ui.elements.confirm({text: mapp.dictionary.location_close_without_save})

if (!confirm) return;
}

location.remove()
}

location.view = mapp.ui.elements.drawer({
class: 'location-view raised expanded',
Expand Down Expand Up @@ -262,21 +274,23 @@ function toggleLocationViewEdits(location) {
*/
async function onClickEditToggle(e) {

// There are edits to be saved.
if (location.infoj.some(entry => typeof entry.newValue !== 'undefined')
// Check for unsaved edits
const unsavedChanges = location.infoj.some(entry => typeof entry.newValue !== 'undefined');

// Confirm whether to save edits.
&& confirm(mapp.dictionary.location_save_changes)) {
if(unsavedChanges) {
// There are edits to be saved.
const confirm = await mapp.ui.elements.confirm({text: mapp.dictionary.location_save_changes})

const update = await location.update()
if(confirm) {

// The update may err due to invalid entries.
if (update instanceof Error) {
const update = await location.update()

// The update may err due to invalid entries.
if (update instanceof Error) return;

return;
}


// There are no unsaved edits.
} else if (e.target.classList.toggle('on')) {

// Button is toggled on.
Expand All @@ -287,6 +301,7 @@ function toggleLocationViewEdits(location) {
// Button is toggled off.
location.removeEdits()
location.view.querySelector('.btn-save').style.display = 'none'

}

location.renderLocationView()
Expand Down
Loading
Loading