upstream: integrar Oasis 1.3.1
Base del merge a tres bandas: git 0.9.5 de epsylon, esta rama y el src de la
APK oficial 1.3.1 (la variante movil: OASIS_MOBILE, regex sin \p{}, audio y
video de Android). Corre en el mismo nodejs-mobile 18.20.4 que ya usabamos.
Se conserva de la rama: Karvan, identidades y multicuenta, topbar y barra
inferior, borrado de EXIF sin sharp, filtro hot del foro, RTC sin STUN y los
modulos apagados en movil (wallet, banking, torrents).
Se toma de upstream lo que ya hace de serie: respuesta citada en chats, ssb-lan
en movil, configuracion en ~/.ssb/oasis (sobrevive a reinstalar el backend).
El asistente de bienvenida deja elegir workflow tambien en movil.
This commit is contained in:
parent
8d838dd8b1
commit
c332afd6ea
265 changed files with 80970 additions and 29167 deletions
|
|
@ -1,17 +1,16 @@
|
|||
const { div, h2, p, section, button, form, a, input, label, span, textarea, br, table, tr, td } = require("../server/node_modules/hyperaxe");
|
||||
const { renderCommentsSection: renderSharedCommentsSection } = require("./comments_view");
|
||||
const { template, i18n, userLink, renderOpinionsVoting, renderEngagement, renderSpreadButton, renderContentActions, renderStateChip, renderLifespanChip, renderSpreadEditWarning } = require("./main_views");
|
||||
const { template, i18n, userLink, renderOpinionsVoting, renderEngagement, renderSpreadButton, renderContentActions, renderStateChip, renderLifespanChip, renderSpreadEditWarning, renderModuleStatsBy, moduleIsEmpty, contentDeleteAction, paged, renderCreatedRows } = require("./main_views");
|
||||
const moment = require("../server/node_modules/moment");
|
||||
const { config } = require("../server/SSB_server.js");
|
||||
const { renderUrl } = require("../backend/renderUrl");
|
||||
const { MAX_OPTIONS, MIN_OPTIONS, MAX_OPTION_LENGTH } = require("../models/polls_model_limits");
|
||||
|
||||
const userId = config.keys.id;
|
||||
|
||||
const FILTERS = [
|
||||
{ key: "ALL", i18n: "pollFilterAll" },
|
||||
{ key: "MINE", i18n: "pollFilterMine" },
|
||||
{ key: "RECENT", i18n: "pollFilterRecent" },
|
||||
{ key: "MINE", i18n: "pollFilterMine" },
|
||||
{ key: "TOP", i18n: "pollFilterTop" },
|
||||
{ key: "VOTED", i18n: "pollFilterVoted" },
|
||||
{ key: "OPEN", i18n: "pollFilterOpen" },
|
||||
|
|
@ -68,7 +67,7 @@ const renderResults = (poll) =>
|
|||
)
|
||||
);
|
||||
|
||||
const renderBallot = (poll, returnTo, basePath) => {
|
||||
const renderBallot = (poll, returnTo, basePath, extra = null) => {
|
||||
if (poll.status === "CLOSED" || poll.hasVoted) return null;
|
||||
const inputType = poll.multiple ? "checkbox" : "radio";
|
||||
return form({ method: "POST", action: `${basePath}/vote/${encodeURIComponent(poll.id)}`, class: "poll-ballot" },
|
||||
|
|
@ -85,7 +84,10 @@ const renderBallot = (poll, returnTo, basePath) => {
|
|||
)
|
||||
)
|
||||
),
|
||||
button({ type: "submit", class: "filter-btn" }, i18n.pollVoteButton)
|
||||
div({ class: "poll-ballot-actions" },
|
||||
button({ type: "submit", class: "filter-btn" }, i18n.pollVoteButton),
|
||||
...(Array.isArray(extra) ? extra.filter(Boolean) : [])
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -103,7 +105,7 @@ const renderPollCard = (poll, filter, spreadInfo, basePath = "/polls") => {
|
|||
return div({ class: "tribe-card poll-card" + (isOwn ? " own-content" : "") },
|
||||
div({ class: "card-header activity-card-header" },
|
||||
span(),
|
||||
renderContentActions(poll.id, href, { spread: spreadInfo || null, author: poll.author, favKind: 'polls', isFavorite: poll.isFavorite, reportTitle: poll.question })
|
||||
renderContentActions(poll.id, href, { spread: spreadInfo || null, author: poll.author, favKind: 'polls', isFavorite: poll.isFavorite, reportTitle: poll.question, deleteAction: isOwn ? contentDeleteAction('poll', poll.id) : undefined })
|
||||
),
|
||||
div({ class: "tribe-card-body" },
|
||||
div({ class: "shop-title-row" },
|
||||
|
|
@ -180,17 +182,30 @@ const renderComments = (poll, comments, basePath) => {
|
|||
});
|
||||
};
|
||||
|
||||
const renderFilterBar = (filter, q, showSearch = true) =>
|
||||
section(
|
||||
const renderFilterBar = (filter, q, showSearch = true, items = null, censusList = null) => {
|
||||
const emptyMod = items !== null && moduleIsEmpty(items, filter, "ALL", q);
|
||||
const censusPl = Array.isArray(censusList) ? censusList : (Array.isArray(items) ? items : []);
|
||||
const pollChip = (x) => {
|
||||
const m = x.key;
|
||||
if (m === filter) return true;
|
||||
if (m === "TOP") return censusPl.length > 0;
|
||||
if (m === "MINE") return censusPl.some(pl => String(pl.author || pl.createdBy) === String(userId));
|
||||
if (m === "RECENT") return censusPl.length > 0;
|
||||
if (m === "VOTED") return censusPl.some(pl => pl.hasVoted || safeArr(pl.myChoices).length > 0);
|
||||
if (m === "OPEN" || m === "CLOSED") return censusPl.some(pl => String(pl.status || "OPEN").toUpperCase() === m);
|
||||
return true;
|
||||
};
|
||||
return section(
|
||||
div({ class: "filters" },
|
||||
form({ method: "GET", action: "/polls", class: "ui-toolbar ui-toolbar--filters" },
|
||||
...FILTERS.map(f =>
|
||||
...(emptyMod ? [] : FILTERS.filter(pollChip).map(f =>
|
||||
button({ type: "submit", name: "filter", value: f.key, class: filter === f.key ? "filter-btn active" : "filter-btn" }, String(i18n[f.i18n]).toUpperCase())
|
||||
),
|
||||
)),
|
||||
button({ type: "submit", name: "filter", value: "CREATE", class: "create-button" }, i18n.pollCreateButton)
|
||||
)
|
||||
),
|
||||
showSearch ? div({ class: "filters" },
|
||||
showSearch && !emptyMod ? div({ class: "filters activity-filter-chips activity-toolbar-row" },
|
||||
items ? renderModuleStatsBy(items, pl => String(pl.status || 'OPEN').toUpperCase(), [{ value: 'OPEN', label: i18n.pollStatusOpen }, { value: 'CLOSED', label: i18n.pollStatusClosed }]) : null,
|
||||
form({ method: "GET", action: "/polls", class: "filter-box" },
|
||||
input({ type: "hidden", name: "filter", value: filter }),
|
||||
input({ type: "text", name: "q", value: q || "", placeholder: i18n.pollSearchPlaceholder, class: "filter-box__input" }),
|
||||
|
|
@ -200,6 +215,7 @@ const renderFilterBar = (filter, q, showSearch = true) =>
|
|||
)
|
||||
) : null
|
||||
);
|
||||
};
|
||||
|
||||
exports.pollsView = async (polls = [], filter = "ALL", params = {}) => {
|
||||
const mode = String(filter).toUpperCase();
|
||||
|
|
@ -209,19 +225,19 @@ exports.pollsView = async (polls = [], filter = "ALL", params = {}) => {
|
|||
if (editing) params = { ...params, spreadWarning: await renderSpreadEditWarning(editing.id) };
|
||||
return template(
|
||||
i18n.pollsTitle,
|
||||
section(div({ class: "tags-header" }, h2(i18n.pollsTitle), p(i18n.pollsDescription))),
|
||||
section(div({ class: "tags-header module-header-line" }, h2(i18n.pollsTitle), p(i18n.pollsDescription))),
|
||||
renderFilterBar(mode, params.q, false),
|
||||
renderCreateForm(editing, params)
|
||||
);
|
||||
}
|
||||
return template(
|
||||
i18n.pollsTitle,
|
||||
section(div({ class: "tags-header" }, h2(i18n.pollsTitle), p(i18n.pollsDescription))),
|
||||
renderFilterBar(mode, params.q),
|
||||
section(div({ class: "tags-header module-header-line" }, h2(i18n.pollsTitle), p(i18n.pollsDescription))),
|
||||
renderFilterBar(mode, params.q, true, polls, params.censusList),
|
||||
section(
|
||||
polls.length
|
||||
? div({ class: "jobs-grid" }, ...polls.map(pl => renderPollCard(pl, mode, spreadMap.get(pl.id))))
|
||||
: p({ class: "no-content" }, i18n.pollsNoItems)
|
||||
? div({ class: "jobs-grid" }, ...paged(polls).map(pl => renderPollCard(pl, mode, spreadMap.get(pl.id))))
|
||||
: div({ class: "no-content-box" }, p({ class: "no-content" }, i18n.pollsNoItems))
|
||||
)
|
||||
);
|
||||
};
|
||||
|
|
@ -246,28 +262,23 @@ exports.singlePollView = async (poll, comments = [], params = {}) => {
|
|||
a({ href: `/search?query=%23${encodeURIComponent(tag)}`, class: "tag-link" }, `#${tag}`)))
|
||||
: null;
|
||||
|
||||
const ownerActions = isOwn
|
||||
const ownerActions = isOwn && poll.totalVoters === 0 && poll.status === "OPEN"
|
||||
? div({ class: "tribe-side-actions" },
|
||||
poll.totalVoters === 0 && poll.status === "OPEN"
|
||||
? form({ method: "GET", action: "/polls" },
|
||||
input({ type: "hidden", name: "filter", value: "EDIT" }),
|
||||
input({ type: "hidden", name: "id", value: poll.id }),
|
||||
button({ type: "submit", class: "update-btn" }, i18n.pollUpdateButton)
|
||||
)
|
||||
: null,
|
||||
form({ method: "POST", action: `/polls/delete/${encodeURIComponent(poll.id)}` },
|
||||
button({ type: "submit", class: "delete-btn" }, i18n.pollDeleteButton)
|
||||
form({ method: "GET", action: "/polls" },
|
||||
input({ type: "hidden", name: "filter", value: "EDIT" }),
|
||||
input({ type: "hidden", name: "id", value: poll.id }),
|
||||
button({ type: "submit", class: "update-btn" }, i18n.pollUpdateButton)
|
||||
)
|
||||
)
|
||||
: null;
|
||||
|
||||
const pollSide = div({ class: "tribe-side" },
|
||||
div({ class: "card-header activity-card-header" },
|
||||
renderContentActions(poll.id, null, { spread: params.spreads || null, author: poll.author, favKind: 'polls', isFavorite: poll.isFavorite, returnTo: href, reportTitle: poll.question })
|
||||
renderContentActions(poll.id, href, { spread: params.spreads || null, author: poll.author, favKind: 'polls', isFavorite: poll.isFavorite, returnTo: href, reportTitle: poll.question, deleteAction: isOwn ? contentDeleteAction('poll', poll.id) : undefined })
|
||||
),
|
||||
div({ class: "shop-title-row" }, h2({ class: "tribe-card-title" }, poll.question)),
|
||||
chips.length ? div({ class: "card-chips-row" }, ...chips) : null,
|
||||
table({ class: "tribe-info-table jobs-info-table" }, ...infoRows),
|
||||
table({ class: "tribe-info-table jobs-info-table" }, ...infoRows, ...renderCreatedRows(poll.createdAt, poll.author)),
|
||||
tagsNode,
|
||||
div({ class: "tribe-card-members" },
|
||||
span({ class: "tribe-members-count" }, `${i18n.pollVoters}: ${poll.totalVoters}`)
|
||||
|
|
@ -297,11 +308,6 @@ exports.singlePollView = async (poll, comments = [], params = {}) => {
|
|||
: (poll.voters.length
|
||||
? div({ class: "card-assigned-list" }, ...poll.voters.map(v => userLink(v)))
|
||||
: null),
|
||||
p({ class: "card-footer" },
|
||||
span({ class: "date-link" }, moment(poll.createdAt).format("YYYY/MM/DD HH:mm")),
|
||||
span(" · "),
|
||||
userLink(poll.author)
|
||||
),
|
||||
renderEngagement(poll.id,
|
||||
renderOpinionsVoting('/polls/opinions', poll.id, poll.opinions, href, poll.opinions_inhabitants),
|
||||
renderComments(poll, comments, basePath)
|
||||
|
|
@ -310,7 +316,7 @@ exports.singlePollView = async (poll, comments = [], params = {}) => {
|
|||
|
||||
return template(
|
||||
poll.question,
|
||||
section(div({ class: "tags-header" }, h2(i18n.pollsTitle), p(i18n.pollsDescription))),
|
||||
section(div({ class: "tags-header module-header-line" }, h2(i18n.pollsTitle), p(i18n.pollsDescription))),
|
||||
renderFilterBar(String(params.filter || "ALL").toUpperCase(), params.q, false),
|
||||
section(div({ class: "tribe-details" }, pollSide, pollMain))
|
||||
);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue