1
0
mirror of https://git.tt-rss.org/git/tt-rss.git synced 2025-12-13 13:25:54 +00:00

add basic plugin installer (uses tt-rss.org)

This commit is contained in:
Andrew Dolgov
2021-03-03 19:07:39 +03:00
parent 06cb181f73
commit cb7f322f09
5 changed files with 329 additions and 16 deletions

View File

@@ -115,7 +115,7 @@ const Filters = {
const li = document.createElement('li');
li.addClassName("rule");
li.innerHTML = `${App.FormFields.checkbox_tag("", false, {onclick: 'Lists.onRowChecked(this)'})}
li.innerHTML = `${App.FormFields.checkbox_tag("", false, "", {onclick: 'Lists.onRowChecked(this)'})}
<span class="name" onclick='App.dialogOf(this).onRuleClicked(this)'>${reply}</span>
<span class="payload" >${App.FormFields.hidden_tag("rule[]", rule)}</span>`;
@@ -147,7 +147,7 @@ const Filters = {
const li = document.createElement('li');
li.addClassName("action");
li.innerHTML = `${App.FormFields.checkbox_tag("", false, {onclick: 'Lists.onRowChecked(this)'})}
li.innerHTML = `${App.FormFields.checkbox_tag("", false, "", {onclick: 'Lists.onRowChecked(this)'})}
<span class="name" onclick='App.dialogOf(this).onActionClicked(this)'>${reply}</span>
<span class="payload">${App.FormFields.hidden_tag("action[]", action)}</span>`;

View File

@@ -349,10 +349,128 @@ const Helpers = {
}
});
},
install: function() {
const dialog = new fox.SingleUseDialog({
PI_RES_ALREADY_INSTALLED: "PI_RES_ALREADY_INSTALLED",
PI_RES_SUCCESS: "PI_RES_SUCCESS",
PI_ERR_NO_CLASS: "PI_ERR_NO_CLASS",
PI_ERR_NO_INIT_PHP: "PI_ERR_NO_INIT_PHP",
PI_ERR_EXEC_FAILED: "PI_ERR_EXEC_FAILED",
PI_ERR_NO_TEMPDIR: "PI_ERR_NO_TEMPDIR",
PI_ERR_PLUGIN_NOT_FOUND: "PI_ERR_PLUGIN_NOT_FOUND",
PI_ERR_NO_WORKDIR: "PI_ERR_NO_WORKDIR",
title: __("List of plugins"),
need_refresh: false,
onHide: function() {
if (this.need_refresh) {
Helpers.Prefs.refresh();
}
},
performInstall: function(plugin) {
const install_dialog = new fox.SingleUseDialog({
title: __("Plugin installer"),
content: `
<ul class="panel panel-scrollable contents">
<li class='text-center'>${__("Installing %s, please wait...").replace("%s", plugin)}</li>
</ul>
<footer class='text-center'>
${App.FormFields.submit_tag(__("Close this window"))}
</footer>`
});
const tmph = dojo.connect(install_dialog, 'onShow', function () {
dojo.disconnect(tmph);
const container = install_dialog.domNode.querySelector(".contents");
xhr.json("backend.php", {op: "pref-prefs", method: "installPlugin", plugin: plugin}, (reply) => {
if (!reply) {
container.innerHTML = `<li class='text-center text-error'>${__("Operation failed: check event log.")}</li>`;
} else {
switch (reply.result) {
case dialog.PI_RES_SUCCESS:
container.innerHTML = `<li class='text-success text-center'>${__("Plugin has been installed.")}</li>`
dialog.need_refresh = true;
break;
case dialog.PI_RES_ALREADY_INSTALLED:
container.innerHTML = `<li class='text-success text-center'>${__("Plugin is already installed.")}</li>`
break;
default:
container.innerHTML = `
<li>
<h3 style="margin-top: 0">${plugin}</h3>
${reply.stderr ? `<pre class="small text-error">${reply.stderr}</pre>` : ''}
${reply.stdour ? `<pre class="small text-success">${reply.stdout}</pre>` : ''}
<p class="small">
${App.FormFields.icon("error_outline") + " " + __("Exited with RC: %d").replace("%d", reply.git_status)}
</p>
</li>
`;
}
}
});
});
install_dialog.show();
},
refresh: function() {
const container = dialog.domNode.querySelector(".contents");
container.innerHTML = `<li class='text-center'>${__("Looking for plugins...")}</li>`;
xhr.json("backend.php", {op: "pref-prefs", method: "getAvailablePlugins"}, (reply) => {
if (!reply) {
container.innerHTML = `<li class='text-center text-error'>${__("Operation failed: check event log.")}</li>`;
} else {
container.innerHTML = "";
reply.forEach((plugin) => {
container.innerHTML += `
<li data-row-value="${App.escapeHtml(plugin.name)}">
<h3 style="margin-top: 0">${plugin.name}
<a target="_blank" href="${App.escapeHtml(plugin.html_url)}">
${App.FormFields.icon("open_in_new_window")}
</a>
</h3>
<p>${plugin.description}</p>
${App.FormFields.button_tag(__('Install plugin'), "", {class: 'alt-primary',
onclick: `App.dialogOf(this).performInstall("${App.escapeHtml(plugin.name)}")`})}
<hr/>
</li>
`
});
dojo.parser.parse(container);
}
});
},
content: `
<ul class="panel panel-scrollable contents"> </ul>
<footer>
${App.FormFields.button_tag(__("Refresh"), "", {class: 'alt-primary', onclick: 'App.dialogOf(this).refresh()'})}
${App.FormFields.cancel_dialog_tag(__("Close"))}
</footer>
`,
});
const tmph = dojo.connect(dialog, 'onShow', function () {
dojo.disconnect(tmph);
dialog.refresh();
});
dialog.show();
},
update: function(name = null) {
const dialog = new fox.SingleUseDialog({
title: __("Plugin Updater"),
title: __("Update plugins"),
need_refresh: false,
plugins_to_update: [],
onHide: function() {

View File

@@ -262,8 +262,11 @@ const Lists = {
if (row)
checked ? row.addClassName("Selected") : row.removeClassName("Selected");
},
select: function(elemId, selected) {
$(elemId).querySelectorAll("li").forEach((row) => {
select: function(elem, selected) {
if (typeof elem == "string")
elem = document.getElementById(elem);
elem.querySelectorAll("li").forEach((row) => {
const checkNode = row.querySelector(".dijitCheckBox,input[type=checkbox]");
if (checkNode) {
const widget = dijit.getEnclosingWidget(checkNode);
@@ -278,6 +281,30 @@ const Lists = {
}
});
},
getSelected: function(elem) {
const rv = [];
if (typeof elem == "string")
elem = document.getElementById(elem);
elem.querySelectorAll("li").forEach((row) => {
if (row.hasClassName("Selected")) {
const rowVal = row.getAttribute("data-row-value");
if (rowVal) {
rv.push(rowVal);
} else {
// either older prefix-XXX notation or separate attribute
const rowId = row.getAttribute("data-row-id") || row.id.replace(/^[A-Z]*?-/, "");
if (!isNaN(rowId))
rv.push(parseInt(rowId));
}
}
});
return rv;
}
};
/* exported Tables */
@@ -293,8 +320,11 @@ const Tables = {
checked ? row.addClassName("Selected") : row.removeClassName("Selected");
},
select: function(elemId, selected) {
$(elemId).querySelectorAll("tr").forEach((row) => {
select: function(elem, selected) {
if (typeof elem == "string")
elem = document.getElementById(elem);
elem.querySelectorAll("tr").forEach((row) => {
const checkNode = row.querySelector(".dijitCheckBox,input[type=checkbox]");
if (checkNode) {
const widget = dijit.getEnclosingWidget(checkNode);
@@ -309,16 +339,25 @@ const Tables = {
}
});
},
getSelected: function(elemId) {
getSelected: function(elem) {
const rv = [];
$(elemId).querySelectorAll("tr").forEach((row) => {
if (row.hasClassName("Selected")) {
// either older prefix-XXX notation or separate attribute
const rowId = row.getAttribute("data-row-id") || row.id.replace(/^[A-Z]*?-/, "");
if (typeof elem == "string")
elem = document.getElementById(elem);
if (!isNaN(rowId))
rv.push(parseInt(rowId));
elem.querySelectorAll("tr").forEach((row) => {
if (row.hasClassName("Selected")) {
const rowVal = row.getAttribute("data-row-value");
if (rowVal) {
rv.push(rowVal);
} else {
// either older prefix-XXX notation or separate attribute
const rowId = row.getAttribute("data-row-id") || row.id.replace(/^[A-Z]*?-/, "");
if (!isNaN(rowId))
rv.push(parseInt(rowId));
}
}
});