summaryrefslogtreecommitdiffhomepage
path: root/modules/luci-base/htdocs/luci-static/resources
diff options
context:
space:
mode:
Diffstat (limited to 'modules/luci-base/htdocs/luci-static/resources')
-rw-r--r--modules/luci-base/htdocs/luci-static/resources/cbi.js6
-rw-r--r--modules/luci-base/htdocs/luci-static/resources/form.js174
-rw-r--r--modules/luci-base/htdocs/luci-static/resources/network.js34
-rw-r--r--modules/luci-base/htdocs/luci-static/resources/ui.js2
-rw-r--r--modules/luci-base/htdocs/luci-static/resources/validation.js12
5 files changed, 206 insertions, 22 deletions
diff --git a/modules/luci-base/htdocs/luci-static/resources/cbi.js b/modules/luci-base/htdocs/luci-static/resources/cbi.js
index 9728e03e12..aef64d577e 100644
--- a/modules/luci-base/htdocs/luci-static/resources/cbi.js
+++ b/modules/luci-base/htdocs/luci-static/resources/cbi.js
@@ -657,7 +657,11 @@ String.prototype.format = function()
for (i = 0; (i < units.length) && (val > mf); i++)
val /= mf;
- subst = (i ? val.toFixed(pr) : val) + units[i];
+ if (i)
+ subst = val.toFixed(pr) + units[i] + (mf == 1024 ? 'i' : '');
+ else
+ subst = val + ' ';
+
pMinLength = null;
break;
}
diff --git a/modules/luci-base/htdocs/luci-static/resources/form.js b/modules/luci-base/htdocs/luci-static/resources/form.js
index fbdd73e55e..4016007742 100644
--- a/modules/luci-base/htdocs/luci-static/resources/form.js
+++ b/modules/luci-base/htdocs/luci-static/resources/form.js
@@ -2489,6 +2489,8 @@ var CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.p
config_name = this.uciconfig || this.map.config,
max_cols = isNaN(this.max_cols) ? this.children.length : this.max_cols,
has_more = max_cols < this.children.length,
+ drag_sort = this.sortable && !('ontouchstart' in window),
+ touch_sort = this.sortable && ('ontouchstart' in window),
sectionEl = E('div', {
'id': 'cbi-%s-%s'.format(config_name, this.sectiontype),
'class': 'cbi-section cbi-tblsection',
@@ -2517,14 +2519,16 @@ var CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.p
'id': 'cbi-%s-%s'.format(config_name, cfgsections[i]),
'class': 'tr cbi-section-table-row',
'data-sid': cfgsections[i],
- 'draggable': this.sortable ? true : null,
- 'mousedown': this.sortable ? L.bind(this.handleDragInit, this) : null,
- 'dragstart': this.sortable ? L.bind(this.handleDragStart, this) : null,
- 'dragover': this.sortable ? L.bind(this.handleDragOver, this) : null,
- 'dragenter': this.sortable ? L.bind(this.handleDragEnter, this) : null,
- 'dragleave': this.sortable ? L.bind(this.handleDragLeave, this) : null,
- 'dragend': this.sortable ? L.bind(this.handleDragEnd, this) : null,
- 'drop': this.sortable ? L.bind(this.handleDrop, this) : null,
+ 'draggable': (drag_sort || touch_sort) ? true : null,
+ 'mousedown': drag_sort ? L.bind(this.handleDragInit, this) : null,
+ 'dragstart': drag_sort ? L.bind(this.handleDragStart, this) : null,
+ 'dragover': drag_sort ? L.bind(this.handleDragOver, this) : null,
+ 'dragenter': drag_sort ? L.bind(this.handleDragEnter, this) : null,
+ 'dragleave': drag_sort ? L.bind(this.handleDragLeave, this) : null,
+ 'dragend': drag_sort ? L.bind(this.handleDragEnd, this) : null,
+ 'drop': drag_sort ? L.bind(this.handleDrop, this) : null,
+ 'touchmove': touch_sort ? L.bind(this.handleTouchMove, this) : null,
+ 'touchend': touch_sort ? L.bind(this.handleTouchEnd, this) : null,
'data-title': (sectionname && (!this.anonymous || this.sectiontitle)) ? sectionname : null,
'data-section-id': cfgsections[i]
});
@@ -2797,6 +2801,160 @@ var CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.p
},
/** @private */
+ determineBackgroundColor: function(node) {
+ var r = 255, g = 255, b = 255;
+
+ while (node) {
+ var s = window.getComputedStyle(node),
+ c = (s.getPropertyValue('background-color') || '').replace(/ /g, '');
+
+ if (c != '' && c != 'transparent' && c != 'rgba(0,0,0,0)') {
+ if (/^#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})$/i.test(c)) {
+ r = parseInt(RegExp.$1, 16);
+ g = parseInt(RegExp.$2, 16);
+ b = parseInt(RegExp.$3, 16);
+ }
+ else if (/^rgba?\(([0-9]+),([0-9]+),([0-9]+)[,)]$/.test(c)) {
+ r = +RegExp.$1;
+ g = +RegExp.$2;
+ b = +RegExp.$3;
+ }
+
+ break;
+ }
+
+ node = node.parentNode;
+ }
+
+ return [ r, g, b ];
+ },
+
+ /** @private */
+ handleTouchMove: function(ev) {
+ if (!ev.target.classList.contains('drag-handle'))
+ return;
+
+ var touchLoc = ev.targetTouches[0],
+ rowBtn = ev.target,
+ rowElem = dom.parent(rowBtn, '.tr'),
+ htmlElem = document.querySelector('html'),
+ dragHandle = document.querySelector('.touchsort-element'),
+ viewportHeight = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
+
+ if (!dragHandle) {
+ var rowRect = rowElem.getBoundingClientRect(),
+ btnRect = rowBtn.getBoundingClientRect(),
+ paddingLeft = btnRect.left - rowRect.left,
+ paddingRight = rowRect.right - btnRect.right,
+ colorBg = this.determineBackgroundColor(rowElem),
+ colorFg = (colorBg[0] * 0.299 + colorBg[1] * 0.587 + colorBg[2] * 0.114) > 186 ? [ 0, 0, 0 ] : [ 255, 255, 255 ];
+
+ dragHandle = E('div', { 'class': 'touchsort-element' }, [
+ E('strong', [ rowElem.getAttribute('data-title') ]),
+ rowBtn.cloneNode(true)
+ ]);
+
+ Object.assign(dragHandle.style, {
+ position: 'absolute',
+ boxShadow: '0 0 3px rgba(%d, %d, %d, 1)'.format(colorFg[0], colorFg[1], colorFg[2]),
+ background: 'rgba(%d, %d, %d, 0.8)'.format(colorBg[0], colorBg[1], colorBg[2]),
+ top: rowRect.top + 'px',
+ left: rowRect.left + 'px',
+ width: rowRect.width + 'px',
+ height: (rowBtn.offsetHeight + 4) + 'px'
+ });
+
+ Object.assign(dragHandle.firstElementChild.style, {
+ position: 'absolute',
+ lineHeight: dragHandle.style.height,
+ whiteSpace: 'nowrap',
+ overflow: 'hidden',
+ textOverflow: 'ellipsis',
+ left: (paddingRight > paddingLeft) ? '' : '5px',
+ right: (paddingRight > paddingLeft) ? '5px' : '',
+ width: (Math.max(paddingLeft, paddingRight) - 10) + 'px'
+ });
+
+ Object.assign(dragHandle.lastElementChild.style, {
+ position: 'absolute',
+ top: '2px',
+ left: paddingLeft + 'px',
+ width: rowBtn.offsetWidth + 'px'
+ });
+
+ document.body.appendChild(dragHandle);
+
+ rowElem.classList.remove('flash');
+ rowBtn.blur();
+ }
+
+ dragHandle.style.top = (touchLoc.pageY - (parseInt(dragHandle.style.height) / 2)) + 'px';
+
+ rowElem.parentNode.querySelectorAll('[draggable]').forEach(function(tr, i, trs) {
+ var trRect = tr.getBoundingClientRect(),
+ yTop = trRect.top + window.scrollY,
+ yBottom = trRect.bottom + window.scrollY,
+ yMiddle = yTop + ((yBottom - yTop) / 2);
+
+ tr.classList.remove('drag-over-above', 'drag-over-below');
+
+ if ((i == 0 || touchLoc.pageY >= yTop) && touchLoc.pageY <= yMiddle)
+ tr.classList.add('drag-over-above');
+ else if ((i == (trs.length - 1) || touchLoc.pageY <= yBottom) && touchLoc.pageY > yMiddle)
+ tr.classList.add('drag-over-below');
+ });
+
+ /* prevent standard scrolling and scroll page when drag handle is
+ * moved very close (~30px) to the viewport edge */
+
+ ev.preventDefault();
+
+ if (touchLoc.clientY < 30)
+ window.requestAnimationFrame(function() { htmlElem.scrollTop -= 30 });
+ else if (touchLoc.clientY > viewportHeight - 30)
+ window.requestAnimationFrame(function() { htmlElem.scrollTop += 30 });
+ },
+
+ /** @private */
+ handleTouchEnd: function(ev) {
+ var rowElem = dom.parent(ev.target, '.tr'),
+ htmlElem = document.querySelector('html'),
+ dragHandle = document.querySelector('.touchsort-element'),
+ targetElem = rowElem.parentNode.querySelector('.drag-over-above, .drag-over-below'),
+ viewportHeight = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
+
+ if (!dragHandle)
+ return;
+
+ if (targetElem) {
+ var isBelow = targetElem.classList.contains('drag-over-below');
+
+ rowElem.parentNode.insertBefore(rowElem, isBelow ? targetElem.nextElementSibling : targetElem);
+
+ this.map.data.move(
+ this.uciconfig || this.map.config,
+ rowElem.getAttribute('data-sid'),
+ targetElem.getAttribute('data-sid'),
+ isBelow);
+
+ window.requestAnimationFrame(function() {
+ var rowRect = rowElem.getBoundingClientRect();
+
+ if (rowRect.top < 50)
+ htmlElem.scrollTop = (htmlElem.scrollTop + rowRect.top - 50);
+ else if (rowRect.bottom > viewportHeight - 50)
+ htmlElem.scrollTop = (htmlElem.scrollTop + viewportHeight - 50 - rowRect.height);
+
+ rowElem.classList.add('flash');
+ });
+
+ targetElem.classList.remove('drag-over-above', 'drag-over-below');
+ }
+
+ document.body.removeChild(dragHandle);
+ },
+
+ /** @private */
handleModalCancel: function(modalMap, ev) {
return Promise.resolve(ui.hideModal());
},
diff --git a/modules/luci-base/htdocs/luci-static/resources/network.js b/modules/luci-base/htdocs/luci-static/resources/network.js
index 17dd055e25..2a402bcd57 100644
--- a/modules/luci-base/htdocs/luci-static/resources/network.js
+++ b/modules/luci-base/htdocs/luci-static/resources/network.js
@@ -1005,9 +1005,10 @@ Network = baseclass.extend(/** @lends LuCI.network.prototype */ {
*/
deleteNetwork: function(name) {
var requireFirewall = Promise.resolve(L.require('firewall')).catch(function() {}),
+ loadDHCP = L.resolveDefault(uci.load('dhcp')),
network = this.instantiateNetwork(name);
- return Promise.all([ requireFirewall, initNetworkState() ]).then(function(res) {
+ return Promise.all([ requireFirewall, loadDHCP, initNetworkState() ]).then(function(res) {
var uciInterface = uci.get('network', name),
firewall = res[0];
@@ -1020,19 +1021,23 @@ Network = baseclass.extend(/** @lends LuCI.network.prototype */ {
uci.remove('luci', s['.name']);
});
- uci.sections('network', 'alias', function(s) {
- if (s.interface == name)
- uci.remove('network', s['.name']);
- });
+ uci.sections('network', null, function(s) {
+ switch (s['.type']) {
+ case 'alias':
+ case 'route':
+ case 'route6':
+ if (s.interface == name)
+ uci.remove('network', s['.name']);
- uci.sections('network', 'route', function(s) {
- if (s.interface == name)
- uci.remove('network', s['.name']);
- });
+ break;
- uci.sections('network', 'route6', function(s) {
- if (s.interface == name)
- uci.remove('network', s['.name']);
+ case 'rule':
+ case 'rule6':
+ if (s.in == name || s.out == name)
+ uci.remove('network', s['.name']);
+
+ break;
+ }
});
uci.sections('wireless', 'wifi-iface', function(s) {
@@ -1044,6 +1049,11 @@ Network = baseclass.extend(/** @lends LuCI.network.prototype */ {
uci.unset('wireless', s['.name'], 'network');
});
+ uci.sections('dhcp', 'dhcp', function(s) {
+ if (s.interface == name)
+ uci.remove('dhcp', s['.name']);
+ });
+
if (firewall)
return firewall.deleteNetwork(name).then(function() { return true });
diff --git a/modules/luci-base/htdocs/luci-static/resources/ui.js b/modules/luci-base/htdocs/luci-static/resources/ui.js
index 0e909b6dcc..9cc62c12db 100644
--- a/modules/luci-base/htdocs/luci-static/resources/ui.js
+++ b/modules/luci-base/htdocs/luci-static/resources/ui.js
@@ -3021,7 +3021,7 @@ function scrubMenu(node) {
for (var k in node.children) {
var child = scrubMenu(node.children[k]);
- if (child.title)
+ if (child.title && !child.firstchild_ineligible)
hasSatisfiedChild = hasSatisfiedChild || child.satisfied;
}
}
diff --git a/modules/luci-base/htdocs/luci-static/resources/validation.js b/modules/luci-base/htdocs/luci-static/resources/validation.js
index 70d3a7e73a..fccce4ab0b 100644
--- a/modules/luci-base/htdocs/luci-static/resources/validation.js
+++ b/modules/luci-base/htdocs/luci-static/resources/validation.js
@@ -575,6 +575,18 @@ var ValidatorFactory = baseclass.extend({
string: function() {
return true;
+ },
+
+ directory: function() {
+ return true;
+ },
+
+ file: function() {
+ return true;
+ },
+
+ device: function() {
+ return true;
}
}
});