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; }