diff --git a/applications/luci-app-opkg/htdocs/luci-static/resources/view/opkg.js b/applications/luci-app-opkg/htdocs/luci-static/resources/view/opkg.js
index bb21cca68780..053d74729f15 100644
--- a/applications/luci-app-opkg/htdocs/luci-static/resources/view/opkg.js
+++ b/applications/luci-app-opkg/htdocs/luci-static/resources/view/opkg.js
@@ -886,7 +886,7 @@ function handleConfig(ev)
}, '%h'.format(conf[file])));
});
- body.push(E('div', { 'class': 'right' }, [
+ body.push(E('div', { 'class': 'button-row' }, [
E('div', {
'class': 'btn cbi-button-neutral',
'click': ui.hideModal
@@ -1012,7 +1012,7 @@ function handleOpkg(ev)
if (res.code !== 0)
dlg.appendChild(E('p', _('The opkg %h command failed with code %d
.').format(cmd, (res.code & 0xff) || -1)));
- dlg.appendChild(E('div', { 'class': 'right' },
+ dlg.appendChild(E('div', { 'class': 'button-row' },
E('div', {
'class': 'btn',
'click': L.bind(function(res) {
diff --git a/modules/luci-base/htdocs/luci-static/resources/form.js b/modules/luci-base/htdocs/luci-static/resources/form.js
index 889f6edd8dcd..c6d2445a5583 100644
--- a/modules/luci-base/htdocs/luci-static/resources/form.js
+++ b/modules/luci-base/htdocs/luci-static/resources/form.js
@@ -3218,13 +3218,13 @@ var CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.p
else {
ui.showModal(title, [
nodes,
- E('div', { 'class': 'right' }, [
+ E('div', { 'class': 'button-row' }, [
E('button', {
- 'class': 'cbi-button',
+ 'class': 'btn cbi-button',
'click': ui.createHandlerFn(this, 'handleModalCancel', m)
}, [ _('Dismiss') ]), ' ',
E('button', {
- 'class': 'cbi-button cbi-button-positive important',
+ 'class': 'btn cbi-button cbi-button-positive important',
'click': ui.createHandlerFn(this, 'handleModalSave', m),
'disabled': m.readonly || null
}, [ _('Save') ])
diff --git a/modules/luci-base/htdocs/luci-static/resources/ui.js b/modules/luci-base/htdocs/luci-static/resources/ui.js
index 0e395cea20c1..7945833fe539 100644
--- a/modules/luci-base/htdocs/luci-static/resources/ui.js
+++ b/modules/luci-base/htdocs/luci-static/resources/ui.js
@@ -3626,7 +3626,7 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ {
/** @private */
cancelModal: function(ev) {
if (ev.key == 'Escape') {
- var btn = modalDiv.querySelector('.right > button, .right > .btn');
+ var btn = modalDiv.querySelector('.right > button, .right > .btn, .button-row > .btn');
if (btn)
btn.click();
@@ -4209,99 +4209,94 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ {
return new Promise(function(resolveFn, rejectFn) {
UI.prototype.showModal(_('Uploading file…'), [
E('p', _('Please select the file to upload.')),
- E('div', { 'style': 'display:flex' }, [
- E('div', { 'class': 'left', 'style': 'flex:1' }, [
- E('input', {
- type: 'file',
- style: 'display:none',
- change: function(ev) {
- var modal = dom.parent(ev.target, '.modal'),
- body = modal.querySelector('p'),
- upload = modal.querySelector('.cbi-button-action.important'),
- file = ev.currentTarget.files[0];
-
- if (file == null)
- return;
-
- dom.content(body, [
- E('ul', {}, [
- E('li', {}, [ '%s: %s'.format(_('Name'), file.name.replace(/^.*[\\\/]/, '')) ]),
- E('li', {}, [ '%s: %1024mB'.format(_('Size'), file.size) ])
- ])
- ]);
-
- upload.disabled = false;
- upload.focus();
- }
- }),
- E('button', {
- 'class': 'btn',
- 'click': function(ev) {
- ev.target.previousElementSibling.click();
- }
- }, [ _('Browse…') ])
- ]),
- E('div', { 'class': 'right', 'style': 'flex:1' }, [
- E('button', {
- 'class': 'btn',
- 'click': function() {
+ E('div', { 'class': 'button-row' }, [
+ E('div', {
+ 'class': 'btn cbi-button',
+ 'click': function() {
+ UI.prototype.hideModal();
+ rejectFn(new Error(_('Upload has been cancelled')));
+ }
+ }, [ _('Cancel') ]),
+ E('input', {
+ type: 'file',
+ style: 'display:none',
+ change: function(ev) {
+ var modal = dom.parent(ev.target, '.modal'),
+ body = modal.querySelector('p'),
+ upload = modal.querySelector('.cbi-button-action.important'),
+ file = ev.currentTarget.files[0];
+
+ if (file == null)
+ return;
+
+ dom.content(body, [
+ E('ul', {}, [
+ E('li', {}, [ '%s: %s'.format(_('Name'), file.name.replace(/^.*[\\\/]/, '')) ]),
+ E('li', {}, [ '%s: %1024mB'.format(_('Size'), file.size) ])
+ ])
+ ]);
+
+ upload.disabled = false;
+ upload.focus();
+ }
+ }),
+ E('div', {
+ 'class': 'btn cbi-button',
+ 'click': function(ev) {
+ ev.target.previousElementSibling.click();
+ }
+ }, [ _('Browse…') ]),
+ E('div', {
+ 'class': 'btn cbi-button-action important',
+ 'disabled': true,
+ 'click': function(ev) {
+ var input = dom.parent(ev.target, '.modal').querySelector('input[type="file"]');
+
+ if (!input.files[0])
+ return;
+
+ var progress = E('div', { 'class': 'cbi-progressbar', 'title': '0%' }, E('div', { 'style': 'width:0' }));
+
+ UI.prototype.showModal(_('Uploading file…'), [ progress ]);
+
+ var data = new FormData();
+
+ data.append('sessionid', rpc.getSessionID());
+ data.append('filename', path);
+ data.append('filedata', input.files[0]);
+
+ var filename = input.files[0].name;
+
+ request.post(L.env.cgi_base + '/cgi-upload', data, {
+ timeout: 0,
+ progress: function(pev) {
+ var percent = (pev.loaded / pev.total) * 100;
+
+ if (progressStatusNode)
+ progressStatusNode.data = '%.2f%%'.format(percent);
+
+ progress.setAttribute('title', '%.2f%%'.format(percent));
+ progress.firstElementChild.style.width = '%.2f%%'.format(percent);
+ }
+ }).then(function(res) {
+ var reply = res.json();
+
UI.prototype.hideModal();
- rejectFn(new Error(_('Upload has been cancelled')));
- }
- }, [ _('Cancel') ]),
- ' ',
- E('button', {
- 'class': 'btn cbi-button-action important',
- 'disabled': true,
- 'click': function(ev) {
- var input = dom.parent(ev.target, '.modal').querySelector('input[type="file"]');
-
- if (!input.files[0])
- return;
-
- var progress = E('div', { 'class': 'cbi-progressbar', 'title': '0%' }, E('div', { 'style': 'width:0' }));
-
- UI.prototype.showModal(_('Uploading file…'), [ progress ]);
-
- var data = new FormData();
-
- data.append('sessionid', rpc.getSessionID());
- data.append('filename', path);
- data.append('filedata', input.files[0]);
-
- var filename = input.files[0].name;
-
- request.post(L.env.cgi_base + '/cgi-upload', data, {
- timeout: 0,
- progress: function(pev) {
- var percent = (pev.loaded / pev.total) * 100;
-
- if (progressStatusNode)
- progressStatusNode.data = '%.2f%%'.format(percent);
-
- progress.setAttribute('title', '%.2f%%'.format(percent));
- progress.firstElementChild.style.width = '%.2f%%'.format(percent);
- }
- }).then(function(res) {
- var reply = res.json();
-
- UI.prototype.hideModal();
-
- if (L.isObject(reply) && reply.failure) {
- UI.prototype.addNotification(null, E('p', _('Upload request failed: %s').format(reply.message)));
- rejectFn(new Error(reply.failure));
- }
- else {
- reply.name = filename;
- resolveFn(reply);
- }
- }, function(err) {
- UI.prototype.hideModal();
- rejectFn(err);
- });
- }
- }, [ _('Upload') ])
- ])
+
+ if (L.isObject(reply) && reply.failure) {
+ UI.prototype.addNotification(null, E('p', _('Upload request failed: %s').format(reply.message)));
+ rejectFn(new Error(reply.failure));
+ }
+ else {
+ reply.name = filename;
+ resolveFn(reply);
+ }
+ }, function(err) {
+ UI.prototype.hideModal();
+ rejectFn(err);
+ });
+ }
+ }, [ _('Upload') ])
])
]);
});
@@ -4480,26 +4475,29 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ {
E('var', {}, E('ins', ' ')), ' ', _('Option changed') ]),
E('div', { 'class': 'uci-change-legend-label' }, [
E('var', {}, E('del', ' ')), ' ', _('Option removed') ])]),
- E('br'), list,
- E('div', { 'class': 'right' }, [
- E('button', {
- 'class': 'btn',
- 'click': UI.prototype.hideModal
- }, [ _('Close') ]), ' ',
- new UIComboButton('0', {
- 0: [ _('Save & Apply') ],
- 1: [ _('Apply unchecked') ]
- }, {
- classes: {
- 0: 'btn cbi-button cbi-button-positive important',
- 1: 'btn cbi-button cbi-button-negative important'
- },
- click: L.bind(function(ev, mode) { this.apply(mode == '0') }, this)
- }).render(), ' ',
- E('button', {
- 'class': 'cbi-button cbi-button-reset',
- 'click': L.bind(this.revert, this)
- }, [ _('Revert') ])])])
+ E('br'),
+ list,
+ ]),
+ E('div', { 'class': 'button-row' }, [
+ E('div', {
+ 'class': 'btn cbi-button',
+ 'click': UI.prototype.hideModal
+ }, [ _('Close') ]), ' ',
+ new UIComboButton('0', {
+ 0: [ _('Save & Apply') ],
+ 1: [ _('Apply unchecked') ]
+ }, {
+ classes: {
+ 0: 'btn cbi-button cbi-button-positive important',
+ 1: 'btn cbi-button cbi-button-negative important'
+ },
+ click: L.bind(function(ev, mode) { this.apply(mode == '0') }, this)
+ }).render(), ' ',
+ E('div', {
+ 'class': 'btn cbi-button cbi-button-reset',
+ 'click': L.bind(this.revert, this)
+ }, [ _('Revert') ])
+ ])
]);
for (var config in this.changes) {
@@ -4732,22 +4730,20 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ {
UI.prototype.changes.displayStatus('warning', [
E('h4', _('Connectivity change')),
- E('p', _('"%h" interface changes could inhibit access to this device.').format(affected)),
- E('p', _('Any IP change requires connecting to the new IP within %d seconds to retain the changes.').format(L.env.apply_rollback)),
- E('p', _('Choose how to apply changes:')),
- E('div', { 'class': 'right' }, [
- E('button', {
- 'class': 'btn',
+ E('p', _('Changes have been made to the existing connection via "%h". This could inhibit access to this device. Any IP change requires connecting to the new IP within %d seconds to retain the changes.').format(affected, L.env.apply_rollback)),
+ E('div', { 'class': 'button-row' }, [
+ E('div', {
+ 'class': 'btn cbi-button',
'click': rejectFn,
}, [ _('Cancel') ]), ' ',
- E('button', {
+ E('div', {
'class': 'btn cbi-button-action important',
'click': resolveFn.bind(null, true)
- }, [ _('Apply, reverting if GUI remains unreachable') ]), ' ',
- E('button', {
+ }, [ _('Apply, reverting in case of connectivity loss') ]), ' ',
+ E('div', {
'class': 'btn cbi-button-negative important',
'click': resolveFn.bind(null, false)
- }, [ _('Apply, committing now') ])
+ }, [ _('Apply unchecked') ])
])
]);
});
diff --git a/modules/luci-mod-network/htdocs/luci-static/resources/view/network/interfaces.js b/modules/luci-mod-network/htdocs/luci-static/resources/view/network/interfaces.js
index 35bb21b8faa3..71e97a7fffc6 100644
--- a/modules/luci-mod-network/htdocs/luci-static/resources/view/network/interfaces.js
+++ b/modules/luci-mod-network/htdocs/luci-static/resources/view/network/interfaces.js
@@ -175,9 +175,9 @@ function iface_updown(up, id, ev, force) {
ui.showModal(_('Confirm disconnect'), [
E('p', _('You appear to be currently connected to the device via the "%h" interface. Do you really want to shut down the interface?').format(id)),
- E('div', { 'class': 'right' }, [
- E('button', {
- 'class': 'cbi-button cbi-button-neutral',
+ E('div', { 'class': 'button-row' }, [
+ E('div', {
+ 'class': 'btn cbi-button cbi-button-neutral',
'click': function(ev) {
btns[1].classList.remove('spinning');
btns[1].disabled = false;
@@ -187,8 +187,8 @@ function iface_updown(up, id, ev, force) {
}
}, _('Cancel')),
' ',
- E('button', {
- 'class': 'cbi-button cbi-button-negative important',
+ E('div', {
+ 'class': 'btn cbi-button cbi-button-negative important',
'click': function(ev) {
dsc.setAttribute('disconnect', '');
dom.content(dsc, E('em', _('Interface is shutting down...')));
diff --git a/themes/luci-theme-bootstrap/htdocs/luci-static/bootstrap/cascade.css b/themes/luci-theme-bootstrap/htdocs/luci-static/bootstrap/cascade.css
index fb8a8509a5e4..cf59b12b5618 100644
--- a/themes/luci-theme-bootstrap/htdocs/luci-static/bootstrap/cascade.css
+++ b/themes/luci-theme-bootstrap/htdocs/luci-static/bootstrap/cascade.css
@@ -1394,6 +1394,19 @@ footer ul.breadcrumb {
width: 100%;
}
+.modal > .button-row {
+ display: flex;
+ justify-content: space-between;
+}
+
+.modal > .button-row > button:not(:last-of-type) {
+ margin-right: .5em;
+}
+
+.modal > .button-row > button:first-of-type {
+ margin-right: auto;
+}
+
body.modal-overlay-active {
overflow: hidden;
height: 100vh;
diff --git a/themes/luci-theme-material/htdocs/luci-static/material/cascade.css b/themes/luci-theme-material/htdocs/luci-static/material/cascade.css
index 5434e108b596..fdcb98eb5b13 100644
--- a/themes/luci-theme-material/htdocs/luci-static/material/cascade.css
+++ b/themes/luci-theme-material/htdocs/luci-static/material/cascade.css
@@ -1749,6 +1749,19 @@ body:not(.Interfaces) .cbi-rowstyle-2:first-child {
max-height: none;
}
+.modal .button-row {
+ display: flex;
+ justify-content: space-between;
+}
+
+.modal .button-row > :not(:last-child) {
+ margin-right: .5em;
+}
+
+.modal .button-row > :first-child {
+ margin-right: auto;
+}
+
body.modal-overlay-active {
overflow: hidden;
height: 100vh;
diff --git a/themes/luci-theme-openwrt-2020/htdocs/luci-static/openwrt2020/cascade.css b/themes/luci-theme-openwrt-2020/htdocs/luci-static/openwrt2020/cascade.css
index 277af225f6a0..46120e813128 100644
--- a/themes/luci-theme-openwrt-2020/htdocs/luci-static/openwrt2020/cascade.css
+++ b/themes/luci-theme-openwrt-2020/htdocs/luci-static/openwrt2020/cascade.css
@@ -275,6 +275,18 @@ body.modal-overlay-active #modal_overlay {
.modal .cbi-section > legend:first-child { font-size: 120%; }
+.modal .button-row {
+ display: flex;
+ justify-content: space-between;
+}
+
+.modal .button-row > :not(:last-child) {
+ margin-right: .5em;
+}
+
+.modal .button-row > :first-child {
+ margin-right: auto;
+}
/*
* table layout
diff --git a/themes/luci-theme-openwrt/htdocs/luci-static/openwrt.org/cascade.css b/themes/luci-theme-openwrt/htdocs/luci-static/openwrt.org/cascade.css
index fbb53f9e9939..6ef9d63e72e3 100644
--- a/themes/luci-theme-openwrt/htdocs/luci-static/openwrt.org/cascade.css
+++ b/themes/luci-theme-openwrt/htdocs/luci-static/openwrt.org/cascade.css
@@ -242,6 +242,19 @@ hr {
overflow: auto;
}
+.modal .button-row {
+ display: flex;
+ justify-content: space-between;
+}
+
+.modal .button-row > :not(:last-child) {
+ margin-right: .5em;
+}
+
+.modal .button-row > :first-child {
+ margin-right: auto;
+}
+
body.modal-overlay-active {
overflow: hidden;
}