summaryrefslogtreecommitdiffhomepage
path: root/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/feeds.js
diff options
context:
space:
mode:
Diffstat (limited to 'applications/luci-app-banip/htdocs/luci-static/resources/view/banip/feeds.js')
-rw-r--r--applications/luci-app-banip/htdocs/luci-static/resources/view/banip/feeds.js234
1 files changed, 234 insertions, 0 deletions
diff --git a/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/feeds.js b/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/feeds.js
new file mode 100644
index 0000000000..672b23d0f8
--- /dev/null
+++ b/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/feeds.js
@@ -0,0 +1,234 @@
+'use strict';
+'require view';
+'require form';
+'require fs';
+'require ui';
+
+/*
+ include custom CSS
+*/
+document.querySelector('head').appendChild(E('link', {
+ 'rel': 'stylesheet',
+ 'type': 'text/css',
+ 'href': L.resource('view/banip/custom.css')
+}));
+
+/*
+ observe DOM changes
+*/
+const observer = new MutationObserver(function (mutations) {
+ if (mutations) {
+ const inputs = document.querySelectorAll('input');
+ inputs.forEach(function (input) {
+ input.setAttribute('autocomplete', 'off')
+ input.setAttribute('autocorrect', 'off')
+ input.setAttribute('autocapitalize', 'off')
+ input.setAttribute('spellcheck', false)
+ })
+ const labels = document.querySelectorAll('label[for^="widget.cbid.json"][for$="name"]');
+ labels.forEach(function (label) {
+ label.setAttribute("style", "font-weight: bold !important; color: #595 !important;");
+ })
+ L.resolveDefault(fs.stat('/etc/banip/banip.custom.feeds'), '').then(function (stat) {
+ const buttons = document.querySelectorAll('#btnClear, #btnCreate, #btnSave');
+ if (buttons[0] && stat.size === 0) {
+ buttons[0].removeAttribute('disabled');
+ } else if (buttons[1] && buttons[2] && stat.size > 0) {
+ buttons[1].removeAttribute('disabled');
+ buttons[2].removeAttribute('disabled');
+ }
+ });
+ }
+});
+
+const targetNode = document.getElementById('view');
+const observerConfig = {
+ childList: true,
+ subtree: true,
+ attributes: false,
+ characterData: false
+};
+observer.observe(targetNode, observerConfig);
+
+/*
+ button handling
+*/
+function handleEdit(ev) {
+ if (ev === 'create') {
+ return fs.read_direct('/etc/banip/banip.feeds', 'json').then(function (content) {
+ fs.write('/etc/banip/banip.custom.feeds', JSON.stringify(content)).then(function () {
+ location.reload();
+ });
+ });
+ }
+ if (ev === 'clear') {
+ return fs.write('/etc/banip/banip.custom.feeds', null).then(function () {
+ location.reload();
+ });
+ }
+ if (ev === 'save') {
+ const invalid = document.querySelectorAll('.cbi-input-invalid');
+ if (invalid.length > 0) {
+ document.body.scrollTop = document.documentElement.scrollTop = 0;
+ return ui.addNotification(null, E('p', _('Invalid input values, unable to save modifications.')), 'error');
+ }
+ }
+ let sumSubElements = [], exportJson;
+ const nodeKeys = document.querySelectorAll('[id^="widget.cbid.json"][id$="name"]');
+ for (let i = 0; i < nodeKeys.length; i++) {
+ let subElements = {};
+ let elements = document.querySelectorAll('[id^="widget.cbid.json.' + nodeKeys[i].id.split('.')[3] + '\."]');
+ for (const element of elements) {
+ let key = element.id.split('.')[4];
+ let value = element.value || "";
+ switch (key) {
+ case 'url_4':
+ subElements.url_4 = value;
+ break;
+ case 'rule_4':
+ subElements.rule_4 = value;
+ break;
+ case 'url_6':
+ subElements.url_6 = value;
+ break;
+ case 'rule_6':
+ subElements.rule_6 = value;
+ break;
+ case 'descr':
+ subElements.descr = value;
+ break;
+ case 'flag':
+ subElements.flag = value;
+ break;
+ }
+ }
+ sumSubElements.push(nodeKeys[i].value, subElements);
+ }
+ exportJson = JSON.stringify(sumSubElements).replace(/,{/g, ':{').replace(/^\[/g, '{').replace(/\]$/g, '}');
+ return fs.write('/etc/banip/banip.custom.feeds', exportJson).then(function () {
+ location.reload();
+ });
+}
+
+return view.extend({
+ load: function () {
+ return L.resolveDefault(fs.read_direct('/etc/banip/banip.custom.feeds', 'json'), "");
+ },
+
+ render: function (data) {
+ let m, s, o, feed, url_4, url_6, rule_4, rule_6, descr, flag;
+
+ m = new form.JSONMap(data, 'Custom Feed Editor', _('With this editor you can fill up an initial custom feed file (a 1:1 copy of the version shipped with the package). \
+ The file is located at \'/etc/banip/banip.custom.feeds\'. \
+ Then you can edit this file, delete entries, add new ones, etc. To go back to the maintainers version just empty the custom feed file again (do not delete it!).'));
+ for (let i = 0; i < Object.keys(m.data.data).length; i++) {
+ feed = Object.keys(m.data.data)[i];
+ url_4 = m.data.data[feed].url_4;
+ rule_4 = m.data.data[feed].rule_4;
+ url_6 = m.data.data[feed].url_6;
+ rule_6 = m.data.data[feed].rule_6;
+ descr = m.data.data[feed].descr;
+ flag = m.data.data[feed].flag;
+
+ s = m.section(form.TypedSection, feed, null);
+ s.addremove = true;
+ s.anonymous = true;
+
+ o = s.option(form.Value, 'name', _('Feed Name'));
+ o.ucioption = '.name';
+ o.datatype = 'and(minlength(3),maxlength(15))';
+ o.validate = function (section_id, value) {
+ if (!value) {
+ return _('Empty field not allowed');
+ }
+ if (!value.match(/^[a-z0-9]+$/)) {
+ return _('Invalid characters');
+ }
+ return true;
+ }
+
+ o = s.option(form.Value, 'url_4', _('URLv4'));
+ o.validate = function (section_id, value) {
+ if (!value) {
+ return true;
+ }
+ if (!value.match(/^(http:\/\/|https:\/\/)[A-Za-z0-9\/\.\-_\?\&=]+$/)) {
+ return _('Protocol/URL format not supported');
+ }
+ return true;
+ }
+
+ o = s.option(form.Value, 'rule_4', _('Rulev4'));
+
+ o = s.option(form.Value, 'url_6', _('URLv6'));
+ o.validate = function (section_id, value) {
+ if (!value) {
+ return true;
+ }
+ if (!value.match(/^(http:\/\/|https:\/\/)[A-Za-z0-9\/\.\-_\?\&=:]+$/)) {
+ return _('Protocol/URL format not supported');
+ }
+ return true;
+ }
+
+ o = s.option(form.Value, 'rule_6', _('Rulev6'));
+
+ o = s.option(form.Value, 'descr', _('Description'));
+ o.datatype = 'and(minlength(3),maxlength(30))';
+ o.validate = function (section_id, value) {
+ if (!value) {
+ return _('Empty field not allowed');
+ }
+ return true;
+ }
+
+ o = s.option(form.Value, 'flag', _('Flag'));
+ o.datatype = 'and(minlength(2),maxlength(2))';
+ o.validate = function (section_id, value) {
+ if (!value) {
+ return true;
+ }
+ if (!value.match(/^gz$/)) {
+ return _('Flag not supported');
+ }
+ return true;
+ }
+ }
+
+ s = m.section(form.NamedSection, 'global');
+ s.render = L.bind(function () {
+ return E('div', { class: 'right' }, [
+ E('button', {
+ 'class': 'btn cbi-button cbi-button-action important',
+ 'id': 'btnCreate',
+ 'disabled': 'disabled',
+ 'click': ui.createHandlerFn(this, function () {
+ return handleEdit('create');
+ })
+ }, [_('Fill Custom Feeds')]),
+ '\xa0\xa0\xa0',
+ E('button', {
+ 'class': 'btn cbi-button cbi-button-negative important',
+ 'id': 'btnClear',
+ 'disabled': 'disabled',
+ 'click': ui.createHandlerFn(this, function () {
+ return handleEdit('clear');
+ })
+ }, [_('Clear Custom Feeds')]),
+ '\xa0\xa0\xa0',
+ E('button', {
+ 'class': 'btn cbi-button cbi-button-positive important',
+ 'id': 'btnSave',
+ 'disabled': 'disabled',
+ 'click': ui.createHandlerFn(this, function () {
+ return handleEdit('save');
+ })
+ }, [_('Save Custom Feeds')])
+ ])
+ });
+ return m.render();
+ },
+ handleSaveApply: null,
+ handleSave: null,
+ handleReset: null
+});