2
0
Эх сурвалжийг харах

modal: Add ability to show multiple input fields for confirm modal

JC Brand 5 жил өмнө
parent
commit
16c58a966a

+ 1 - 0
CHANGES.md

@@ -31,6 +31,7 @@ Soon we'll deprecate the latter, so prepare now.
   [discover_connection_methods](https://conversejs.org/docs/html/configuration.html#discover-connection-methods) now has a default value of `true`).
 - [show_send_button](https://conversejs.org/docs/html/configuration.html#show-send-button) now has a default value of `true`.
 - New configuration setting [muc_hats_from_vcard](https://conversejs.org/docs/html/configuration.html#muc-hats-from-vcard).
+- The [api.confirm](https://conversejs.org/docs/html/api/-_converse.api.html#.confirm) method now accepts a list of fields and returns the filled in list upon confirmation.
 
 ## 6.0.0 (2020-01-09)
 

+ 49 - 52
src/converse-modal.js

@@ -115,23 +115,26 @@ export const Confirm = BootstrapModal.extend({
         }
     },
 
-    onConfimation (ev) {
-        ev.preventDefault();
-        this.confirmation.resolve(true);
-        this.modal.hide();
-    }
-});
-
-
-export const Prompt = Confirm.extend({
-    toHTML () {
-        return tpl_prompt(this.model.toJSON());
-    },
-
     onConfimation (ev) {
         ev.preventDefault();
         const form_data = new FormData(ev.target);
-        this.confirmation.resolve(form_data.get('reason'));
+        const fields = (this.model.get('fields') || [])
+            .map(field => {
+                const value = form_data.get(field.name).trim();
+                field.value = value;
+                if (field.challenge) {
+                    field.challenge_failed = (value !== field.challenge);
+                }
+                return field;
+            });
+
+        if (fields.filter(c => c.challenge_failed).length) {
+            this.model.set('fields', fields);
+            // Setting an array doesn't trigger a change event
+            this.model.trigger('change');
+            return;
+        }
+        this.confirmation.resolve(fields);
         this.modal.hide();
     }
 });
@@ -165,7 +168,7 @@ converse.plugins.add('converse-modal', {
 
         /************************ BEGIN API ************************/
         // We extend the default converse.js API to add methods specific to MUC chat rooms.
-        let alert, prompt, confirm;
+        let alert;
 
         Object.assign(_converse.api, {
             /**
@@ -173,33 +176,30 @@ converse.plugins.add('converse-modal', {
              * @method _converse.api.confirm
              * @param { String } title - The header text for the confirmation dialog
              * @param { (String[]|String) } messages - The text to show to the user
-             * @returns { Promise } A promise which resolves with true or false
+             * @param { Array<Field> } fields - An object representing a fields presented to the user.
+             * @property { String } Field.label - The form label for the input field.
+             * @property { String } Field.name - The name for the input field.
+             * @property { String } [Field.challenge] - A challenge value that must be provided by the user.
+             * @property { String } [Field.placeholder] - The placeholder for the input field.
+             * @property { Boolean} [Field.required] - Whether the field is required or not
+             * @returns { Promise<Array|false> } A promise which resolves with an array of
+             *  filled in fields or `false` if the confirm dialog was closed or canceled.
              */
-            async confirm (title, messages=[]) {
+            async confirm (title, messages=[], fields=[]) {
                 if (isString(messages)) {
                     messages = [messages];
                 }
-                if (confirm === undefined) {
-                    const model = new Model({
-                        'title': title,
-                        'messages': messages,
-                        'type': 'confirm'
-                    })
-                    confirm = new Confirm({model});
-                } else {
-                    confirm.confirmation = u.getResolveablePromise();
-                    confirm.model.set({
-                        'title': title,
-                        'messages': messages,
-                        'type': 'confirm'
-                    });
-                }
+                const model = new Model({title, messages, fields, 'type': 'confirm'})
+                const confirm = new Confirm({model});
                 confirm.show();
+                let result;
                 try {
-                    return await confirm.confirmation;
+                    result = await confirm.confirmation;
                 } catch (e) {
-                    return false;
+                    result = false;
                 }
+                confirm.remove();
+                return result;
             },
 
             /**
@@ -208,35 +208,32 @@ converse.plugins.add('converse-modal', {
              * @param { String } title - The header text for the prompt
              * @param { (String[]|String) } messages - The prompt text to show to the user
              * @param { String } placeholder - The placeholder text for the prompt input
-             * @returns { Promise } A promise which resolves with the text provided by the
+             * @returns { Promise<String|false> } A promise which resolves with the text provided by the
              *  user or `false` if the user canceled the prompt.
              */
             async prompt (title, messages=[], placeholder='') {
                 if (isString(messages)) {
                     messages = [messages];
                 }
-                if (prompt === undefined) {
-                    const model = new Model({
-                        'title': title,
-                        'messages': messages,
+                const model = new Model({
+                    title,
+                    messages,
+                    'fields': [{
+                        'name': 'reason',
                         'placeholder': placeholder,
-                        'type': 'prompt'
-                    })
-                    prompt = new Prompt({model});
-                } else {
-                    prompt.confirmation = u.getResolveablePromise();
-                    prompt.model.set({
-                        'title': title,
-                        'messages': messages,
-                        'type': 'prompt'
-                    });
-                }
+                    }],
+                    'type': 'prompt'
+                })
+                const prompt = new Confirm({model});
                 prompt.show();
+                let result;
                 try {
-                    return await prompt.confirmation;
+                    result = (await prompt.confirmation).pop()?.value;
                 } catch (e) {
-                    return false;
+                    result = false;
                 }
+                prompt.remove();
+                return result;
             },
 
             /**

+ 11 - 4
src/templates/prompt.js

@@ -6,9 +6,16 @@ const i18n_cancel = __('Cancel');
 const i18n_ok = __('OK');
 
 
-const tpl_reason = (o) => html`
+const tpl_field = (f) => html`
     <div class="form-group">
-        <input type="text" name="reason" class="form-control" placeholder="${o.placeholder}"/>
+        <label>
+            ${f.label || ''}
+            <input type="text"
+                name="${f.name}"
+                class="${(f.challenge_failed) ? 'error' : ''} form-control form-control--labeled"
+                ?required="${f.required}"
+                placeholder="${f.placeholder}" />
+        </label>
     </div>
 `;
 
@@ -16,7 +23,7 @@ const tpl_reason = (o) => html`
 export default (o) => html`
     <div class="modal-dialog" role="document">
       <div class="modal-content">
-        <div class="modal-header ${o.level}">
+        <div class="modal-header ${o.level || ''}">
           <h5 class="modal-title">${o.title}</h5>
           <button type="button" class="close" data-dismiss="modal" aria-label="Close">
             <span aria-hidden="true">×</span>
@@ -28,7 +35,7 @@ export default (o) => html`
               <div class="form-group">
                   ${ o.messages.map(message => html`<p>${message}</p>`) }
               </div>
-              ${ (o.type === 'prompt') ? tpl_reason(o) : '' }
+              ${ o.fields.map(f => tpl_field(f)) }
               <div class="form-group">
                   <button type="submit" class="btn btn-primary">${i18n_ok}</button>
                   <input type="button" class="btn btn-secondary" data-dismiss="modal" value="${i18n_cancel}"/>