Import pwic as source, add overrides

This commit imports the latest source of the pwic module directly
and modifies it just enough for it to be an importable module.

Source: https://github.com/gitbra/pwic
This commit is contained in:
evilchili
2025-09-21 14:56:05 -07:00
parent 2dfb63e061
commit 7aa6f03d5d
88 changed files with 26410 additions and 6 deletions
@@ -0,0 +1,14 @@
<ul>
{% if pwic.env.support_email %}
<li>{% trans %}By email:{% endtrans %} <a href="mailto:{{pwic.env.support_email.value|urlencode}}">{{pwic.env.support_email.value|escape}}</a></li>
{% endif %}
{% if pwic.env.support_phone %}
<li>{% trans %}By phone:{% endtrans %} <a href="tel:{{pwic.env.support_phone.value|replace(' ','')|urlencode}}">{{pwic.env.support_phone.value|escape}}</a></li>
{% endif %}
{% if pwic.env.support_url %}
<li>{% trans %}On a portal:{% endtrans %} <a href="{{pwic.env.support_url.value|escape}}">{{pwic.env.support_url.value|escape}}</a></li>
{% endif %}
{% if pwic.env.support_text %}
<li>{{pwic.env.support_text.value|escape|replace('\\n','<br>')}}</li>
{% endif %}
</ul>
@@ -0,0 +1,24 @@
<p id="page_topofpage" class="pwic_hidden">
<a href="#top">{{pwic.emojis.top}} {% trans %}Top of the page{% endtrans %} {{pwic.emojis.top}}</a>
</p>
<footer>
<div>
{% trans %}Powered by{% endtrans %} <a href="https://pwic.wiki">Pwic.wiki</a> v{{pwic.constants.version|escape}} &copy; {% if pwic.env.copyright_years %}{{pwic.env.copyright_years.value|escape}}{% else %}2020-2025{% endif %}
{% if not pwic.env.no_help %}
&mdash; {{pwic.emojis.help}}&nbsp;<a href="/special/help">{% trans %}Help{% endtrans %}</a>
{% endif %}
&mdash;
{% if not pwic.user|reserved_user_name %}
{{pwic.emojis.laptop}}&nbsp;<a href="/special/user/{{pwic.user|urlencode}}" title="{% trans %}Your profile{% endtrans %}" rel="nofollow">{{pwic.user|escape}}</a> (<a class="pwic_bold" href="/special/logout" onclick="return confirm({% trans %}'Are you sure to disconnect from Pwic.wiki?'{% endtrans %})">{% trans %}Log out{% endtrans %}</a>)
{% else %}
<a class="pwic_bold" href="/special/login">{% trans %}Log in{% endtrans %}</a>
{% endif %}
</div>
</footer>
<script>
$('H1,H2,H3,H4,H5,H6,TH,TD,P,DIV,SPAN,A,LI').removeClass('pwic_js');
pwic_url_status({% trans %}'The operation is a success.'{% endtrans %}, {% trans %}'The operation failed.'{% endtrans %});
</script>
File diff suppressed because it is too large Load Diff
+57
View File
@@ -0,0 +1,57 @@
{% extends 'html/main.html' %}
{% block title %}{% trans %}Connect to Pwic.wiki{% endtrans %}{% endblock %}
{% block content %}
<header>
<div class="pwic_ph1"><a href="/">{{pwic.emojis.finger_up}} {% trans %}Connect to Pwic.wiki{% endtrans %}</a></div>
</header>
<article>
{% if pwic.env.no_login %}
<p class="pwic_warning">{{pwic.emojis.pin}} {% trans %}This instance is accessible anonymously.{% endtrans %}</p>
{% endif %}
<p class="pwic_error" id="login_js">{{pwic.emojis.red_check}} {% trans %}Your browser is incompatible or enable JavaScript.{% endtrans %}</p>
<form id="login_form" action="/api/login?redirect" method="post">
<p><strong>{% trans %}User:{% endtrans %}</strong> <input class="pwic_fill" type="text" id="login_user" name="user" autofocus autocomplete="username" required="true" spellcheck="false"></p>
<p><strong>{% trans %}Password:{% endtrans %}</strong> <input class="pwic_fill" type="password" id="login_password" name="password" autocomplete="current-password"></p>
{% if pwic.env.totp %}
<p><strong>{% trans %}Optional PIN code for 2FA:{% endtrans %}</strong>
<br><input type="number" id="login_pin" name="pin" min="0" max="999999"></p>
{% endif %}
<p {% if pwic.constants.languages|count == 1 %} class="pwic_hidden" {% endif %}>
<strong>{% trans %}Language:{% endtrans %}</strong>
<br><select id="login_language" name="language">
{% for lang in pwic.constants.languages %}
<option value="{{lang|escape}}"
{% if lang == pwic.language %}
selected="selected"
{% endif %}
>{{lang|escape}}</option>
{% endfor %}
</select>
</p>
<p>
<input type="submit" value="{{pwic.emojis.plug}} {% trans %}Log in{% endtrans %}">
<input type="button" value="{{pwic.emojis.alien}} {% trans %}Anonymous login{% endtrans %}" onclick="login_anonymous()">
{% if pwic.env.oauth_provider %}
<input type="button" value="{{pwic.emojis.id}} {% trans %}Federated login{% endtrans %}" onclick="login_oauth()">
{% endif %}
{% if pwic.env.registration_link %}
<input type="button" value="{{pwic.emojis.users}} {% trans %}Register{% endtrans %}" onclick="login_register()">
{% endif %}
</p>
</form>
</article>
{% include 'js/login.js' %}
<script>
login_translate_langs({ 'de': 'Deutsch',
'en': 'English',
'fr': 'Français'
});
</script>
{% endblock %}
@@ -0,0 +1,21 @@
{% extends 'html/main.html' %}
{% block title %}{% trans %}Disconnected from Pwic.wiki{% endtrans %}{% endblock %}
{% block content %}
<header>
<div class="pwic_ph1"><a href="/">{% trans %}You are disconnected{% endtrans %}</a></div>
</header>
<article>
<p class="pwic_information">{{pwic.emojis.globe}} {% trans %}You successfully logged out.{% endtrans %}</p>
<p>{% trans %}You can go back to:{% endtrans %}</p>
<ol>
<li><a href="/">{% trans %}the selection of a new project{% endtrans %}</a></li>
<li><a href="/special/login">{% trans %}the login page{% endtrans %}</a></li>
</ol>
</article>
{% endblock %}
+190
View File
@@ -0,0 +1,190 @@
<!DOCTYPE html>
<html lang="{% if pwic.env.language %}{{pwic.env.language.value|escape}}{% else %}{{pwic.language|escape}}{% endif %}"
dir="{% if pwic.env.language and (pwic.env.language.value in pwic.constants.rtl) %}rtl{% else %}ltr{% endif %}">
<head>
<!-- General headers -->
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="generator" content="Pwic.wiki version {{pwic.constants.version|escape}}">
{% if pwic.env.robots %}
<meta name="robots" content="{{pwic.env.robots.value|replace(' ',', ')|escape}}">
{% endif %}
<meta charset="utf-8">
<meta name="description" content="{{(pwic.description or gettext('No description'))|escape}}">
{% if pwic.keywords %}
<meta name="keywords" content="{{pwic.keywords|escape}}">
{% endif %}
<title>{% block title %}{{pwic.title|escape}}{% endblock %}{% if pwic.env.title %} - {{pwic.env.title.value|escape}}{% endif %}</title>
{% if pwic.canonical %}
<link rel="canonical" href="{{pwic.canonical|escape}}">
{% endif %}
<link rel="icon" type="image/png" href="/static/favicon.png">
{% if pwic.project and (pwic.project not in pwic.constants.not_project) %}
{% if not pwic.env.no_sitemap %}
<link rel="sitemap" type="application/xml" href="/{{pwic.project|urlencode}}/special/sitemap">
{% endif %}
{% if not pwic.env.no_search %}
<link rel="search" type="application/opensearchdescription+xml" href="/{{pwic.project|urlencode}}/special/searchlink" title="{{ gettext('Search in project %(project)s')|format(project=pwic.project|escape) }}">
{% endif %}
{% if pwic.env.manifest %}
<link rel="manifest" href="/{{pwic.project|urlencode}}/special/manifest">
{% endif %}
{% if not pwic.env.no_feed and (not pwic.pure_reader or not pwic.env.no_history) %}
<link rel="alternate" type="application/atom+xml" href="/{{pwic.project|urlencode}}/special/feed/atom" title="{{ gettext('Recent changes for %(project)s (%(format)s)')|format(project=pwic.project|escape, format='ATOM') }}">
<link rel="alternate" type="application/rss+xml" href="/{{pwic.project|urlencode}}/special/feed/rss" title="{{ gettext('Recent changes for %(project)s (%(format)s)')|format(project=pwic.project|escape, format='RSS') }}">
{% endif %}
{% endif %}
<!-- Styles -->
<link rel="stylesheet" type="text/css" href="/static/styles.css" media="all">
{% if pwic.env.css %}
{% set list = pwic.env.css.value.split(';') %}
{% for css in list %}
<link rel="stylesheet" type="text/css" href="{{css|trim|urlencode}}" media="all">
{% endfor %}
{% endif %}
{% if pwic.env.dark_theme %}
<link rel="stylesheet" type="text/css" href="/static/styles_dark.css" media="screen">
{% if pwic.env.css_dark %}
{% set list = pwic.env.css_dark.value.split(';') %}
{% for css in list %}
<link rel="stylesheet" type="text/css" href="{{css|trim|urlencode}}" media="screen">
{% endfor %}
{% endif %}
{% endif %}
<link rel="stylesheet" type="text/css" href="/static/styles-print.css" media="print">
{% if pwic.env.css_printing %}
{% set list = pwic.env.css_printing.value.split(';') %}
{% for css in list %}
<link rel="stylesheet" type="text/css" href="{{css|trim|urlencode}}" media="print">
{% endfor %}
{% endif %}
{% if pwic.env.no_printing %}
<style media="print">
BODY { display: none }
</style>
{% endif %}
<!-- Scripts -->
<script src="/static/cash.min.js"></script>
{% block header_scripts %}{% endblock %}
<script>
'use strict';
function pwic_entities(value) {
return value.replaceAll('<', '&lt;').replaceAll('>', '&gt;').replaceAll('"', '&quot;');
}
function pwic_is_safe(name) {
if (name == '')
return false;
var chars = '{{pwic.constants.unsafe_chars|replace("\\", "\\\\")|replace("'", "\\'")}}';
for (var i=0 ; i<chars.length ; i++)
if (name.indexOf(chars[i]) !== -1)
return false;
return true;
}
function pwic_kick(value, chars) {
while (true) {
var curlen = value.length;
for (var i=0 ; i<chars.length ; i++)
value = value.replaceAll(chars[i], '');
if (value.length == curlen)
break;
}
return value;
}
function pwic_slash(value) {
{# sof/18251399 #}
return value.split("'").join("\\'").split('"').join('\\"');
}
function pwic_unimoji(value) {
return value.replace(/&#x([0-9a-f]+);/gi, (match, v) => {
return String.fromCodePoint(parseInt(v, 16));
});
}
function pwic_url_status(success, failed) {
var url = window.location.toString();
if ((url.indexOf('?success') !== -1) || (url.indexOf('&success') !== -1))
alert(success);
else
if ((url.indexOf('?failed') !== -1) || (url.indexOf('&failed') !== -1))
alert(failed);
}
</script>
</head>
<body id="top">
{% block content %}{% endblock %}
{% include 'html/footer.html' %}
<script>
'use strict';
{% if not pwic.env.no_sort_table %}
function pwic_table_sort(that, column) {
function _get_sort_key(obj) {
var v, list = $(obj).find('INPUT[type=checkbox]');
if (list.length > 0)
return (!list.prop('checked')).toString();
v = (obj.dataset.sort || obj.innerText).trim();
if (v == '')
return '';
if (/^-?\d+( *%)?$/.test(v))
return parseInt(v.replace('%', '').trim());
v = v.replaceAll(',', '.');
if ((/^-?\d+(\.\d*)?(e-?\d+)?$/.test(v)) || (/^-?\.\d+(e-?\d+)?$/.test(v)))
return parseFloat(v);
return v.trim().toLowerCase();
}
var e = $(that),
table = e.parents('TABLE')[0],
i, j, op, data, src;
// Sort order
op = parseInt(e.data('sort') || '1');
e.data('sort', -op);
// Cache and sort the data
data = [];
for (i=1 ; i<table.rows.length ; i++)
data.push([i, _get_sort_key($(table.rows[i]).find('TD')[column])]);
data.sort(function(a, b) {
if (a[1] == b[1])
return 0;
return (a[1] < b[1] ? -1 : 1) * op;
});
// Update DOM
for (i=0 ; i<data.length ; i++) {
src = data[i][0];
if (src != i + 1) {
table.rows[src].parentNode.insertBefore(table.rows[src], table.rows[i+1]);
for (j=0; j<data.length; j++)
if (data[j][0] < src)
data[j][0]++;
}
}
}
$('TABLE').each(function(i, e) {
$(e).find('TR TH').each(function(i, e) {
e.innerHTML = '<span class="pwic_cursor" title="{% trans %}Sort{% endtrans %}" onclick="pwic_table_sort(this, '+i+')">' + (e.innerHTML||'...') + '<\/span>';
});
});
{% endif %}
{% if pwic.env.link_new_tab %}
$('A[href^="http"]').attr('target','_blank');
{% endif %}
</script>
</body>
</html>
@@ -0,0 +1,32 @@
{% extends 'html/main.html' %}
{% block title %}{% trans %}Page not found{% endtrans %}{% endblock %}
{% block content %}
<header>
<div class="pwic_ph1"><a href="/{{pwic.project|urlencode}}">{{pwic.project_description|escape}}</a></div>
{% if pwic.links|count > 0 %}
<div class="pwic_tagbox">
{% for link in pwic.links %}
<a href="/{{pwic.project|urlencode}}/{{link.page|urlencode}}">{{link.title|escape}}</a>
{% endfor %}
</div>
{% endif %}
</header>
<article>
<p class="pwic_error">{{pwic.emojis.padlock}} {% trans %}The page does not exist.{% endtrans %}</p>
<p>{% trans %}Please verify your authorizations, the spelling of the link and the revision level of the page.{% endtrans %}</p>
<p>{% trans %}You can go back to:{% endtrans %}</p>
<ol>
<li class="pwic_js"><a href="#" onclick="history.back()">{% trans %}your last browsed page{% endtrans %}</a></li>
<li><a href="/{{pwic.project|urlencode}}/{{pwic.page|urlencode}}">{% trans %}the latest revision of the page{% endtrans %}</a></li>
<li><a href="/{{pwic.project|urlencode}}">{% trans %}the home page of the project{% endtrans %}</a></li>
<li class="pwic_js"><a href="/{{pwic.project|urlencode}}/special/page?page={{pwic.page|urlencode}}">{% trans %}the creation of the missing page{% endtrans %}</a></li>
<li><a href="/{{pwic.project|urlencode}}/special">{% trans %}the special page of the project{% endtrans %}</a></li>
<li><a href="/">{% trans %}the selection of a new project{% endtrans %}</a></li>
</ol>
</article>
{% endblock %}
@@ -0,0 +1,93 @@
{% extends 'html/main.html' %}
{% block title %}{% trans %}Audit{% endtrans %}{% endblock %}
{% block content %}
<header>
<div class="pwic_ph1"><a href="/{{pwic.project|urlencode}}/special">{{pwic.emojis.finger_left}} {% trans %}Audit of the activities{% endtrans %}</a></div>
<div class="pwic_ph2">[{{pwic.project|escape}}] {{pwic.project_description|escape}}</div>
</header>
<article>
<div class="pwic_action_bar">
<a href="/{{pwic.project|urlencode}}/special/env">{{pwic.emojis.pill}} {% trans %}Settings{% endtrans %}</a>
{% if not pwic.env.no_help %}
<a href="/special/help#help_setup">{{pwic.emojis.help}} {% trans %}Help{% endtrans %}</a>
{% endif %}
</div>
<h1>{% trans %}Server information{% endtrans %}</h1>
<p>{{ gettext('The server has started on %(date)s at %(time)s.')|format(date=pwic.up.date|escape, time=pwic.up.time|escape) }}</p>
<p>{{ gettext('The current time on the server is %(date)s at %(time)s.')|format(date=pwic.systime.date|escape, time=pwic.systime.time|escape) }}</p>
<p>{{ gettext('You are connected in %(protocol)s.')|format(protocol=pwic.protocol|escape) }}</p>
<h1>{% trans %}Environment variables{% endtrans %}</h1>
<table id="audit_envs">
<tr>
<th>{% trans %}Key{% endtrans %}</th>
<th>{% trans %}Scope{% endtrans %}</th>
<th>{% trans %}Value{% endtrans %}</th>
</tr>
</table>
{% if pwic.audits|count > 0 %}
<h1>{{ gettext('Audit of the last %(n)d days')|format(n=pwic.range) }}</h1>
<table>
<tr>
<th>{% trans %}Date{% endtrans %}</th>
<th>{% trans %}Time{% endtrans %}</th>
<th>{% trans %}Author{% endtrans %}</th>
<th>{% trans %}Event{% endtrans %}</th>
<th class="pwic_desktop">{% trans %}Project{% endtrans %}</th>
<th>{% trans %}Page{% endtrans %}</th>
<th class="pwic_desktop">{% trans %}Reference{% endtrans %}</th>
<th class="pwic_desktop">{% trans %}String{% endtrans %}</th>
</tr>
{% for audit in pwic.audits %}
<tr>
<td class="pwic_nowrap">{{audit.date|escape}}</td>
<td>{{audit.time|escape}}</td>
<td><a class="pwic_break" href="/special/user/{{audit.author|urlencode}}" rel="nofollow">{{audit.author|escape}}</a></td>
<td>{{audit.event|escape}}</td>
<td class="pwic_desktop">
{% if audit.project != '' %}
<a href="/{{audit.project|urlencode}}">{{audit.project|escape}}</a>
{% endif %}
</td>
<td>
{% if audit.page != '' %}
<a href="/{{audit.project|urlencode}}/{{audit.page|urlencode}}">{{audit.page|escape}}</a>
{% endif %}
</td>
<td class="pwic_desktop">
{% if audit.reference > 0 %}
{% if audit.event[-9:] == '-revision' %}
<a href="/{{audit.project|urlencode}}/{{audit.page|urlencode}}/rev{{audit.reference|urlencode}}">{{audit.reference|escape}}</a>
{% elif audit.event[-9:] == '-document' %}
<a href="/special/document/{{audit.reference|urlencode}}?attachment" target="_blank">{{audit.reference|escape}}</a>
{% else %}
?
{% endif %}
{% endif %}
</td>
<td class="pwic_desktop">
{% if audit.string != '' %}
{{audit.string|escape}}
{% elif audit.user != '' %}
<a class="pwic_break" href="/special/user/{{audit.user|urlencode}}" rel="nofollow">{{audit.user|escape}}</a>
{% endif %}
</td>
</tr>
{% endfor %}
</table>
{% endif %}
{% include 'js/page-audit.js' %}
</article>
{% endblock %}
@@ -0,0 +1,17 @@
{% extends 'html/main.html' %}
{% block content %}
<header>
<div class="pwic_ph1"><a href="/{{pwic.project|urlencode}}">{{pwic.project_description|escape}}</a></div>
<div class="pwic_ph2"><a href="/{{pwic.project|urlencode}}/{{pwic.page|urlencode}}/history">{{pwic.emojis.finger_left}} [{{pwic.page|escape}}] {{pwic.title|escape}}</a></div>
</header>
<article>
<h2>Comparison of <a href="/{{pwic.project|urlencode}}/{{pwic.page|urlencode}}/rev{{pwic.old_revision|escape}}">revision {{pwic.old_revision|escape}}</a> and <a href="/{{pwic.project|urlencode}}/{{pwic.page|urlencode}}/rev{{pwic.new_revision|escape}}">revision {{pwic.new_revision|escape}}</a></h2>
<hr>
{{pwic.diff}}
</article>
{% endblock %}
@@ -0,0 +1,53 @@
{% extends 'html/main.html' %}
{% block title %}{% trans %}Create a new page{% endtrans %}{% endblock %}
{% block content %}
<header>
<div class="pwic_ph1"><a href="/">{{pwic.emojis.finger_left}} {% trans %}Create a new page{% endtrans %}</a></div>
</header>
<article>
{% if pwic.projects|count == 0 %}
<p class="pwic_error">{{pwic.emojis.padlock}} {% trans %}You have no authorization to create a new page. Please contact your manager.{% endtrans %}</p>
{% else %}
<h1>{% trans %}New page{% endtrans %}</h1>
<p><strong>{% trans %}Project:{% endtrans %}</strong><br>
<select id="create_project">
{% for proj in pwic.projects %}
<option value="{{proj.project|escape}}"
{% if proj.project == pwic.default_project %} selected="selected" {% endif %}
>{{proj.description|escape}} [{{proj.project|escape}}]</option>
{% endfor %}
</select>
</p>
<p><strong>{% trans %}Page identifier:{% endtrans %}</strong>
<br><input id="create_kb" type="checkbox"> <label for="create_kb">{% trans %}Generate a knowledge base article{% endtrans %}</label>
<br><input id="create_page" class="pwic_fill" type="text" value="{{pwic.default_page|escape}}" spellcheck="false"></p>
<p><strong>{% trans %}Tags:{% endtrans %}</strong> <input id="create_tags" class="pwic_fill" type="text" title="{% trans %}No hash and separated by a space{% endtrans %}" spellcheck="false"></p>
<p><strong>{% trans %}Milestone:{% endtrans %}</strong> <input id="create_milestone" class="pwic_fill" type="text"></p>
<h1>{% trans %}Copy in reference to another page{% endtrans %}</h1>
<p><strong>{% trans %}Project:{% endtrans %}</strong><br>
<select id="create_ref_project">
<option value=""></option>
{% for p in pwic.projects %}
<option value="{{p.project|escape}}">{{p.description|escape}} [{{p.project|escape}}]</option>
{% endfor %}
</select>
</p>
<p><strong>{% trans %}Page identifier:{% endtrans %}</strong> <input id="create_ref_page" class="pwic_fill" type="text" spellcheck="false"></p>
<p><input id="create_ref_tags" type="checkbox" checked="checked"> <label for="create_ref_tags">{% trans %}Copy and merge the tags{% endtrans %}</label></p>
<p><input type="button" value="{{pwic.emojis.sparkles}} {% trans %}Create the page{% endtrans %}" onclick="create_submit()"></p>
{% include 'js/page-create.js' %}
{% endif %}
</article>
{% endblock %}
@@ -0,0 +1,149 @@
{% extends 'html/main.html' %}
{% block header_scripts %}
<link rel="stylesheet" type="text/css" href="/static/codemirror.min.css">
<style>
.CodeMirror { height: 75vh; margin-top: 5px; border: 1px solid black }
</style>
<script src="/static/codemirror_md.min.js"></script>
{% endblock %}
{% block content %}
<header>
<div class="pwic_ph1"><a href="/{{pwic.project|urlencode}}/{{pwic.page|urlencode}}">{{pwic.emojis.finger_left}} {% trans %}Edit the page{% endtrans %}</a></div>
</header>
<article>
<h1>[{{pwic.page|escape}}] {{pwic.title|escape}}</h1>
{% if not pwic.manager and (pwic.protection or not pwic.editor) %}
<p class="pwic_error">{{pwic.emojis.padlock}} {% trans %}You are not authorized to edit the page.{% endtrans %}</p>
{% else %}
<form id="edit_form" action="/api/page/edit" method="post">
<p><strong><span class="pwic_red">*</span> {% trans %}Title:{% endtrans %}</strong> <input id="edit_title" class="pwic_fill" type="text" value="{{pwic.title|escape}}"></p>
<p><strong>{% trans %}Tags:{% endtrans %}</strong> <input id="edit_tags" class="pwic_fill" type="text" value="{{pwic.tags|escape}}" title="{% trans %}No hash and separated by a space{% endtrans %}" spellcheck="false"></p>
<div id="edit_toolbar">
<div>
<input type="button" value="{{pwic.emojis.glasses}}" title="{% trans %}Preview{% endtrans %}" onclick="edit_preview_md('{{pwic.page|urlencode}}')" data-shortcut="Ctrl-E">
<input type="button" value="{{pwic.emojis.round_arrow_left}}" title="{% trans %}Undo{% endtrans %}" onclick="edit_undo(true)" data-shortcut="Ctrl-Z">
<input type="button" value="{{pwic.emojis.round_arrow_right}}" title="{% trans %}Redo{% endtrans %}" onclick="edit_undo(false)" data-shortcut="Ctrl-Y">
</div>
<div>
<input type="button" value="B" title="** {% trans %}Bold{% endtrans %} **" style="font-weight: bold" onclick="edit_decorate('**', '**')" data-shortcut="Ctrl-B">
<input type="button" value="I" title="* {% trans %}Italic{% endtrans %} *" style="font-style: italic" onclick="edit_decorate('*', '*')" data-shortcut="Ctrl-I">
<input type="button" value="U" title="-- {% trans %}Underline{% endtrans %} --" style="text-decoration: underline" onclick="edit_decorate('--', '--')" data-shortcut="Ctrl-U">
<input type="button" value="S" title="~~ {% trans %}Strikethrough{% endtrans %} ~~" style="text-decoration: line-through" onclick="edit_decorate('~~', '~~')">
<input type="button" value="^2" title="<sup> {% trans %}Superscript{% endtrans %} </sup>" onclick="edit_decorate('<sup>', '</sup>')">
<input type="button" value="_2" title="<sub> {% trans %}Subscript{% endtrans %} </sub>" onclick="edit_decorate('<sub>', '</sub>')">
<input type="button" value="{{pwic.emojis.chains}}" title="[{% trans %}Link{% endtrans %}](url)" onclick="edit_link()" data-shortcut="Ctrl-K">
</div>
<div>
<input type="button" value="abCD" title="{% trans %}Upper/Lower case{% endtrans %}" onclick="edit_switch_case()" data-shortcut="Shift-F3">
<input type="button" value="{{pwic.emojis.double}}" title="{% trans %}No double spaces{% endtrans %}" onclick="edit_double_spaces()">
<input type="button" value="{{pwic.emojis.right}}" title="{% trans %}Shift to the right{% endtrans %}" onclick="edit_prepend(' ')">
<input type="button" value="{{pwic.emojis.left}}" title="{% trans %}Shift to the left{% endtrans %}" onclick="edit_left_line()">
<input type="button" value="{{pwic.emojis.noblank}}" title="{% trans %}No blank line{% endtrans %}" onclick="edit_no_blank_line()">
<input type="button" value="{{pwic.emojis.oneline}}" title="{% trans %}As single line{% endtrans %}" onclick="edit_single_line()">
</div>
<div>
<input type="button" value="H1" title="# {% trans %}Title{% endtrans %} 1" onclick="edit_prepend('# ')" data-shortcut="Shift-Ctrl-F1">
<input type="button" value="H2" title="## {% trans %}Title{% endtrans %} 2" onclick="edit_prepend('## ')" data-shortcut="Shift-Ctrl-F2">
<input type="button" value="H3" title="### {% trans %}Title{% endtrans %} 3" onclick="edit_prepend('### ')" data-shortcut="Shift-Ctrl-F3">
<input type="button" value="H4" title="#### {% trans %}Title{% endtrans %} 4" onclick="edit_prepend('#### ')" data-shortcut="Shift-Ctrl-F4">
<input type="button" value="H5" title="##### {% trans %}Title{% endtrans %} 5" onclick="edit_prepend('##### ')" data-shortcut="Shift-Ctrl-F5">
<input type="button" value="H6" title="###### {% trans %}Title{% endtrans %} 6" onclick="edit_prepend('###### ')" data-shortcut="Shift-Ctrl-F6">
<input type="button" value="{% trans %}Footnote{% endtrans %}" title="[^1] {% trans %}Footnote{% endtrans %}" onclick="edit_footnote()">
<input type="button" value="[{% trans %}Annotation{% endtrans %}]" title="&lt;!-- {% trans %}Annotation{% endtrans %} --&gt;" onclick="edit_decorate('&lt;!-- ', ' --&gt;')">
</div>
<div>
<input type="button" value="{% trans %}Line{% endtrans %}" title="{% trans %}Horizontal line{% endtrans %}" onclick="edit_decorate('\n---\n\n', '')">
<input id="edit_toolbar_table" type="button" value="Table" title="{% trans %}Table{% endtrans %} | {% trans %}Table{% endtrans %}" onclick="edit_table()">
<input type="button" value="{% trans %}AutoTable{% endtrans %}" title="{% trans %}Paste as target table{% endtrans %}" onclick="edit_table_import()">
<input type="button" value="- {% trans %}List{% endtrans %}" title="- {% trans %}Bulleted list{% endtrans %}" onclick="edit_prepend('- ')" data-shortcut="Ctrl-L">
<input type="button" value="1. {% trans %}List{% endtrans %}" title="1. {% trans %}Numbered list{% endtrans %}" onclick="edit_prepend_nlist()">
<input type="button" value="- [X] {% trans %}Tasks{% endtrans %}" onclick="edit_prepend('- [ ] ')">
<input type="button" value="> {% trans %}Quote{% endtrans %}" onclick="edit_prepend('> ')">
<input type="button" value=">! {% trans %}Spoiler{% endtrans %}" onclick="edit_prepend('>! ')">
<input type="button" value="`{% trans %}Keyword{% endtrans %}`" title="`{% trans %}Monospaced keyword{% endtrans %}`" onclick="edit_decorate('`', '`')" data-shortcut="Ctrl-'">
<input type="button" value="{% trans %}Code{% endtrans %}" title="```{% trans %}Code{% endtrans %}```" onclick="edit_decorate('```\n', '\n```')">
{% if pwic.env.emojis %}
<input type="button" value="{{pwic.emojis.bang}}" title="{% trans %}Emojis{% endtrans %}" onclick="$('#edit_emojis').toggleClass('pwic_hidden');md_editor.focus()">
{% endif %}
{% if pwic.env.remote_url %}
<input type="button" value="{{pwic.emojis.recycle}}" title="{% trans %}Fetch a remote web page{% endtrans %}" onclick="edit_convert_remote_document()">
{% endif %}
{% if not pwic.env.no_dictation %}
<input id="edit_toolbar_dictate" type="button" value="{{pwic.emojis.microphone}}" title="{% trans %}Dictate{% endtrans %}">
{% endif %}
</div>
</div>
{% if pwic.env.emojis %}
<div id="edit_emojis" class="pwic_hidden">
{% set list = pwic.emojis_toolbar.split(' ') %}
{% for e in list %}
{% if e|is_hex %}
{% if e[-4:] == 'fe0f' %}
{% set e = '&#x' + e[:-4]|upper + ';&#xFE0F;' %}
{% else %}
{% set e = '&#x' + e|upper + ';' %}
{% endif %}
<span title="{% trans %}Insert{% endtrans %}" onclick="edit_decorate_end('{{e|escape}} ')">{{e}}</span>
{% endif %}
{% endfor %}
</div>
{% endif %}
<textarea id="edit_markdown">{{pwic.markdown|escape}}</textarea>
{% if (not pwic.env.document_size_max) or (pwic.env.document_size_max.value|int > 0) %}
<h2>{% trans %}Documents{% endtrans %}</h2>
<div id="edit_files_drop" ondrop="edit_drop(event)" ondragover="edit_dragover(event)" ondragleave="edit_dragleave(event)">
<input type="button" value="{{pwic.emojis.refresh}}" title="{% trans %}Refresh{% endtrans %}" onclick="edit_refresh_documents()">
<input class="pwic_mobile" type="button" value="{{pwic.emojis.inbox}}" title="{% trans %}Upload a new document{% endtrans %}" onclick="edit_upload_document()" style="margin-left: 15px">
<br>
{% trans %}Drop the files here{% endtrans %}
{% if pwic.env.document_size_max %}
({% trans %}max:{% endtrans %} {{pwic.env.document_size_max.value|size2str|escape}})
{% endif %}
{% trans %}and save immediately{% endtrans %}
</div>
<table id="edit_files_list" class="pwic_break">
<tr>
<th>{% trans %}Action{% endtrans %}</th>
<th>{% trans %}File name{% endtrans %}</th>
<th class="pwic_desktop" title="{% trans %}For the latest saved revision only{% endtrans %}">{% trans %}Used{% endtrans %}</th>
<th>{% trans %}Size{% endtrans %}</th>
<th class="pwic_desktop">{% trans %}Format{% endtrans %}</th>
<th class="pwic_desktop">{% trans %}Author{% endtrans %}</th>
<th>{% trans %}Date{% endtrans %}</th>
<th class="pwic_desktop">{% trans %}Time{% endtrans %}</th>
<th>{% trans %}File{% endtrans %}</th>
</tr>
</table>
{% endif %}
<h2>{% trans %}Attributes{% endtrans %}</h2>
<p><strong><span class="pwic_red">*</span> {% trans %}Reason for the modification:{% endtrans %}</strong> <input id="edit_comment" class="pwic_fill" type="text" placeholder="{{pwic.comment|escape}}"></p>
<p><strong>{% trans %}Milestone:{% endtrans %}</strong> <input id="edit_milestone" class="pwic_fill" type="text" value="{{pwic.milestone|escape}}" title="{% trans %}Free text to report the expected readiness of the page{% endtrans %}"></p>
<p>
<input id="edit_draft" type="checkbox" {% if pwic.draft %}checked="checked"{% endif %} onclick="$('#edit_final').prop('checked', false)"> <label for="edit_draft">{% trans %}Draft{% endtrans %}</label>
<br><input id="edit_final" type="checkbox" onclick="$('#edit_draft').prop('checked', false)"> <label for="edit_final">{% trans %}Final version{% endtrans %}</label>
<br><input id="edit_header" type="checkbox" {% if pwic.header %}checked="checked"{% endif %} {% if not pwic.manager %}disabled="disabled"{% endif %}> <label for="edit_header">{% trans %}Header line *{% endtrans %}</label>
<br><input id="edit_protection" type="checkbox" {% if pwic.protection %}checked="checked"{% endif %} {% if not pwic.manager %}disabled="disabled"{% endif %}> <label for="edit_protection">{% trans %}Protected page *{% endtrans %}</label>
</p>
<p>
<input id="edit_submit" type="button" value="{{pwic.emojis.save}} {% trans %}Save the modifications{% endtrans %}" onclick="edit_submit_form()">
<input id="edit_preview" type="button" value="{{pwic.emojis.glasses}} {% trans %}Preview{% endtrans %}" onclick="edit_preview_md('{{pwic.page|urlencode}}')">
</p>
</form>
{% include 'js/page-edit.js' %}
{% endif %}
</article>
{% endblock %}
@@ -0,0 +1,37 @@
{% extends 'html/main.html' %}
{% block title %}{% trans %}Project-dependent environment variables{% endtrans %}{% endblock %}
{% block content %}
<header>
<div class="pwic_ph1"><a href="/{{pwic.project|urlencode}}/special">{{pwic.emojis.finger_left}} {% trans %}Project-dependent settings{% endtrans %}</a></div>
<div class="pwic_ph2">[{{pwic.project|escape}}] {{pwic.project_description|escape}}</div>
</header>
<article>
<p>{% trans %}The following settings are changeable online and they are applicable to the current project only.{% endtrans %}</p>
<p>{{ gettext('Refer to your administrator to configure the <a href="/%(project)s/special/audit">other environment variables</a> (whose details are available in the <a href="/special/help#help_setup">help page</a>), or if you want a setting to apply once for all the projects hosted on the server.')|format(project=pwic.project|urlencode) }}</p>
<table>
<tr>
<th style="width:33%">{% trans %}Variable{% endtrans %}</th>
<th style="width:67%">{% trans %}Value{% endtrans %}</th>
</tr>
{% for key in pwic.changeable_vars %}
<tr>
<td><code>{{key|escape}}</code></td>
<td style="padding-right: 10px">
<input class="pwic_fill" type="text" data-key="{{key|escape}}">
<input type="button" data-key="{{key|escape}}" value="{{pwic.emojis.save}} {% trans %}Save{% endtrans %}">
</td>
</tr>
{% endfor %}
</table>
<p class="pwic_center"><a href="env" onclick="return confirm({% trans %}'Are you sure to reset the current changes?'{% endtrans %})">{% trans %}Cancel the current modifications{% endtrans %}</a></p>
</article>
{% include 'js/page-env.js' %}
{% endblock %}
@@ -0,0 +1,19 @@
{% extends 'html/main.html' %}
{% block title %}{% trans %}Graph of the project{% endtrans %}{% endblock %}
{% block content %}
<header>
<div class="pwic_ph1"><a href="/{{pwic.project|urlencode}}/special">{{pwic.emojis.finger_left}} {% trans %}Visual representation of the pages{% endtrans %}</a></div>
<div class="pwic_ph2">[{{pwic.project|escape}}] {{pwic.project_description|escape}}</div>
</header>
<article>
<p><input type="button" value="{{pwic.emojis.inbox}} {% trans %}Download as a file{% endtrans %}" onclick="graph_get_data('download')"></p>
<div id="graph_viz"></div>
{% include 'js/page-graph.js' %}
</article>
{% endblock %}
@@ -0,0 +1,50 @@
{% extends 'html/main.html' %}
{% block content %}
<header>
<div class="pwic_ph1"><a href="/{{pwic.project|urlencode}}/{{pwic.page|urlencode}}">{{pwic.emojis.finger_left}} {% trans %}History of the modifications{% endtrans %}</a></div>
<div class="pwic_ph2"><a href="/{{pwic.project|urlencode}}">[{{pwic.project|escape}}] {{pwic.project_description|escape}}</a></div>
</header>
{% include 'js/page-history.js' %}
<article>
<h1>[{{pwic.page|escape}}] {{pwic.title|escape}}</h1>
<table>
<tr>
<th class="pwic_js"><span class="pwic_desktop">{% trans %}Compare{% endtrans %}</span></th>
<th>{% trans %}Rev<span class="pwic_desktop">ision</span>{% endtrans %}</th>
<th>{% trans %}Flags{% endtrans %}</th>
<th>{% trans %}Author{% endtrans %}</th>
<th>{% trans %}Date{% endtrans %}</th>
<th class="pwic_desktop">{% trans %}Time{% endtrans %}</th>
<th>{% trans %}Comment{% endtrans %}</th>
<th class="pwic_desktop">{% trans %}Milestone{% endtrans %}</th>
</tr>
{% for rev in pwic.revisions %}
<tr>
<td class="pwic_js"><input type="checkbox" data-revision="{{rev.revision|escape}}" onclick="return history_compare()"></td>
<td><a href="/{{pwic.project|urlencode}}/{{pwic.page|urlencode}}/rev{{rev.revision|urlencode}}">{{rev.revision|escape}}</a></td>
<td>
{% if rev.draft %}
<span title="{% trans %}Draft{% endtrans %}">{{pwic.emojis.hourglass}}</span>
{% endif %}
{% if rev.final %}
<span title="{% trans %}Marked as final{% endtrans %}">{{pwic.emojis.notes}}</span>
{% endif %}
{% if rev.valuser != '' %}
<span title="{{ gettext('Validated by %(valuser)s on %(valdate)s at %(valtime)s.')|format(valuser=rev.valuser|escape, valdate=rev.valdate|escape, valtime=rev.valtime|escape) }}">{{pwic.emojis.flag}}</span>
{% endif %}
</td>
<td><a class="pwic_break" href="/special/user/{{rev.author|urlencode}}" rel="nofollow">{{rev.author|escape}}</a></td>
<td>{{rev.date|escape}}</td>
<td class="pwic_desktop">{{rev.time|escape}}</td>
<td>{{rev.comment|escape}}</td>
<td class="pwic_desktop">{{rev.milestone|escape}}</td>
</tr>
{% endfor %}
</table>
</article>
{% endblock %}
@@ -0,0 +1,68 @@
{% extends 'html/main.html' %}
{% block title %}{% trans %}Report of the links{% endtrans %}{% endblock %}
{% block content %}
<header>
<div class="pwic_ph1"><a href="/{{pwic.project|urlencode}}/special">{{pwic.emojis.finger_left}} {% trans %}Verification of the links{% endtrans %}</a></div>
<div class="pwic_ph2">[{{pwic.project|escape}}] {{pwic.project_description|escape}}</div>
</header>
<article>
<h1>{% trans %}Orphaned pages{% endtrans %}</h1>
{% if pwic.orphans|count == 0 %}
<p>{% trans %}You have no orphaned page.{% endtrans %}</p>
{% else %}
<p>{% trans %}These pages cannot be reached by simple clicks but are still referenced by the search engine.{% endtrans %}</p>
<ul>
{% for page in pwic.orphans %}
<li><a href="/{{pwic.project|urlencode}}/{{page|urlencode}}">{{page|escape}}</a></li>
{% endfor %}
</ul>
{% endif %}
<h1>{% trans %}Broken links to a page{% endtrans %}</h1>
{% if pwic.broken|count == 0 %}
<p>{% trans %}You have no broken link to a page.{% endtrans %}</p>
{% else %}
<p>{% trans %}A broken link displays the error 404 because the targeted page does not exist.{% endtrans %}</p>
<table class="pwic_fit">
<tr>
<th>{% trans %}Page{% endtrans %}</th>
<th>{% trans %}Non-existent page{% endtrans %}</th>
</tr>
{% for page in pwic.broken %}
<tr>
<td><a href="/{{pwic.project|urlencode}}/{{page[0]|urlencode}}">{{page[0]|escape}}</a></td>
<td>{{pwic.emojis.sheet}} <a href="/{{pwic.project|urlencode}}/special/page?page={{page[1]|urlencode}}" title="{% trans %}Create the page{% endtrans %}">{{page[1]|escape}}</a></td>
</tr>
{% endfor %}
</table>
<p class="pwic_italic">{% trans %}Note: the table does not check the links to the other projects.{% endtrans %}</p>
{% endif %}
<h1>{% trans %}Broken links to a document{% endtrans %}</h1>
{% if pwic.broken_docs|count == 0 %}
<p>{% trans %}You have no broken link to a document.{% endtrans %}</p>
{% else %}
<p>{% trans %}Managing the files without updating the pages may result in invalid links.{% endtrans %}</p>
<table class="pwic_fit">
<tr>
<th>{% trans %}Page{% endtrans %}</th>
<th>{% trans %}Non-existent document{% endtrans %}</th>
</tr>
{% for page in pwic.broken_docs %}
<tr>
<td><a href="/{{pwic.project|urlencode}}/{{page|urlencode}}/edit">{{page|escape}}</a></td>
<td>{{pwic.broken_docs[page]|sort|join(', ')|escape}}</td>
</tr>
{% endfor %}
</table>
{% endif %}
</article>
{% endblock %}
@@ -0,0 +1,58 @@
{% extends 'html/main.html' %}
{% block title %}{% trans %}Move a page{% endtrans %}{% endblock %}
{% block content %}
<header>
<div class="pwic_ph1"><a href="/{{pwic.project|urlencode}}/{{pwic.page|urlencode}}">{{pwic.emojis.finger_left}} {% trans %}Move the page and its attachments{% endtrans %}</a></div>
</header>
<article>
<h1>[{{pwic.project|escape}}/{{pwic.page|escape}}] {{pwic.title|escape}}</h1>
<input id="move_src_project" type="hidden" value="{{pwic.project|escape}}">
<input id="move_src_page" type="hidden" value="{{pwic.page|escape}}">
<p><strong>{% trans %}Target project:{% endtrans %}</strong><br>
<select id="move_dst_project">
{% for proj in pwic.projects %}
<option value="{{proj.project|escape}}"
{% if proj.project == pwic.project %} selected="selected" {% endif %}
>{{proj.description|escape}} [{{proj.project|escape}}]</option>
{% endfor %}
</select>
</p>
<p><strong>{% trans %}Target page identifier:{% endtrans %}</strong> <input id="move_dst_page" class="pwic_fill" type="text" placeholder="{{pwic.page|escape}}" spellcheck="false"></p>
<p><input type="button" value="{{pwic.emojis.truck}} {% trans %}Move the page{% endtrans %}" onclick="move_submit()"></p>
<p class="pwic_italic">
{% trans %}This form can be used to rename an existing page.{% endtrans %}
{% if pwic.relations|count > 0 %}
{% trans %}No link will be updated within the following pages:{% endtrans %}
{% endif %}
</p>
{% if pwic.relations|count > 0 %}
<table>
<tr>
<th>{% trans %}Link{% endtrans %}</th>
<th>{% trans %}Title{% endtrans %}</th>
<th>{% trans %}Date{% endtrans %}</th>
</tr>
{% for row in pwic.relations %}
<tr>
<td><a href="/{{row.project|urlencode}}/{{row.page|urlencode}}">/{{row.project|escape}}/{{row.page|escape}}</a></td>
<td>{{row.title|escape}}</td>
<td>{{row.date|escape}}</td>
</tr>
{% endfor %}
</table>
{% endif %}
{% include 'js/page-move.js' %}
</article>
{% endblock %}
@@ -0,0 +1,261 @@
{% extends 'html/main.html' %}
{% block content %}
<header>
<div class="pwic_ph1"><a href="/{{pwic.project|urlencode}}">{{pwic.emojis.finger_up}} {{pwic.project_description|escape}}</a></div>
{% if (not pwic.env.no_search) or (pwic.links|count > 0) %}
<div class="pwic_tagbox">
{% for link in pwic.links %}
<a href="/{{pwic.project|urlencode}}/{{link.page|urlencode}}">{{link.title|escape}}</a>
{% endfor %}
{% if not pwic.env.no_search %}
<div class="pwic_searchbox pwic_js">
{{pwic.emojis.search}}
<input type="text" id="page_search" onkeypress="page_search()">
</div>
{% endif %}
</div>
{% endif %}
</header>
{% if not pwic.env.no_search %}
{% include 'js/search.js' %}
{% endif %}
<article>
{% if pwic.env.maintenance %}
<div class="pwic_error">{{pwic.emojis.calendar}} {{pwic.env.maintenance.value|escape}}</div>
{% endif %}
{% if pwic.env.message %}
<div class="pwic_information">{{pwic.emojis.pin}} {{pwic.env.message.value|escape}}</div>
{% endif %}
<div class="pwic_action_bar">
{% if pwic.admin %}
<a class="pwic_js" href="/{{pwic.project|urlencode}}/special/user">{{pwic.emojis.users}} {% trans %}New user{% endtrans %}</a>
<a class="pwic_js" href="/{{pwic.project|urlencode}}/special/roles">{{pwic.emojis.key}} {% trans %}Roles{% endtrans %}</a>
<a href="/{{pwic.project|urlencode}}/special/audit">{{pwic.emojis.glasses}} {% trans %}Audit{% endtrans %}</a>
<a class="pwic_js" href="/{{pwic.project|urlencode}}/special/env">{{pwic.emojis.pill}} {% trans %}Settings{% endtrans %}</a>
{% endif %}
{% if pwic.manager %}
<a class="pwic_js" href="/{{pwic.project|urlencode}}/special/page">{{pwic.emojis.sparkles}} {% trans %}New page{% endtrans %}</a>
{% endif %}
{% if not pwic.env.no_feed and (not pwic.pure_reader or not pwic.env.no_history) %}
<a href="/{{pwic.project|urlencode}}/special/feed/atom">{{pwic.emojis.atom}} {% trans %}ATOM{% endtrans %}</a>
<a href="/{{pwic.project|urlencode}}/special/feed/rss">{{pwic.emojis.rss}} {% trans %}RSS{% endtrans %}</a>
{% endif %}
{% if pwic.manager %}
{% if not pwic.env.no_link_review %}
<a href="/{{pwic.project|urlencode}}/special/links">{{pwic.emojis.chains}} {% trans %}Links{% endtrans %}</a>
{% endif %}
{% if not pwic.env.no_graph %}
<a class="pwic_js" href="/{{pwic.project|urlencode}}/special/graph">{{pwic.emojis.globe}} {% trans %}Graph{% endtrans %}</a>
{% endif %}
{% endif %}
{% if pwic.admin and not pwic.env.no_export_project %}
<a class="pwic_desktop" href="/{{pwic.project|urlencode}}/special/export/zip" title="{{ gettext('Export to format %(format)s')|format(format='ZIP') }}">{{pwic.emojis.clamp}} ZIP</a>
{% endif %}
<a class="pwic_js" href="/api">{{pwic.emojis.brick}} {% trans %}API{% endtrans %}</a>
<a href="/{{pwic.project|urlencode}}/special/random">{{pwic.emojis.dice}} {% trans %}Random page{% endtrans %}</a>
</div>
{% if pwic.env.support_email or pwic.env.support_phone or pwic.env.support_url or pwic.env.support_text %}
<h1>{% trans %}Internal support{% endtrans %}</h1>
{% include 'html/block-support.html' %}
{% endif %}
{% if pwic.recents|count > 0 %}
<h1 class="pwic_cursor" title="{% trans %}Expand/Collapse{% endtrans %}" onclick="$('#page_updates_list').toggleClass('pwic_hidden')">{% trans %}Recent updates{% endtrans %}</h1>
<table id="page_updates_list">
<tr>
<th>{% trans %}Date{% endtrans %}</th>
<th class="pwic_desktop">{% trans %}Time{% endtrans %}</th>
<th>{% trans %}Page{% endtrans %}</th>
<th class="pwic_desktop">{% trans %}Author{% endtrans %}</th>
<th>{% trans %}Comment{% endtrans %}</th>
<th class="pwic_desktop">{% trans %}Milestone{% endtrans %}</th>
</tr>
{% for recent in pwic.recents %}
<tr>
<td class="pwic_nowrap">{{recent.date|escape}}</td>
<td class="pwic_desktop">{{recent.time|escape}}</td>
<td><a href="/{{pwic.project|urlencode}}/{{recent.page|urlencode}}">{{recent.title|escape}}</a></td>
<td class="pwic_desktop"><a class="pwic_break" href="/special/user/{{recent.author|urlencode}}" rel="nofollow">{{recent.author|escape}}</a></td>
<td>{{recent.comment|escape}}</td>
<td class="pwic_desktop">{{recent.milestone|escape}}</td>
</tr>
{% endfor %}
</table>
{% endif %}
{% if pwic.admins|count + pwic.managers|count + pwic.editors|count + pwic.validators|count + pwic.readers|count > 0 %}
<h1 class="pwic_cursor" title="{% trans %}Expand/Collapse{% endtrans %}" onclick="$('#page_members_list').toggleClass('pwic_hidden')">{% trans %}Team members{% endtrans %}</h1>
<ul id="page_members_list">
{% if pwic.admins|count > 0 %}
<li><strong>{% trans %}Administrators:{% endtrans %}</strong>
{% for admin in pwic.admins %}
<a href="/special/user/{{admin|urlencode}}" rel="nofollow">{{admin|escape}}</a>
{% endfor %}
</li>
{% endif %}
{% if pwic.managers|count > 0 %}
<li><strong>{% trans %}Managers:{% endtrans %}</strong>
{% for manager in pwic.managers %}
<a href="/special/user/{{manager|urlencode}}" rel="nofollow">{{manager|escape}}</a>
{% endfor %}
</li>
{% endif %}
{% if pwic.editors|count > 0 %}
<li><strong>{% trans %}Editors:{% endtrans %}</strong>
{% for editor in pwic.editors %}
<a href="/special/user/{{editor|urlencode}}" rel="nofollow">{{editor|escape}}</a>
{% endfor %}
</li>
{% endif %}
{% if pwic.validators|count > 0 %}
<li><strong>{% trans %}Validators:{% endtrans %}</strong>
{% for validator in pwic.validators %}
<a href="/special/user/{{validator|urlencode}}" rel="nofollow">{{validator|escape}}</a>
{% endfor %}
</li>
{% endif %}
{% if pwic.readers|count > 0 %}
<li><strong>{% trans %}Readers:{% endtrans %}</strong>
{% if pwic.readers|count > 100 %}
too many users.
{% else %}
{% for reader in pwic.readers %}
<a href="/special/user/{{reader|urlencode}}" rel="nofollow">{{reader|escape}}</a>
{% endfor %}
{% endif %}
</li>
{% endif %}
</ul>
{% endif %}
{% if (pwic.pages|count > 0) and (not pwic.user|reserved_user_name) %}
<h1 class="pwic_cursor" title="{% trans %}Expand/Collapse{% endtrans %}" onclick="$('#page_pages_list').toggleClass('pwic_hidden')">{% trans %}All the pages of the project{% endtrans %}</h1>
<table id="page_pages_list">
<tr>
<th>{% trans %}Page{% endtrans %}</th>
<th>{% trans %}Title{% endtrans %}</th>
<th class="pwic_desktop">{% trans %}Revision{% endtrans %}</th>
<th>{% trans %}Flags{% endtrans %}</th>
<th>{% trans %}Author{% endtrans %}</th>
<th class="pwic_desktop">{% trans %}Date{% endtrans %}</th>
<th class="pwic_desktop">{% trans %}Time{% endtrans %}</th>
<th class="pwic_desktop">{% trans %}Milestone{% endtrans %}</th>
</tr>
{% for page in pwic.pages %}
<tr>
<td>{{page.page|escape}}</td>
<td><a href="/{{pwic.project|urlencode}}/{{page.page|urlencode}}">{{page.title|escape}}</a></td>
<td class="pwic_desktop">{{page.revision|escape}}</td>
<td>
{% if page.draft %}
<span title="{% trans %}Draft{% endtrans %}">{{pwic.emojis.hourglass}}</span>
{% endif %}
{% if page.final %}
<span title="{% trans %}Marked as final{% endtrans %}">{{pwic.emojis.notes}}</span>
{% endif %}
{% if page.valuser != '' %}
<span title="{{ gettext('Validated by %(valuser)s on %(valdate)s at %(valtime)s.')|format(valuser=page.valuser|escape, valdate=page.valdate|escape, valtime=page.valtime|escape) }}">{{pwic.emojis.flag}}</span>
{% endif %}
</td>
<td><a class="pwic_break" href="/special/user/{{page.author|urlencode}}" rel="nofollow">{{page.author|escape}}</a></td>
<td class="pwic_desktop pwic_nowrap">{{page.date|escape}}</td>
<td class="pwic_desktop">{{page.time|escape}}</td>
<td class="pwic_desktop">{{page.milestone|escape}}</td>
</tr>
{% endfor %}
</table>
{% endif %}
{% if (pwic.tags|count > 0) and (not pwic.user|reserved_user_name) %}
<h1 class="pwic_js">{% trans %}Progress by tag{% endtrans %}</h1>
<div id="page_progress_tags" class="pwic_tagbox pwic_js">
<a href="#" title="{% trans %}Select all{% endtrans %}">{{pwic.emojis.check}}</a>
<a href="#" title="{% trans %}Deselect all{% endtrans %}">{{pwic.emojis.red_check}}</a>
<a class="pwic_spacer" href="#" title="{% trans %}Combined selection{% endtrans %}">{{pwic.emojis.paperclip}}</a>
{% for tag in pwic.tags %}
<a href="#" title="{% trans %}De/Select this tag{% endtrans %}">#{{tag|escape}}</a>
{% endfor %}
</div>
<table id="page_progress_list" class="pwic_hidden">
<tr>
<th>{% trans %}Tag{% endtrans %}</th>
<th>{% trans %}Draft{% endtrans %}</th>
<th class="pwic_desktop">{{pwic.emojis.updown}}</th>
<th>{% trans %}Step{% endtrans %}</th>
<th class="pwic_desktop">{{pwic.emojis.updown}}</th>
<th>{% trans %}Final{% endtrans %}</th>
<th class="pwic_desktop">{{pwic.emojis.updown}}</th>
<th>{% trans %}Validated{% endtrans %}</th>
<th class="pwic_desktop">{{pwic.emojis.updown}}</th>
</tr>
</table>
{% include 'js/page-special-progress.js' %}
{% endif %}
{% if (pwic.documents|count > 0) and (not pwic.user|reserved_user_name) %}
<h1 class="pwic_cursor" title="{% trans %}Expand/Collapse{% endtrans %}" onclick="$('#page_documents_space, #page_documents_list').toggleClass('pwic_hidden')">{% trans %}All the documents of the project{% endtrans %}</h1>
<p id="page_documents_space" class="pwic_center"><strong>{% trans %}Disk space usage:{% endtrans %}</strong>
{% if pwic.disk_space.project_max > 0 %}
<span class="pwic_progressbar">
<span style="width:{{pwic.disk_space.percentage|escape}}%">&nbsp;</span>
</span>
<span class="pwic_nowrap">{{pwic.disk_space.used|size2str|escape}} / {{pwic.disk_space.project_max|size2str|escape}} ({{pwic.disk_space.percentage|escape}} %)</span>
{% else %}
{{pwic.disk_space.used|size2str|escape}}
{% endif %}
</p>
<table id="page_documents_list">
<tr>
<th class="pwic_desktop">{% trans %}Page{% endtrans %}</th>
<th>{% trans %}File name{% endtrans %}</th>
<th class="pwic_desktop">{% trans %}Format{% endtrans %}</th>
<th>{% trans %}Size{% endtrans %}</th>
<th class="pwic_desktop">{% trans %}Hash{% endtrans %}</th>
<th>{% trans %}Author{% endtrans %}</th>
<th class="pwic_desktop">{% trans %}Date{% endtrans %}</th>
<th class="pwic_desktop">{% trans %}Time{% endtrans %}</th>
<th><span class="pwic_desktop">{% trans %}Download{% endtrans %}</span></th>
</tr>
{% for doc in pwic.documents %}
<tr>
<td class="pwic_desktop"><a href="/{{doc.project|urlencode}}/{{doc.page|urlencode}}">{{doc.page|escape}}</a></td>
<td>
<a class="pwic_break" href="/special/document/{{doc.id|urlencode}}/{{doc.filename|urlencode}}">{{doc.filename|escape}}</a>
{% if doc.exturl != ''%}
<span title="{% trans %}External storage{% endtrans %}">{{pwic.emojis.cloud}}</span>
{% endif%}
</td>
<td class="pwic_desktop" title="{{doc.mime|escape}}">{{doc.mime_icon}} {{doc.extension|upper}}</td>
<td data-sort="{{doc.size|escape}}">{{doc.size|size2str|escape}}</td>
<td class="pwic_desktop">
<span title="{{doc.hash|escape}}">{{doc.hash[:8]|escape}}</span>
{% if doc.occurrence > 1 %}
<span title="{% trans %}Duplicate file{% endtrans %}">{{pwic.emojis.gemini}}</span>
{% endif %}
</td>
<td><a class="pwic_break" href="/special/user/{{doc.author|urlencode}}" rel="nofollow">{{doc.author|escape}}</a></td>
<td class="pwic_desktop pwic_nowrap">{{doc.date|escape}}</td>
<td class="pwic_desktop">{{doc.time|escape}}</td>
<td><a href="/special/document/{{doc.id|urlencode}}?attachment">{{pwic.emojis.inbox}}</a></td>
</tr>
{% endfor %}
</table>
{% endif %}
</article>
{% endblock %}
@@ -0,0 +1,47 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>API specification for Pwic.wiki</title>
<link rel="stylesheet" type="text/css" href="/static/api/swagger-ui.css" >
<style>
html {
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
*, *:before, *:after {
box-sizing: inherit;
}
body {
margin: 0;
background: #fafafa;
}
</style>
</head>
<body>
<div id="swagger-ui"></div>
<script src="/static/api/swagger-ui-bundle.js"></script>
<script src="/static/api/swagger-ui-standalone-preset.js"></script>
<script>
window.onload = function() {
const ui = SwaggerUIBundle({
url: '/static/api/swagger.txt',
dom_id: '#swagger-ui',
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: 'StandaloneLayout'
});
window.ui = ui;
};
</script>
</body>
</html>
+192
View File
@@ -0,0 +1,192 @@
{% extends 'html/main.html' %}
{% block header_scripts %}
{% if pwic.env.mathjax %}
<script>
window.MathJax = {
tex: { inlineMath: [['$', '$'], ['\\(', '\\)']] },
svg: { fontCache: 'global' }
};
</script>
<script src="/static/mathjax.min.js" async></script>
{% endif %}
{% endblock %}
{% block content %}
<header>
<div class="pwic_ph1"><a href="/{% if pwic.page != pwic.constants['default_home'] %}{{pwic.project|urlencode}}{% endif %}">{{pwic.project_description|escape}}</a></div>
{% if (not pwic.env.no_search) or (pwic.links|count > 0) %}
<div class="pwic_tagbox">
{% for link in pwic.links %}
<a href="/{{pwic.project|urlencode}}/{{link.page|urlencode}}">{{link.title|escape}}</a>
{% endfor %}
{% if not pwic.env.no_search %}
<div class="pwic_searchbox pwic_js">
{{pwic.emojis.search}}
<input type="text" id="page_search" onkeypress="page_search()">
</div>
{% endif %}
</div>
{% endif %}
</header>
<article>
<div id="pwic_progress"></div>
{% if pwic.env.maintenance %}
<div class="pwic_error">{{pwic.emojis.calendar}} {{pwic.env.maintenance.value|escape|replace('\\n','<br>')}}</div>
{% endif %}
{% if pwic.env.message %}
<div class="pwic_information">{{pwic.emojis.pin}} {{pwic.env.message.value|escape|replace('\\n','<br>')}}</div>
{% endif %}
<div class="pwic_action_bar">
{% if pwic.protection %}
<span title="{% trans %}The page is protected{% endtrans %}">{{pwic.emojis.padlock}}</span>
{% endif %}
<a href="/{{pwic.project|urlencode}}/special">{{pwic.emojis.star}} {% trans %}Special{% endtrans %}</a>
{% if pwic.manager %}
<a class="pwic_js" href="/{{pwic.project|urlencode}}/special/page">{{pwic.emojis.sparkles}} {% trans %}New page{% endtrans %}</a>
{% endif %}
{% if pwic.latest and (pwic.manager or (pwic.editor and not pwic.protection)) %}
<a class="pwic_js" href="/{{pwic.project|urlencode}}/{{pwic.page|urlencode}}/edit">{{pwic.emojis.set_square}} {% trans %}Edit{% endtrans %}</a>
{% endif %}
{% if not pwic.pure_reader or not pwic.env.no_history %}
<a href="/{{pwic.project|urlencode}}/{{pwic.page|urlencode}}/history">{{pwic.emojis.clock}} {% trans %}History{% endtrans %}</a>
{% endif %}
{% if pwic.manager %}
<a class="pwic_js" href="/{{pwic.project|urlencode}}/{{pwic.page|urlencode}}/move">{{pwic.emojis.truck}} {% trans %}Move{% endtrans %}</a>
{% endif %}
<a class="pwic_js" href="#" onclick="return page_email()">{{pwic.emojis.outbox}} {% trans %}Email{% endtrans %}</a>
{% if not pwic.env.no_printing %}
<a class="pwic_desktop pwic_js" href="#" onclick="return page_print()">{{pwic.emojis.printer}} {% trans %}Print{% endtrans %}</a>
{% endif %}
{% set no_formats = pwic.env.get('file_formats_disabled', {'value': ''}).value.split(' ') %}
{% if '*' not in no_formats %}
{% for f in pwic.file_formats %}
{% if f not in no_formats %}
<a class="pwic_js" href="#" title="{% trans %}Export to{% endtrans %} {{f|escape|upper}}" onclick="return page_export('{{f|escape}}')">{{pwic.emojis.save}} {{f|escape|upper}}</a>
{% endif %}
{% endfor %}
{% endif %}
{% if pwic.validator and (pwic.valuser == '') and pwic.final %}
<a class="pwic_js" href="#" onclick="return page_post_action('validate', {% trans %}'The validation cannot be undone.\n\nDo you want to continue?'{% endtrans %})">{{pwic.emojis.validate}} {% trans %}Validate{% endtrans %}</a>
{% endif %}
{% if pwic.removable %}
<a class="pwic_js" href="#" onclick="return page_post_action('delete', {% trans %}'Warning: deleting the revision cannot be undone.\n\nDo you want to continue?'{% endtrans %})">{{pwic.emojis.trashcan}} {% trans %}Delete{% endtrans %}</a>
{% endif %}
</div>
{% if not pwic.latest %}
<p class="pwic_warning">{{pwic.emojis.eye}}
{% if pwic.env.validated_only %}
{{ gettext('You are viewing the <span class="pwic_bold">revision %(revision)d</span> and <a href="/%(project)s/%(page)s/history">other revisions</a> are pending.')|format(revision=pwic.revision, project=pwic.project|urlencode, page=pwic.page|urlencode) }}
{% else %}
{{ gettext('You are viewing the <span class="pwic_bold">revision %(revision)d</span>, but the <a href="/%(project)s/%(page)s">latest version</a> is available.')|format(revision=pwic.revision, project=pwic.project|urlencode, page=pwic.page|urlencode) }}
{% endif %}
</p>
{% endif %}
{% if pwic.valuser != '' %}
<p class="pwic_information">{{pwic.emojis.flag}} {{ gettext('This page has been validated by <a href="/special/user/%(user1)s" rel="nofollow">%(user2)s</a> on %(sdate)s at %(stime)s.')|format(user1=pwic.valuser|urlencode, user2=pwic.valuser|escape, sdate=pwic.valdate|escape, stime=pwic.valtime|escape) }}</p>
{% endif %}
{% if pwic.tmap|count + pwic.documents|count > 1 %}
<div id="pwic_browser_access" class="pwic_js" title="{% trans %}Show/Hide the map of the page{% endtrans %}" onclick="page_tmap()">
{{pwic.emojis.pin}}
</div>
<div id="pwic_browser" class="pwic_hidden">
{% for tmap in pwic.tmap %}
<a class="pwic_browser_item pwic_browser_item_h{{tmap.level}}" href="#{{tmap.tag|urlencode}}" onclick="page_tmap()">{% if not pwic.env.no_heading %}<span class="pwic_bold">{{tmap.header|escape}}</span> {% endif %}{{tmap.title|no_html|escape}}</a>
{% endfor %}
{% if not pwic.env.no_document_list and (pwic.documents|count + pwic.images|count > 0) %}
<a class="pwic_browser_item pwic_browser_item_h1" href="#page_documents" onclick="page_tmap()">{{pwic.emojis.scroll}} {% trans %}Attached documents{% endtrans %}</a>
{% endif %}
</div>
{% endif %}
{% if pwic.relations|count > 0 %}
<p id="pwic_relations">
<span class="pwic_bold">{% trans %}Related pages:{% endtrans %}</span>
{% for p in pwic.relations %}
{% if loop.index > 1 %} &ndash; {% endif %}
<a href="{{p[0]|escape}}">{{p[1]|escape}}</a>
{% endfor %}
</p>
{% endif %}
{% if pwic.tags|count > 0 %}
<div class="pwic_tagbox">
{% for tag in pwic.tags %}
{% if pwic.env.no_search %}
<a href="#" onclick="return false">#{{tag|escape}}</a>
{% else %}
<a href="/{{pwic.project|urlencode}}/special/search?q=%23{{tag|urlencode}}" title="{% trans %}Search for related classified pages{% endtrans %}">#{{tag|escape}}</a>
{% endif %}
{% endfor %}
</div>
{% endif %}
{{pwic.html}}
{% if not pwic.env.no_document_list and (pwic.documents|count + pwic.images|count > 0) %}
<h1 id="page_documents" class="pwic_cursor" title="{% trans %}Expand/Collapse{% endtrans %}" onclick="$('#page_section_files').toggleClass('pwic_hidden')">{% trans %}Attached documents{% endtrans %}</h1>
<div id="page_section_files">
{% if pwic.documents|count > 0 %}
<div class="pwic_file_gallery">
{% if pwic.documents|count + pwic.images|count > 1 %}
<a href="/{{pwic.project|urlencode}}/special/documents/{{pwic.page|urlencode}}" rel="nofollow">
<span>{% trans %}Download all{% endtrans %}</span>
<br>{{pwic.emojis.inbox}}
</a>
{% endif %}
{% for doc in pwic.documents %}
<a href="/special/document/{{doc.id|urlencode}}/{{doc.filename|urlencode}}" title="{{ gettext('Uploaded by %(author)s on %(date)s at %(time)s.')|format(author=doc.author|escape, date=doc.date|escape, time=doc.time|escape) }}">
<span>{{doc.filename|escape}}</span>
<br><small>{{doc.mime|escape}}</small> ({{doc.size|size2str|escape}})
</a>
{% endfor %}
</div>
{% endif %}
{% if pwic.images|count > 0 %}
<div class="pwic_file_gallery">
{% if (pwic.documents|count == 0) and (pwic.images|count > 1) %}
<a href="/{{pwic.project|urlencode}}/special/documents/{{pwic.page|urlencode}}" rel="nofollow">
<span>{% trans %}Download all{% endtrans %}</span>
<br>{{pwic.emojis.inbox}}
</a>
{% endif %}
{% for doc in pwic.images %}
<a href="/special/document/{{doc.id|urlencode}}/{{doc.filename|urlencode}}" title="{{ gettext('Uploaded by %(author)s on %(date)s at %(time)s.')|format(author=doc.author|escape, date=doc.date|escape, time=doc.time|escape) }}">
<span>{{doc.filename|escape}}</span>
<br><small>{{doc.mime|escape}}</small> ({{doc.size|size2str|escape}})
</a>
{% endfor %}
</div>
{% endif %}
</div>
{% endif %}
<p id="page_lastmod">
{{ gettext('Revision <span class="pwic_bold">#%(revision)d</span> was last modified by <a href="/special/user/%(author1)s" rel="nofollow">%(author2)s</a><br>on %(date)s at %(time)s &mdash; <span title="Hash: %(hash)s">%(shash)s</span>')|format(revision=pwic.revision, author1=pwic.author|urlencode, author2=pwic.author|escape, date=pwic.date|escape, time=pwic.time|escape, hash=pwic.hash|escape, shash=pwic.hash[:16]|escape) }}
</p>
{% if pwic.env.legal_notice %}
<div id="page_legal_notice">{{pwic.env.legal_notice.value|escape|replace('\n','<br>')}}</div>
{% endif %}
</article>
<!-- Scripts -->
{% include 'js/page.js' %}
{% if not pwic.env.no_search %}
{% include 'js/search.js' %}
{% endif %}
{% endblock %}
@@ -0,0 +1,22 @@
{% extends 'html/main.html' %}
{% block title %}{% trans %}No access{% endtrans %}{% endblock %}
{% block content %}
<header>
<div class="pwic_ph1"><a href="/">{{pwic.emojis.finger_up}} [{{pwic.project|escape}}] {% trans %}Access denied{% endtrans %}</a></div>
</header>
<article>
<p class="pwic_error">{{pwic.emojis.red_check}} {% trans %}You don't have the authorizations to access this project.{% endtrans %}</p>
{% if pwic.env.support_email or pwic.env.support_phone or pwic.env.support_url or pwic.env.support_text %}
<p>{% trans %}To request your access, get in touch with the support team:{% endtrans %}</p>
{% include 'html/block-support.html' %}
{% else %}
<p>{% trans %}Unfortunately, there is no defined support information to request your access.{% endtrans %}</p>
{% endif %}
</article>
{% endblock %}
@@ -0,0 +1,62 @@
{% extends 'html/main.html' %}
{% block title %}{% trans %}Select your project{% endtrans %}{% endblock %}
{% block content %}
<header>
<div class="pwic_ph1">{{pwic.emojis.home}} {% trans %}Select your project{% endtrans %}</div>
</header>
<article>
<div class="pwic_action_bar">
<a class="pwic_js" href="/api">{{pwic.emojis.brick}} {% trans %}API{% endtrans %}</a>
{% if not pwic.env.no_help %}
<a href="/special/help">{{pwic.emojis.help}} {% trans %}Help{% endtrans %}</a>
{% endif %}
</div>
{% if (pwic.projects|count + pwic.joinable_projects|count) == 0 %}
<p>{% trans %}Unfortunately, you have access to no project at all.{% endtrans %}</p>
{% endif %}
{% if pwic.projects|count > 0 %}
<h1 class="pwic_cursor" title="{% trans %}Expand/Collapse{% endtrans %}" onclick="$('#projects_1').toggleClass('pwic_hidden')">{% trans %}Joined projects{% endtrans %}</h1>
<table id="projects_1">
<tr>
<th>{% trans %}Project{% endtrans %}</th>
<th>{% trans %}Description{% endtrans %}</th>
<th class="pwic_desktop">{% trans %}Last activity{% endtrans %}</th>
<th class="pwic_desktop">{% trans %}Creation date{% endtrans %}</th>
</tr>
{% for p in pwic.projects %}
<tr>
<td>{{p.project|escape}}</td>
<td><a href="/{{p.project|urlencode}}">{{p.description|escape}}</a></td>
<td class="pwic_desktop">{{(p.last_activity or '-')|escape}}</td>
<td class="pwic_desktop">{{p.date|escape}}</td>
</tr>
{% endfor %}
</table>
{% endif %}
{% if pwic.joinable_projects|count > 0 %}
<h1 class="pwic_cursor" title="{% trans %}Expand/Collapse{% endtrans %}" onclick="$('#projects_2').toggleClass('pwic_hidden')">{% trans %}Available public projects{% endtrans %}</h1>
<table id="projects_2">
<tr>
<th>{% trans %}Project{% endtrans %}</th>
<th>{% trans %}Description{% endtrans %}</th>
<th class="pwic_desktop">{% trans %}Date{% endtrans %}</th>
</tr>
{% for p in pwic.joinable_projects %}
<tr>
<td>{{p.project|escape}}</td>
<td><a href="/{{p.project|urlencode}}">{{p.description|escape}}</a></td>
<td class="pwic_desktop">{{p.date|escape}}</td>
</tr>
{% endfor %}
</table>
{% endif %}
</article>
{% endblock %}
+100
View File
@@ -0,0 +1,100 @@
{% extends 'html/main.html' %}
{% block title %}{% trans %}Search{% endtrans %}{% endblock %}
{% block content %}
<header>
<div class="pwic_ph1"><a href="/{{pwic.project|urlencode}}">{{pwic.emojis.finger_left}} {{pwic.project_description|escape}}</a></div>
</header>
{% include 'js/search.js' %}
<article>
<h1>{{pwic.pages|count + pwic.documents|count}} {% trans %}results{% endtrans %}</h1>
<p>{% trans %}Search terms:{% endtrans %}
<input id="page_search" class="pwic_fill" type="text" value="{{pwic.terms|escape}}" onkeypress="page_search()">
{% if not pwic.pure_reader or not pwic.env.no_history %}
<span class="pwic_js">
<input id="page_search_withrev" type="checkbox" {% if 'rev' in pwic.args %}checked="checked"{% endif %} onclick="page_start_search()">
<label for="page_search_withrev">{% trans %}Include the old revisions{% endtrans %}</label>,
</div>
{% endif %}
<span class="pwic_js">
<input id="page_search_casesensitive" type="checkbox" {% if 'cs' in pwic.args %}checked="checked"{% endif %} onclick="page_start_search()">
<label for="page_search_casesensitive">{% trans %}Case-sensitive{% endtrans %}</label>
</div>
</p>
{% if pwic.pages|count > 0 %}
<h2>{% trans %}Pages{% endtrans %}</h2>
<table>
<tr>
<th>{% trans %}Page{% endtrans %}</th>
<th class="pwic_desktop">{% trans %}Revision{% endtrans %}</th>
<th>{% trans %}Title{% endtrans %}</th>
<th>{% trans %}Flags{% endtrans %}</th>
<th class="pwic_desktop">{% trans %}Author{% endtrans %}</th>
<th>{% trans %}Date{% endtrans %}</th>
<th class="pwic_desktop">{% trans %}Time{% endtrans %}</th>
<th class="pwic_desktop">{% trans %}Score{% endtrans %}</th>
</tr>
{% for page in pwic.pages %}
<tr>
<td>{{page.page|escape}}</td>
<td class="pwic_desktop">{{page.revision|escape}}</td>
<td><a href="/{{page.project|urlencode}}/{{page.page|urlencode}}{% if not page.latest %}/rev{{page.revision|urlencode}}{% endif %}">{{page.title|escape}}</a></td>
<td>
{% if pwic.with_rev and page.latest %}
<span title="{% trans %}Latest{% endtrans %}">{{pwic.emojis.watch}}</span>
{% endif %}
{% if page.draft %}
<span title="{% trans %}Draft{% endtrans %}">{{pwic.emojis.hourglass}}</span>
{% endif %}
{% if page.final %}
<span title="{% trans %}Marked as final{% endtrans %}">{{pwic.emojis.notes}}</span>
{% endif %}
{% if page.valuser != '' %}
<span title="{{ gettext('Validated by %(valuser)s on %(valdate)s at %(valtime)s.')|format(valuser=page.valuser|escape, valdate=page.valdate|escape, valtime=page.valtime|escape) }}">{{pwic.emojis.flag}}</span>
{% endif %}
</td>
<td class="pwic_desktop"><a class="pwic_break" href="/special/user/{{page.author|urlencode}}" rel="nofollow">{{page.author|escape}}</a></td>
<td>{{page.date|escape}}</td>
<td class="pwic_desktop">{{page.time|escape}}</td>
<td class="pwic_desktop">{{page.score|escape}}</td>
</tr>
{% endfor %}
</table>
{% endif %}
{% if pwic.documents|count > 0 %}
<h2>{% trans %}Documents{% endtrans %}</h2>
<table>
<tr>
<th>{% trans %}Page{% endtrans %}</th>
<th>{% trans %}File name{% endtrans %}</th>
<th class="pwic_desktop">{% trans %}Format{% endtrans %}</th>
<th>{% trans %}Size{% endtrans %}</th>
<th class="pwic_desktop">{% trans %}Author{% endtrans %}</th>
<th>{% trans %}Date{% endtrans %}</th>
<!-- <th class="pwic_desktop">{% trans %}Time{% endtrans %}</th> -->
</tr>
{% for doc in pwic.documents %}
<tr>
<td><a href="/{{pwic.project|urlencode}}/{{doc.page|urlencode}}">{{doc.page|escape}}</a></td>
<td><a href="/special/document/{{doc.id|urlencode}}/{{doc.filename|escape}}">{{doc.filename|escape}}</a></td>
<td class="pwic_desktop" title="{{doc.mime|escape}}">{{doc.mime_icon}} {{doc.extension|upper}}</td>
<td>{{doc.size|size2str|escape}}</td>
<td class="pwic_desktop"><a class="pwic_break" href="/special/user/{{doc.author|urlencode}}" rel="nofollow">{{doc.author|escape}}</a></td>
<td>{{doc.date|escape}}</td>
<!-- <td class="pwic_desktop">{{doc.time|escape}}</td> -->
</tr>
{% endfor %}
</table>
{% endif %}
</article>
{% endblock %}
@@ -0,0 +1,36 @@
{% extends 'html/main.html' %}
{% block title %}{% trans %}Create a new user{% endtrans %}{% endblock %}
{% block content %}
<header>
<div class="pwic_ph1"><a href="/">{{pwic.emojis.finger_left}} {% if pwic.env.no_new_user %}{% trans %}Assign a new user{% endtrans %}{% else %}{% trans %}Create a new user{% endtrans %}{% endif %}</a></div>
</header>
{% include 'js/user-create.js' %}
<article>
{% if pwic.projects|count == 0 %}
<p class="pwic_error">{{pwic.emojis.padlock}} {% trans %}You have no authorization to create a new user. Please contact your administrator.{% endtrans %}</p>
{% else %}
<p class="pwic_italic">{% trans %}Reminder: your password must be changed before you can add a new user to the selected project.{% endtrans %}</p>
<p><strong>{% trans %}Project:{% endtrans %}</strong><br>
<select id="create_project" name="project">
{% for proj in pwic.projects %}
<option value="{{proj.project|escape}}"
{% if proj.project == pwic.default_project %} selected="selected" {% endif %}
>{{proj.description|escape}} [{{proj.project|escape}}]</option>
{% endfor %}
</select>
</p>
<p><strong>{% trans %}User name:{% endtrans %}</strong> <input id="create_user" class="pwic_fill" type="text" name="user" autofocus required="true" spellcheck="false"></p>
<p><input type="button" value="{{pwic.emojis.users}} {% trans %}Create the user{% endtrans %}" onclick="create_submit()"></p>
{% endif %}
</article>
{% endblock %}
@@ -0,0 +1,140 @@
{% extends 'html/main.html' %}
{% block title %}{% trans %}Roles of the users{% endtrans %}{% endblock %}
{% block content %}
<header>
<div class="pwic_ph1"><a href="/{{pwic.project|urlencode}}/special">{{pwic.emojis.finger_left}} {% trans %}Roles of the users{% endtrans %}</a></div>
<div class="pwic_ph2">[{{pwic.project|escape}}] {{pwic.project_description|escape}}</div>
</header>
<article>
<div class="pwic_action_bar">
<a href="/{{pwic.project|urlencode}}/special/audit">{{pwic.emojis.glasses}} {% trans %}Audit{% endtrans %}</a>
<a href="/{{pwic.project|urlencode}}/special/user">{{pwic.emojis.users}} {% trans %}Create a user{% endtrans %}</a>
</div>
<p class="pwic_italic">{% trans %}Reminder: the password of a user must be changed before his roles can be changed.{% endtrans %}</p>
<table id="roles_table" class="pwic_zebra">
<tr>
<th>{% trans %}User{% endtrans %}</th>
<th class="pwic_desktop" title="{% trans %}Password{% endtrans %}">{% trans %}Pwd{% endtrans %}</th>
<th class="pwic_desktop">{% trans %}Activity{% endtrans %}</th>
<th>{% trans %}A<span class="pwic_desktop">dmin</span>{% endtrans %}</th>
<th>{% trans %}M<span class="pwic_desktop">anager</span>{% endtrans %}</th>
<th>{% trans %}E<span class="pwic_desktop">ditor</span>{% endtrans %}</th>
<th>{% trans %}V<span class="pwic_desktop">alidator</span>{% endtrans %}</th>
<th>{% trans %}R<span class="pwic_desktop">eader</span>{% endtrans %}</th>
<th>{% trans %}Dis<span class="pwic_desktop">abled</span>{% endtrans %}</th>
<th>{% trans %}Del<span class="pwic_desktop">ete</span>{% endtrans %}</th>
</tr>
{% set u = namespace(value=0) %}
{% for role in pwic.roles %}
<tr id="roles_tag_{{u.value+7}}">
<td><a class="pwic_break" href="/special/user/{{role.user|urlencode}}" rel="nofollow">{{role.user|escape}}</a></td>
<td class="pwic_desktop">
{% if role.user|reserved_user_name %}
<span title="{% trans %}Special account{% endtrans %}">{{pwic.emojis.star}}</span>
{% elif role.oauth %}
<span title="{% trans %}Federated authentication{% endtrans %}">{{pwic.emojis.id}}</span>
{% elif role.initial %}
<span title="{% trans %}The user must change his password{% endtrans %}">{{pwic.emojis.unlocked}}</span>
{% else %}
{{pwic.emojis.green_check}}
{% endif %}
</td>
<td class="pwic_desktop">{{role.activity|escape}}</td>
<td>
<input id="roles_tag_{{u.value+1}}"
type="checkbox"
{% if (role.user == pwic.user) or role.user|reserved_user_name or role.initial %}
disabled="disabled"
{% else %}
onclick="return roles_toggle({{u.value+1}}, '{{pwic.project|escape}}', '{{role.user|escape}}', 'admin')"
{% endif %}
{% if role.admin %}
checked="checked"
{% endif %}
>
</td>
<td>
<input id="roles_tag_{{u.value+2}}"
type="checkbox"
onclick="return roles_toggle({{u.value+2}}, '{{pwic.project|escape}}', '{{role.user|escape}}', 'manager')"
{% if role.initial %}
disabled="disabled"
{% endif %}
{% if role.manager %}
checked="checked"
{% endif %}
>
</td>
<td>
<input id="roles_tag_{{u.value+3}}"
type="checkbox"
onclick="return roles_toggle({{u.value+3}}, '{{pwic.project|escape}}', '{{role.user|escape}}', 'editor')"
{% if role.initial %}
disabled="disabled"
{% endif %}
{% if role.editor %}
checked="checked"
{% endif %}
>
</td>
<td>
<input id="roles_tag_{{u.value+4}}"
type="checkbox"
onclick="return roles_toggle({{u.value+4}}, '{{pwic.project|escape}}', '{{role.user|escape}}', 'validator')"
{% if role.initial %}
disabled="disabled"
{% endif %}
{% if role.validator %}
checked="checked"
{% endif %}
>
</td>
<td>
<input id="roles_tag_{{u.value+5}}"
type="checkbox"
onclick="return roles_toggle({{u.value+5}}, '{{pwic.project|escape}}', '{{role.user|escape}}', 'reader')"
{% if role.initial %}
disabled="disabled"
{% endif %}
{% if role.reader %}
checked="checked"
{% endif %}
>
</td>
<td>
<input id="roles_tag_{{u.value+6}}" type="checkbox"
{% if (role.user == pwic.user) or role.initial %}
disabled="disabled"
{% else %}
onclick="return roles_toggle({{u.value+6}}, '{{pwic.project|escape}}', '{{role.user|escape}}', 'disabled')"
{% endif %}
{% if role.disabled %}
checked="checked"
{% endif %}
>
</td>
<td>
{% if (role.user != pwic.user) and (not role.user|reserved_user_name) %}
<input type="button"
onclick="return roles_delete('Are you sure to delete the rights of the user \'{{role.user|escape}}\' for the project?', {{u.value+7}}, '{{pwic.project|escape}}', '{{role.user|escape}}')"
value="{{pwic.emojis.red_check}}"
title="{% trans %}Delete{% endtrans %} {{role.user|escape}}"
>
{% endif %}
</td>
</tr>
{% set u.value = u.value + 7 %}
{% endfor %}
</table>
</article>
{% include 'js/user-roles.js' %}
{% endblock %}
+150
View File
@@ -0,0 +1,150 @@
{% extends 'html/main.html' %}
{% block title %}{% trans %}User profile{% endtrans %}{% endblock %}
{% block content %}
<header>
<div class="pwic_ph1"><a href="/">{{pwic.emojis.finger_up}} {% trans %}User profile{% endtrans %}</a></div>
</header>
{% include 'js/user.js' %}
<article>
<h1>{{pwic.userpage|escape}}</h1>
<h2>{% trans %}Profile{% endtrans %}</h2>
<ul>
<li>{% trans %}Own password:{% endtrans %}
<span id="user_password_status">{{pwic.emojis.red_check if pwic.password_initial else pwic.emojis.green_check}}</span>
{% if pwic.password_totp %}
<span title="{% trans %}Enabled two-factor authentication (2FA){% endtrans %}">{{pwic.emojis.slot}}</span>
{% endif %}
{% if pwic.password_oauth %}
<span title="{% trans %}Federated authentication only{% endtrans %}">{{pwic.emojis.id}}</span>
{% elif (pwic.user == pwic.userpage) and (not pwic.userpage|reserved_user_name) %}
<span class="pwic_js">(<a href="#" onclick="return user_password_popup()">{% trans %}change it{% endtrans %}</a>)</span>
{% endif %}
</li>
{% if pwic.user == pwic.userpage %}
<li>{% trans %}Language:{% endtrans %}
<select id="user_language" onchange="user_language_set()">
{% for lang in pwic.constants.languages %}
<option value="{{lang|escape}}" {% if lang == pwic.language %} selected="selected" {% endif %}>{{lang|escape}}</option>
{% endfor %}
</select>
</li>
{% endif %}
{% if pwic.projects|count > 0 %}
<li>{% trans %}Projects:{% endtrans %}
<ul>
{% for project in pwic.projects %}
<li><a href="/{{project.project|urlencode}}">{{project.description|escape}}</a></li>
{% endfor %}
</ul>
</li>
{% endif %}
</ul>
{% if (not pwic.password_oauth) and (pwic.user == pwic.userpage) and (not pwic.userpage|reserved_user_name) %}
<div id="user_password_popup" class="pwic_blurcontainer pwic_hidden">
<div class="pwic_popup">
<form autocomplete="new-password">
<p class="pwic_bold">{% trans %}Change your password{% endtrans %}</p>
<p id="user_password_notice" class="pwic_italic">{{pwic.emojis.warning}} {% trans %}Warning: the site does not use a secure protocol. Please choose a dedicated password that you use nowhere else.{% endtrans %}</p>
<table class="pwic_noborder">
<tr><td>{% trans %}Current password:{% endtrans %}</td> <td><input class="pwic_fill" type="password" id="user_password_current" autocomplete="current-password" required="true"></td></tr>
<tr><td>{% trans %}New password:{% endtrans %}</td> <td><input class="pwic_fill" type="password" id="user_password_new1" autocomplete="new-password" required="true"></td></tr>
<tr><td>{% trans %}Repeat password:{% endtrans %}</td> <td><input class="pwic_fill" type="password" id="user_password_new2" autocomplete="off" required="true" onpaste="return false"></td></tr>
</table>
<p>
<input type="button" value="{{pwic.emojis.locked}} {% trans %}Change{% endtrans %}" onclick="user_password_submit()">
<input type="button" value="{% trans %}Cancel{% endtrans %}" onclick="user_password_popup()">
</p>
</form>
</div>
</div>
{% endif %}
<h2>{% trans %}Contributions in the last 90 days{% endtrans %}</h2>
{% if pwic.pages|count == 0 %}
<p class="pwic_center pwic_italic">{% trans %}The user has no recent contribution.{% endtrans %}</p>
{% else%}
<table>
<tr>
<th class="pwic_desktop">{% trans %}Project{% endtrans %}</th>
<th class="pwic_desktop">{% trans %}Page{% endtrans %}</th>
<th>{% trans %}Title{% endtrans %}</th>
<th>{% trans %}Flags{% endtrans %}</th>
<th>{% trans %}Date{% endtrans %}</th>
<th class="pwic_desktop">{% trans %}Time{% endtrans %}</th>
<th class="pwic_desktop">{% trans %}Milestone{% endtrans %}</th>
</tr>
{% for page in pwic.pages %}
<tr>
<td class="pwic_desktop pwic_break">{{page.project|escape}}</td>
<td class="pwic_desktop pwic_break">{{page.page|escape}}</td>
<td><a href="/{{page.project|urlencode}}/{{page.page|urlencode}}">{{page.title|escape}}</a></td>
<td>
{% if page.draft %}
<span title="{% trans %}Draft{% endtrans %}">{{pwic.emojis.hourglass}}</span>
{% endif %}
{% if page.final %}
<span title="{% trans %}Marked as final{% endtrans %}">{{pwic.emojis.notes}}</span>
{% endif %}
{% if page.valuser != '' %}
<span title="{{ gettext('Validated by %(valuser)s on %(valdate)s at %(valtime)s.')|format(valuser=page.valuser|escape, valdate=page.valdate|escape, valtime=page.valtime|escape) }}">{{pwic.emojis.flag}}</span>
{% endif %}
</td>
<td>{{page.date|escape}}</td>
<td class="pwic_desktop">{{page.time|escape}}</td>
<td class="pwic_desktop">{{page.milestone|escape}}</td>
</tr>
{% endfor %}
</table>
{% endif %}
{% if (pwic.documents|count > 0) and (not pwic.user|reserved_user_name) %}
<h2>{% trans %}Uploaded documents{% endtrans %}</h2>
<table>
<tr>
<th class="pwic_desktop">{% trans %}Project{% endtrans %}</th>
<th class="pwic_desktop">{% trans %}Page{% endtrans %}</th>
<th>{% trans %}File name{% endtrans %}</th>
<th class="pwic_desktop">{% trans %}Format{% endtrans %}</th>
<th>{% trans %}Size{% endtrans %}</th>
<th class="pwic_desktop">{% trans %}Hash{% endtrans %}</th>
<th>{% trans %}Date{% endtrans %}</th>
<th class="pwic_desktop">{% trans %}Time{% endtrans %}</th>
<th><span class="pwic_desktop">{% trans %}Download{% endtrans %}</span></th>
</tr>
{% for doc in pwic.documents %}
<tr>
<td class="pwic_desktop pwic_break">{{doc.project|escape}}</td>
<td class="pwic_desktop pwic_break"><a href="/{{doc.project|urlencode}}/{{doc.page|urlencode}}">{{doc.page|escape}}</a></td>
<td>
<a class="pwic_break" href="/special/document/{{doc.id|urlencode}}/{{doc.filename|urlencode}}">{{doc.filename|escape}}</a>
{% if doc.exturl != ''%}
<span title="{% trans %}External storage{% endtrans %}">{{pwic.emojis.cloud}}</span>
{% endif%}
</td>
<td class="pwic_desktop" title="{{doc.mime|escape}}">{{doc.mime_icon}} {{doc.extension|upper}}</td>
<td data-sort="{{doc.size|escape}}">{{doc.size|size2str|escape}}</td>
<td class="pwic_desktop">
<span title="{{doc.hash|escape}}">{{doc.hash[:8]|escape}}</span>
{% if doc.occurrence > 1 %} <span title="{% trans %}Duplicate file{% endtrans %}">{{pwic.emojis.gemini}}</span> {% endif %}
</td>
<td>{{doc.date|escape}}</td>
<td class="pwic_desktop">{{doc.time|escape}}</td>
<td><a href="/special/document/{{doc.id|urlencode}}?attachment">{{pwic.emojis.inbox}}</a></td>
</tr>
{% endfor %}
</table>
{% endif %}
</article>
{% endblock %}
+71
View File
@@ -0,0 +1,71 @@
<script>
'use strict';
function login_translate_langs(mapping) {
$('#login_language OPTION').each((i, e) => {
var lang = $(e).attr('value');
if (mapping.hasOwnProperty(lang))
$(e).html(lang + ' - ' + mapping[lang]);
});
}
function login_anonymous() {
$('#login_user').val('{{pwic.constants.anonymous_user|escape}}');
$('#login_password').val('');
$('#login_pin').val('');
$('#login_form')[0].submit();
return true;
}
{% if pwic.env.base_url and pwic.env.oauth_provider %}
function login_oauth() {
{% if pwic.env.oauth_provider.value == 'github' %}
var args = {client_id: '{{pwic.env.oauth_identifier.value|escape}}',
redirect_uri: '{{pwic.env.base_url.value|escape}}/api/oauth',
login: $('#login_user').val(),
scope: 'user:email',
state: '{{pwic.oauth_user_secret|escape}}',
allow_signup: false};
window.location = 'https://github.com/login/oauth/authorize?' + (new URLSearchParams(args).toString());
{% elif pwic.env.oauth_provider.value == 'google' %}
var args = {client_id: '{{pwic.env.oauth_identifier.value|escape}}',
redirect_uri: '{{pwic.env.base_url.value|escape}}/api/oauth',
scope: 'https://www.googleapis.com/auth/userinfo.email',
access_type: 'online',
state: '{{pwic.oauth_user_secret|escape}}',
login_hint: $('#login_user').val(),
response_type: 'code'};
window.location = 'https://accounts.google.com/o/oauth2/v2/auth?' + (new URLSearchParams(args).toString());
{% elif pwic.env.oauth_provider.value == 'microsoft' %}
var args = {client_id: '{{pwic.env.oauth_identifier.value|escape}}',
response_type: 'code',
redirect_uri: '{{pwic.env.base_url.value|escape}}/api/oauth',
scope: 'https://graph.microsoft.com/user.read',
response_mode: 'query',
state: '{{pwic.oauth_user_secret|escape}}',
login_hint: $('#login_user').val()};
{% if pwic.env.oauth_domains %}
var main = '{{pwic.env.oauth_domains.value|escape}}'.trim().split(' ')[0];
if (main.length > 0)
args['domain_hint'] = main;
{% endif %}
window.location = 'https://login.microsoftonline.com/{{pwic.env.oauth_tenant.value|urlencode}}/oauth2/v2.0/authorize?' + (new URLSearchParams(args).toString());
{% else %}
throw 'Internal error - Invalid OAuth provider';
{% endif %}
}
{% endif %}
{% if pwic.env.registration_link %}
function login_register() {
window.location = '{{pwic.env.registration_link.value|escape}}';
return true;
}
{% endif %}
if (window.fetch)
$('#login_js').addClass('pwic_hidden');
</script>
@@ -0,0 +1,30 @@
<script>
'use strict';
fetch('/api/server/env/get',
{ method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams({'project': '{{pwic.project|slash}}'}),
credentials: 'same-origin'})
.then(response => {
if (response.ok)
response.json().then(data => {
var key, buffer, tr;
for (key in data) {
tr = $(document.createElement('TR')).appendTo($('#audit_envs'));
$(document.createElement('TD'))
.html('<code>' + pwic_entities(key) + '</code>')
.appendTo(tr);
$(document.createElement('TD'))
.html(data[key].global
? '<span title="{% trans %}Global{% endtrans %}">{{pwic.emojis.globe}}</span>'
: '<span title="{% trans %}Project-dependent{% endtrans %}">{{pwic.emojis.hammer}}</span>')
.appendTo(tr);
$(document.createElement('TD'))
.addClass('pwic_monospace')
.html(pwic_entities(data[key].value))
.appendTo(tr);
}
});
});
</script>
@@ -0,0 +1,49 @@
<script>
'use strict';
$('#create_kb').on('change', event => {
if ($(event.target).prop('checked')) {
var e = $('#create_page');
if (e.val() == '')
e.val('kb');
e[0].select();
}
});
function create_submit() {
var project = $('#create_project').val().trim().toLowerCase(),
kbmode = $('#create_kb').prop('checked'),
page = $('#create_page').val().trim().toLowerCase();
// Check the parameters
if (!pwic_is_safe(project) || !pwic_is_safe(page)) {
alert({% trans %}'The parameters are not acceptable.'{% endtrans %});
return false;
}
// Submit the form
$('INPUT[type=button]').attr('disabled', '');
var args = {project: project,
kb: kbmode,
page: page,
tags: $('#create_tags').val(),
milestone: $('#create_milestone').val(),
ref_project: $('#create_ref_project').val(),
ref_page: $('#create_ref_page').val(),
ref_tags: $('#create_ref_tags').val()};
fetch('/api/page/create', { method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams(args),
credentials: 'same-origin'})
.then(response => {
$('INPUT[type=button]').removeAttr('disabled');
if (!response.ok)
throw Error(response.status + ' ' + response.statusText);
response.json().then(data => window.location = data['url'] + '?success');
})
.catch(error => {
alert(error);
$('INPUT[type=button]').removeAttr('disabled');
});
}
</script>
+695
View File
@@ -0,0 +1,695 @@
<script>
'use strict';
// -------------------------------- Toolbar
function edit_decorate(tagStart, tagEnd) {
var nosel = !md_editor.somethingSelected();
md_editor.replaceSelection(tagStart + md_editor.getSelection() + tagEnd);
if (nosel) {
var cur = md_editor.getCursor();
md_editor.setCursor(cur.line, cur.ch - tagEnd.length);
}
md_editor.focus();
}
function edit_decorate_end(text) {
md_editor.replaceSelection(md_editor.getSelection() + text);
md_editor.focus();
}
function edit_link() {
if (md_editor.somethingSelected()) {
// Check the current selection for an autolink
var txt = md_editor.getSelection();
if (txt.match('^[a-z]{3,7}:\/\/')) {
md_editor.replaceSelection('<' + md_editor.getSelection().replaceAll(' ', '%20') + '>');
md_editor.focus();
return;
}
// Ask for the link
var url = prompt({% trans %}'Paste the link:'{% endtrans %}, '');
if ((url != null) && (url != '')) {
url = url.trim();
if ((url.length > 0)
&& (url.indexOf(':') === -1)
&& (url.indexOf('/') === -1)
&& (url == url.toLowerCase()))
url = '/{{pwic.project}}/' + url;
// Replace the text by another one
md_editor.replaceSelection('[' + txt + '](' + url + ')');
}
}
md_editor.focus();
}
function _edit_prepend_generic(ftag) {
// Fit the selection
var lft = md_editor.getCursor('start'),
rgt = md_editor.getCursor('end');
md_editor.setCursor(lft.line, 0);
md_editor.setSelection(md_editor.getCursor('start'), rgt);
// Adapt the content to the new format
var txt = ftag() + md_editor.getSelection();
md_editor.replaceSelection(txt.split('').map(c => c == '\n' ? '\n' + ftag() : c).join(''));
md_editor.focus();
}
function edit_prepend(tag) {
return _edit_prepend_generic(() => tag);
}
function edit_prepend_nlist() {
var id = 0;
return _edit_prepend_generic(() => ++id + '. ');
}
function _edit_block_transform(f) {
if (md_editor.somethingSelected())
md_editor.replaceSelection(f(md_editor.getSelection()), 'around');
md_editor.focus();
}
function edit_switch_case() {
_edit_block_transform(s => (s == s.toUpperCase()
? s.toLowerCase()
: (s == s.toLowerCase()
? s.substring(0,1).toUpperCase() + s.substring(1).toLowerCase()
: s.toUpperCase())));
}
function edit_double_spaces() {
_edit_block_transform(s => s.replace(/ +/g, ' '));
}
function edit_left_line() {
_edit_block_transform(s => s.replaceAll('\r', '').replace(/\n\s+/g, '\n'));
}
function edit_no_blank_line() {
_edit_block_transform(s => s.replaceAll('\r', '').replaceAll(/\n\s*\n/g, '\n'));
}
function edit_single_line() {
_edit_block_transform(s => s.replaceAll('\r', '').replace(/[\s\t]*\n[\s\t]*/, '\n').replaceAll('\n', ' '));
}
function edit_table() {
// Get the dimensions of the table
var ncol = parseInt(prompt({% trans %}'Number of columns:'{% endtrans %}, 0));
if (isNaN(ncol) || (ncol < 1))
return false;
var nrow = parseInt(prompt({% trans %}'Number of rows:'{% endtrans %}, 0)) + 1;
if (isNaN(nrow) || (nrow < 1))
return false;
// Prepare the associated markdown
var i, j, buffer = '';
for (i=0 ; i<nrow ; i++) {
buffer += '|';
for (j=0 ; j<ncol ; j++)
buffer += ' |';
buffer += '\n';
if (i == 0) {
buffer += '|';
for (j=0 ; j<ncol ; j++)
buffer += ' -------- |';
buffer += '\n';
}
}
// Apply the text
md_editor.replaceSelection(buffer);
md_editor.focus();
}
function edit_table_import() {
try {
navigator.clipboard.readText()
.then(input_text => {
var i, j, lines, cols,
ncols = 0,
nlens = [],
txt, buffer, nice;
// Check
input_text = input_text.replaceAll('\r', '').trim();
if (input_text.length == 0) {
$('#edit_toolbar_table').trigger('click');
return;
}
// Scan the dimensions of the table
lines = input_text.split('\n');
for (i=0 ; i<lines.length ; i++) {
cols = lines[i].split('\t');
ncols = Math.max(ncols, cols.length);
for (j=0 ; j<cols.length ; j++) {
if (nlens.length <= j)
nlens.push(0);
nlens[j] = Math.max(nlens[j], cols[j].trim().length);
}
}
nice = (nlens.reduce((a, b) => a + b, 0) <= 128); // To shorten large tables
// Build the final text
buffer = '';
for (i=0 ; i<lines.length ; i++) {
buffer += '\n';
cols = lines[i].split('\t');
for (j=0 ; j<ncols ; j++) {
txt = (j < cols.length ? cols[j] : '').trim();
buffer += '| ' + txt + ' '.repeat((nice ? nlens[j] - txt.length : 0) + 1);
}
buffer += '|';
// Header line
if (i == 0) {
buffer += '\n';
for (j=0 ; j<ncols ; j++)
buffer += '|' + '-'.repeat((nice ? nlens[j] : 1) + 2);
buffer += '|';
}
}
// Paste the table
edit_decorate_end('\n' + buffer + '\n\n');
});
} catch (e) {
// See dom.events.testing.asyncClipboard in Firefox
alert({% trans %}'You cannot use this feature.'{% endtrans %});
}
}
function edit_footnote() {
// Search for the highest current footnote
var id = 0,
list = [...md_editor.getValue().matchAll(/\[\^([0-9]+)\]/g)];
list.forEach(match => {
var value = parseInt(match[1]);
if (value > id)
id = value;
});
// Apply the footnote
md_editor.replaceSelection(md_editor.getSelection() + ' [^'+(id+1)+']');
md_editor.setValue(md_editor.getValue() + '\n\n' + '[^'+(id+1)+']: ');
md_editor.focus();
md_editor.setCursor(md_editor.lineCount(), 0);
}
function edit_join_document(id, filename, mime) {
var buffer = '';
// Include an image
if (mime.substring(0, 6) == 'image/') {
var tip = prompt({% trans %}'Tooltip of the image:'{% endtrans %}, ''),
alt = prompt({% trans %}'Alternate text for the image:'{% endtrans %}, '');
buffer = '![';
if (alt != '')
buffer += pwic_kick(alt, '["]');
buffer += '](/special/document/' + id;
if (tip != '')
buffer += ' "'+pwic_kick(tip, '"')+'"';
buffer += ')';
}
// Any other file
else
buffer = '['+filename+'](/special/document/'+id+'?attachment)'
// Set the value
md_editor.replaceSelection(buffer);
md_editor.focus();
}
function _edit_convert(endpoint, payload) {
fetch(endpoint, { method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams(payload),
credentials: 'same-origin'})
.then(response => {
if (!response.ok)
throw Error(response.status + ' ' + response.statusText);
response.text().then(text => {
if ((text != '') && confirm({% trans %}'Do you want to replace the current content by the one of the selected document?'{% endtrans %})) {
md_editor.setValue(text);
md_editor.focus();
}
});
})
.catch(error => alert(error));
}
function edit_convert_document(id) {
_edit_convert('/api/document/convert', {id: id});
}
{% if pwic.env.remote_url %}
function edit_convert_remote_document() {
var url = prompt({% trans %}'Remote URL to fetch:'{% endtrans %}, '');
if ((url != null) && (url != ''))
_edit_convert( '/api/document/remote/convert',
{project: '{{pwic.project|slash}}', url: url});
}
{% endif %}
// -------------------------------- Dictation
{% if not pwic.env.no_dictation %}
class PwicSpeech {
constructor() {
this._timeout = null;
// Load the speech recognition
if ((location.protocol != 'https:') || (window.webkitSpeechRecognition === undefined)) {
$('#edit_toolbar_dictate').prop('disabled', 'disabled');
return false;
}
this._handler = new webkitSpeechRecognition();
this._handler.continuous = true;
this._handler.interimResults = true;
this._handler.lang = $('HTML').prop('lang');
// Event when started
this._handler.onstart = () => {
this._timeout = setTimeout(() => this._handler.stop(), 5000);
$('#edit_toolbar_dictate').addClass('pwic_limebg');
};
// Event on word received
// https://developer.chrome.com/blog/voice-driven-web-apps-introduction-to-the-web-speech-api
this._handler.onresult = (event) => {
// Fetch the words
var buffer, i, result, lft, rgt;
buffer = '';
for (i=event.resultIndex; i<event.results.length; ++i) {
result = event.results[i];
buffer += result[0].transcript;
}
// Update the Markdown editor
md_editor.replaceSelection(buffer);
if (!result.isFinal) {
rgt = md_editor.getCursor();
lft = {...rgt};
lft.ch -= buffer.length;
md_editor.setSelection(lft, rgt);
}
// Delay
clearTimeout(this._timeout);
this._timeout = setTimeout(() => this._handler.stop(), 5000);
};
// Event when ended
this._handler.onend = () => {
clearTimeout(this._timeout);
this._timeout = null;
$('#edit_toolbar_dictate').removeClass('pwic_limebg');
};
// Install
$('#edit_toolbar_dictate').on('click', (event) => {
if ($(event.target).hasClass('pwic_limebg'))
this._handler.stop();
else
if (this._timeout == null) {
this._handler.start();
md_editor.focus();
}
});
return true;
}
};
new PwicSpeech();
{% endif %}
// -------------------------------- File drop
function edit_refresh_documents() {
fetch('/api/document/list', { method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams({ project: '{{pwic.project|slash}}',
page: '{{pwic.page|slash}}' }),
credentials: 'same-origin'})
.then(response => {
if (!response.ok)
throw Error(response.status + ' ' + response.statusText);
response.json().then(data => {
$('#edit_files_list TR:nth-child(n+2)').remove();
var i, doc, tr, td;
for (i=0 ; i<data.length ; i++) {
doc = data[i];
tr = $(document.createElement('TR')).appendTo($('#edit_files_list'));
td = $(document.createElement('TD')).appendTo(tr);
$(document.createElement('INPUT'))
.attr('type', 'button')
.val(pwic_unimoji('{{pwic.emojis.plus}}'))
.attr('title', "{% trans %}Add a link{% endtrans %}")
.data('id', doc.id)
.data('filename', doc.filename)
.data('mime', doc.mime)
.on('click', (e) => edit_join_document($(e.target).data('id'), $(e.target).data('filename'), $(e.target).data('mime')))
.appendTo(td);
if (doc.convertible)
$(document.createElement('INPUT'))
.addClass('pwic_desktop')
.attr('type', 'button')
.val(pwic_unimoji('{{pwic.emojis.hammer}}'))
.attr('title', "{% trans %}Import the content of the document{% endtrans %}")
.data('id', doc.id)
.on('click', (e) => edit_convert_document($(e.target).data('id')))
.appendTo(td);
td = $(document.createElement('TD')).appendTo(tr);
$(document.createElement('A'))
.attr('href', '/special/document/' + encodeURIComponent(doc.id) + '/' + encodeURIComponent(doc.filename))
.attr('target', '_blank')
.html(pwic_entities(doc.filename) + (doc.exturl != '' ? ' {{pwic.emojis.cloud}}' : ''))
.appendTo(td);
$(document.createElement('TD'))
.addClass('pwic_desktop')
.html(doc.used ? '{{pwic.emojis.green_check}}' : '')
.appendTo(tr);
$(document.createElement('TD'))
.attr('title', "{% trans %}Hash:{% endtrans %} " + pwic_entities(doc.hash.substring(0, 8)))
.html(doc.size_str)
.appendTo(tr);
$(document.createElement('TD'))
.addClass('pwic_desktop')
.attr('title', pwic_entities(doc.mime))
.html(doc.mime_icon + ' ' + pwic_entities(doc.extension).toUpperCase())
.appendTo(tr);
td = $(document.createElement('TD'))
.addClass('pwic_desktop')
.appendTo(tr);
$(document.createElement('A'))
.attr('href', '/special/user/' + encodeURIComponent(doc.author))
.attr('target', '_blank')
.attr('rel', 'nofollow')
.html(pwic_entities(doc.author))
.appendTo(td);
$(document.createElement('TD'))
.html(pwic_entities(doc.date))
.appendTo(tr);
$(document.createElement('TD'))
.addClass('pwic_desktop')
.html(pwic_entities(doc.time))
.appendTo(tr);
td = $(document.createElement('TD')).appendTo(tr);
$(document.createElement('INPUT'))
.attr('type', 'button')
.val(pwic_unimoji('{{pwic.emojis.curved_left_arrow}}'))
.attr('title', "{% trans %}Rename the document{% endtrans %}")
.data('id', doc.id)
.data('filename', doc.filename)
.on('click', (e) => edit_rename_document($(e.target).data('id'), $(e.target).data('filename')))
.appendTo(td);
$(document.createElement('INPUT'))
.attr('type', 'button')
.val(pwic_unimoji('{{pwic.emojis.red_check}}'))
.attr('title', "{% trans %}Delete the document{% endtrans %}")
.data('id', doc.id)
.data('filename', doc.filename)
.on('click', (e) => edit_delete_document($(e.target).data('id'), $(e.target).data('filename')))
.appendTo(td);
}
$('#edit_files_list').toggleClass('pwic_hidden', data.length == 0);
});
})
.catch(error => alert(error));
}
edit_refresh_documents(); // For the initialization
function _edit_transfer_files(files) {
// Create an XHR for each file
var notification = null;
for (var i=0 ; i<files.length ; i++) {
// Fields
var form = new FormData();
form.append('project', '{{pwic.project|slash}}');
form.append('page', '{{pwic.page|slash}}');
form.append('content', files[i]);
// Request
fetch('/api/document/create', { method: 'POST',
body: form,
credentials: 'same-origin'})
.then(response => {
if (!response.ok)
throw Error(response.status + ' ' + response.statusText);
if (notification != null)
clearTimeout(notification);
notification = setTimeout(() => {
edit_refresh_documents();
alert({% trans %}'The file is uploaded and usable in the list below.'{% endtrans %});
}, 2000);
})
.catch(error => alert(error));
}
}
function edit_upload_document() {
var obj = $(document.createElement('INPUT'))
.attr('type', 'file')
.addClass('pwic_hidden')
.appendTo('body')
.on('change', e => { _edit_transfer_files(e.target.files), obj.remove() })
.on('cancel', () => obj.remove())
.trigger('click');
}
function edit_drop(event) {
$('#edit_files_drop').removeClass('pwic_dragover');
if (event.dataTransfer.items) {
event.preventDefault();
event.stopPropagation();
_edit_transfer_files(event.dataTransfer.files);
} else
alert({% trans %}'Unsupported feature.'{% endtrans %});
}
function edit_dragover(event) {
$('#edit_files_drop').addClass('pwic_dragover');
event.preventDefault();
event.stopPropagation();
}
function edit_dragleave(event) {
$('#edit_files_drop').removeClass('pwic_dragover');
event.preventDefault();
event.stopPropagation();
}
function edit_rename_document(id, filename) {
var newfn = prompt('Type the new file name:', filename);
if ((newfn != null) && (newfn != filename)) {
fetch('/api/document/rename', { method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams({ id: id,
project: '{{pwic.project|slash}}',
filename: newfn}),
credentials: 'same-origin'})
.then(response => {
if (!response.ok)
throw Error(response.status + ' ' + response.statusText);
setTimeout(edit_refresh_documents, 1000);
})
.catch(error => alert(error));
}
return false;
}
function edit_delete_document(id, filename) {
if (confirm({% trans %}'Are sure to delete "%s"?'{% endtrans %}.replace('%s', filename))) {
fetch('/api/document/delete', { method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams({ id: id,
project: '{{pwic.project|slash}}'}),
credentials: 'same-origin'})
.then(response => {
if (!response.ok)
throw Error(response.status + ' ' + response.statusText);
setTimeout(edit_refresh_documents, 1000);
})
.catch(error => alert(error));
}
return false;
}
// -------------------------------- Submit a page
$('#edit_comment').on('dblclick', event => {
if ($(event.target).val() == '')
$(event.target).val($(event.target).prop('placeholder'));
});
var edit_submittable = false,
edit_preview_hwnd = null;
function edit_submit_form() {
// Check the current values
edit_submittable = ($('#edit_title').val() != '')
&& ($('#edit_comment').val() != '');
if (!edit_submittable) {
alert({% trans %}'Some fields are mandatory.'{% endtrans %});
return false;
}
// Disable the button temporarily
$('#edit_submit').prop('disabled', true);
setTimeout(() => $('#edit_submit').prop('disabled', false), 5000);
// First ping-pong the server to make sure that the session is still valid
fetch('/api/server/ping', { method: 'POST',
credentials: 'same-origin'})
.then(response => {
var errorPing = {% trans %}'Your session is not valid anymore. Please reconnect from another tab and retry.'{% endtrans %};
if (!response.ok)
alert('['+response.status+'] '+errorPing);
else
response.text().then(text => {
if (text != 'OK') {
alert(errorPing);
return;
}
// Close the preview
if (edit_preview_hwnd != null) {
edit_preview_hwnd.close();
edit_preview_hwnd = null;
}
// Query the current revision of the modified page
fetch('/api/project/get', { method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams({ project: '{{pwic.project|slash}}',
page: '{{pwic.page|slash}}'}),
credentials: 'same-origin'})
.then(response => {
if (!response.ok)
throw Error('['+response.status+'] '+response.statusText);
response.json().then(data => {
// Check the conflict
if (data['{{pwic.page|slash}}']['revisions'][0]['revision'] > {{pwic.revision}}) {
if (!confirm({% trans %}'Warning: the page has been modified in parallel of your current modifications.\n\nConsequently, your changes will be posted as a removable draft. You must merge the changes manually later.'{% endtrans %}))
return false;
$('#edit_draft').prop('checked', true);
$('#edit_final').prop('checked', false);
}
// Submit the modifications
{# sof/7542586 #}
var form = {project: '{{pwic.project|slash}}',
page: '{{pwic.page|slash}}',
title: $('#edit_title').val(),
tags: $('#edit_tags').val(),
markdown: md_editor.getValue(),
comment: $('#edit_comment').val(),
milestone: $('#edit_milestone').val(),
draft: $('#edit_draft').prop('checked'),
final: $('#edit_final').prop('checked'),
header: $('#edit_header').prop('checked'),
protection: $('#edit_protection').prop('checked')};
fetch('/api/page/edit', { method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams(form),
credentials: 'same-origin'})
.then(response => {
if (!response.ok)
throw Error(response.status + ' ' + response.statusText);
window.location = '/{{pwic.project|urlencode}}/{{pwic.page|urlencode}}?success';
})
.catch(error => alert(error));
});
})
.catch(error => alert(error));
});
})
.catch(error => alert({% trans %}'The server or your Internet connection is down.'{% endtrans %}));
}
function edit_preview_md(pageName) {
fetch('/api/markdown/convert', {method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams({ project: '{{pwic.project|slash}}',
markdown: md_editor.somethingSelected() ? md_editor.getSelection() : md_editor.getValue()}),
credentials: 'same-origin'})
.then(response => {
if (!response.ok)
throw Error(response.status + ' ' + response.statusText);
response.text().then(text => {
if (edit_preview_hwnd != null)
edit_preview_hwnd.close();
edit_preview_hwnd = window.open('');
edit_preview_hwnd.document.head.innerHTML = '<link rel="stylesheet" type="text/css" href="'+window.location.protocol+'//'+window.location.host+'/static/styles.css" />';
edit_preview_hwnd.document.title = {% trans %}'Preview of the page'{% endtrans %} + ' "'+pageName+'"';
edit_preview_hwnd.document.body.innerHTML = '\
<article>\
<p style="position:fixed; top:0px; right:0px; padding:15px">\
<input type="button" onclick="window.close()" value="{{pwic.emojis.door}} '+{% trans %}'Close the preview'{% endtrans %}+'" />\
<\/p>\
'+text+'\
<\/article>';
edit_preview_hwnd.window.onkeydown = function(event) {
if (event.key == 'Escape') {
edit_preview_hwnd.close();
edit_preview_hwnd = null;
}
};
});
})
.catch(error => alert(error));
}
// -------------------------------- Leave without saving
window.onbeforeunload = function(e) {
var e = e || window.event;
if (!edit_submittable)
if (e)
e.returnValue = {% trans %}'The current changes may be lost.'{% endtrans %};
};
// -------------------------------- Markdown editor
function edit_undo(mode) {
if (mode)
md_editor.undo();
else
md_editor.redo();
md_editor.focus();
return false;
}
function _edit_get_shortcuts() { // Callable once
var sc = {};
$("INPUT[type='button'][data-shortcut]").each((i, e) => {
e.title = (e.title || '') + ' (' + e.dataset['shortcut'] + ')';
sc[e.dataset.shortcut] = cm => e.click();
});
return sc;
}
var md_editor = CodeMirror.fromTextArea(document.getElementById('edit_markdown'), {
mode: 'markdown',
lineNumbers: true,
lineWrapping: true,
extraKeys: _edit_get_shortcuts()
});
</script>
+76
View File
@@ -0,0 +1,76 @@
<script>
'use strict';
// Easy copy of the global value
$('INPUT[type=text]').on('dblclick', event => {
if ($(event.target).val() == '') {
$(event.target).val($(event.target).prop('placeholder'));
$(event.target).trigger('keyup');
}
});
// Manage the visibility of the save button
$('INPUT[type=button]').addClass('pwic_hidden');
$('INPUT[type=text]').on('keyup', event => {
// Inbound values
var value = $(event.target).val(),
saved = ($(event.target).data('saved') || ''),
global = ($(event.target).data('global') == 'X');
// Conditions to show it
var b1 = !global && (value != saved),
b2 = global && (value != '');
$('INPUT[type=button][data-key='+$(event.target).data('key')+']').toggleClass('pwic_hidden', !b1 && !b2);
});
// Manage the save button
$('INPUT[type=button]').on('click', event => {
var key = $(event.target).data('key'),
value = $('INPUT[type=text][data-key='+key+']').val();
env_set(key, value);
});
// Load the default values of the configuration
$('INPUT[type=text]').attr('readonly', '').addClass('pwic_disabled_bg');
fetch('/api/server/env/get', { method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams({project: '{{pwic.project|slash}}'}),
credentials: 'same-origin'})
.then(response => {
if (!response.ok)
throw Error(response.status + ' ' + response.statusText);
response.json().then(data => {
var key, item, element;
for (key in data) {
item = data[key];
element = $('INPUT[type=text][data-key='+key+']');
if (element.length == 1) {
element.data('saved', item['value'])
.data('global', (item['global'] ? 'X' : ''));
if (item['global'])
element.attr('placeholder', item['value']);
else
element.val(item['value']);
}
}
$('INPUT[type=text]').removeAttr('readonly').removeClass('pwic_disabled_bg');
});
})
.catch(error => alert(error));
// Action when the save button is pressed
function env_set(key, value) {
fetch('/api/project/env/set', { method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams({ project: '{{pwic.project|slash}}',
key: key,
value: value}),
credentials: 'same-origin'})
.then(response => {
if (!response.ok)
throw Error(response.status + ' ' + response.statusText);
$('INPUT[type=text][data-key='+key+']').data('saved', value);
$('INPUT[type=button][data-key='+key+']').addClass('pwic_hidden');
})
.catch(error => alert(error));
}
</script>
@@ -0,0 +1,70 @@
<script src="/static/svg-pan-zoom.min.js"></script>
<script>
'use strict';
// Get the graph from the API
var graph_cache = null;
function graph_get_data(action) {
// Download from cache
if ((action == 'download') && (graph_cache != null))
return graph_download();
// Else first download
fetch('/api/project/graph/get', { method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams({project: '{{pwic.project|slash}}'}),
credentials: 'same-origin'})
.then(response => {
if (!response.ok)
throw Error(response.status + ' ' + response.statusText);
response.text().then(text => {
graph_cache = text;
if (action == 'render')
graph_generate_svg();
else
if (action == 'download')
graph_download();
});
})
.catch(error => alert(error));
}
graph_get_data('render');
// Download the graph as a raw file
function graph_download() {
if (graph_cache == null)
return false;
var blob = window.URL.createObjectURL(new Blob([graph_cache], {type: 'text/vnd.graphviz'}));
$(document.createElement('A'))
.addClass('pwic_hidden')
.attr('href', blob)
.attr('download', '{{pwic.project|slash}}.gv')
.appendTo('BODY')
.trigger('click')
.remove();
window.URL.revokeObjectURL(blob);
return true;
}
// Generate the graph
function graph_generate_svg() {
var worker = new Worker('/static/viz.js');
worker.onmessage = function(e) {
// Render SVG
var graph = $('#graph_viz')[0];
var svg = (new DOMParser()).parseFromString(e.data, 'image/svg+xml').documentElement;
graph.appendChild(svg);
// Zooming area for SVG
var panZoom = svgPanZoom(svg, {zoomEnabled: true, controlIconsEnabled: true, center: true, minZoom: 0.1});
svg.addEventListener('paneresize', e => panZoom.resize(), false);
window.addEventListener('resize', e => panZoom.resize());
worker.terminate();
};
worker.onerror = function(e) {
alert(e.message === undefined ? 'The graph cannot be rendered.' : e.message);
};
worker.postMessage({src: graph_cache, options: {engine: 'dot', format: 'svg'}});
}
</script>
@@ -0,0 +1,19 @@
<script>
'use strict';
function history_compare() {
var rev = [];
$('input').each((i, e) => {
e = $(e);
if ((e.attr('type') == 'checkbox') && e.prop('checked'))
rev.push(e.data('revision'));
});
if (rev.length > 2)
return false;
if (rev.length == 2) {
rev.sort();
window.location = '/{{pwic.project|urlencode}}/{{pwic.page|urlencode}}/rev'+rev[1]+'/compare/rev'+rev[0];
}
return true;
}
</script>
+52
View File
@@ -0,0 +1,52 @@
<script>
'use strict';
$('#move_dst_page').on('dblclick', event => {
if ($(event.target).val() == '')
$(event.target).val($(event.target).prop('placeholder'));
});
function move_submit() {
// Fetch the parameters
var srcproj = $('#move_src_project').val(),
srcpage = $('#move_src_page').val(),
dstproj = $('#move_dst_project').val(),
dstpage = $('#move_dst_page').val().trim().toLowerCase();
// Check the parameters
if (dstpage == '')
dstpage = srcpage;
if ( !pwic_is_safe(srcproj)
|| !pwic_is_safe(srcpage)
|| !pwic_is_safe(dstproj)
|| !pwic_is_safe(dstpage)
|| ((srcproj == dstproj) && (dstpage == srcpage))
|| ((srcproj != dstproj) && (dstpage == ''))
) {
alert({% trans %}'The parameters are not acceptable.'{% endtrans %});
return false;
}
// Submit the form
$('INPUT[type=button]').attr('disabled', '');
var args = {project: dstproj,
page: dstpage,
ref_project: srcproj,
ref_page: srcpage,
ignore_file_errors: 'X'};
fetch('/api/page/move', { method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams(args),
credentials: 'same-origin'})
.then(response => {
$('INPUT[type=button]').removeAttr('disabled');
if (!response.ok)
throw Error(response.status + ' ' + response.statusText);
window.location = response.url;
})
.catch(error => {
alert(error);
$('INPUT[type=button]').removeAttr('disabled');
});
}
</script>
@@ -0,0 +1,86 @@
<script>
(function() {
var list_initial = null,
timeout = null;
$('#page_progress_tags > A:nth-child(1)').on('click', event => {
$('#page_progress_tags > A:nth-child(n+4)').addClass('pwic_selected');
clearTimeout(timeout);
page_progress_refresh();
return false;
});
$('#page_progress_tags > A:nth-child(2)').on('click', event => {
$('#page_progress_tags > A:nth-child(n+4)').removeClass('pwic_selected');
clearTimeout(timeout);
page_progress_refresh();
return false;
});
$('#page_progress_tags > A:nth-child(n+3)').on('click', event => {
$(event.target).toggleClass('pwic_selected');
clearTimeout(timeout);
timeout = setTimeout(page_progress_refresh, 2000);
return false;
});
async function page_progress_refresh() {
function _pc(a, b) {
return (b == 0 ? '' : Math.floor(100 * a / b) + ' %');
}
function _sl(terms, text, entries) {
if ({% if pwic.env.no_search %} true {% else %} false {% endif %} || (entries == 0))
return encodeURIComponent(text);
return '<a href="/{{pwic.project|urlencode}}/special/search?q=%23'+encodeURIComponent(terms)+'" target="_blank">'+encodeURIComponent(text)+'<\/a>';
}
// Get the selected tags
var tags = '';
$('#page_progress_tags > A:nth-child(n+4)').each((i, e) => {
if ($(e).hasClass('pwic_selected'))
tags += ' ' + $(e).text().substring(1);
});
tags = tags.trim();
// Calculate the progress
var buffer = '';
if (tags.length > 0) {
var args = {project: '{{pwic.project|slash}}',
tags: tags,
combined: $('#page_progress_tags > A:nth-child(3)').hasClass('pwic_selected') ? 'on' : ''},
options = { method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams(args),
credentials: 'same-origin'};
try {
var request = await fetch('/api/project/progress/get', options);
if (request.ok) {
var data = await request.json();
for (var tag in data) {
var item = data[tag];
if (item['total'] > 0)
buffer += '<tr>'
+ '<td>' + _sl(tag, tag, 1) + '<\/td>'
+ '<td>' + _sl(tag + ' :draft', item['draft'], item['draft']) + '<\/td>'
+ '<td class="pwic_desktop">' + _pc(item['draft'], item['total']) + '<\/td>'
+ '<td>' + _sl(tag + ' -:draft -:final -:validated', item['step'], item['step']) + '<\/td>'
+ '<td class="pwic_desktop">' + _pc(item['step'], item['total']) + '<\/td>'
+ '<td>' + _sl(tag + ' :final', item['final'], item['final']) + '<\/td>'
+ '<td class="pwic_desktop">' + _pc(item['final'], item['total']) + '<\/td>'
+ '<td>' + _sl(tag + ' :validated', item['validated'], item['validated']) + '<\/td>'
+ '<td class="pwic_desktop">' + _pc(item['validated'], item['total']) + '<\/td>'
+ '<\/tr>';
}
}
}
catch (error) {
console.log(error);
}
}
// Display the result
var e = $('#page_progress_list');
e.html((list_initial = list_initial || e.html()) + buffer).toggleClass('pwic_hidden', buffer.length == 0);
}
}());
</script>
+156
View File
@@ -0,0 +1,156 @@
<script>
'use strict';
{% if pwic.env.no_text_selection %}
$(document).on('keydown', e => !((e.key == 'F12') || (e.ctrlKey && e.shiftKey && (e.key == 'I')) || (e.ctrlKey && (e.key == 'u'))));
$(document).on('selectstart', () => false);
$(document).on('contextmenu', () => false);
$('ARTICLE *').css(atob('dXNlci1zZWxlY3Q='), 'none');
{% endif %}
window.onscroll = () => {
var scroll = document.body.scrollTop || document.documentElement.scrollTop,
height = document.documentElement.scrollHeight - document.documentElement.clientHeight;
$('#pwic_progress')[0].style.width = ((scroll / height) * 100).toString() + 'vw';
$('#page_topofpage').toggleClass('pwic_hidden', scroll == 0);
};
$(document).on('keyup', event => {
if (!$('#pwic_browser').hasClass('pwic_hidden'))
if ((event || window.event).key == 'Escape')
$('#pwic_browser_access').trigger('click');
});
function page_email() {
{% if pwic.draft %}
if (confirm({% trans %}'Warning: the current page is a draft, so its content may disappear in the future without notice.'{% endtrans %}))
{% endif %}
{
var url = window.location.toString();
if (url.endsWith('#'))
url = url.substring(0, url.length - 1);
window.location = "mailto:?subject={{pwic.title|urlencode}}&body="+encodeURIComponent('\n\n'+url);
}
return false;
}
function page_print() {
window.print();
return false;
}
function page_tmap() {
var element = $('#pwic_browser');
element.toggleClass('pwic_hidden');
if (!element.hasClass('pwic_hidden'))
element[0].focus();
}
function page_post_action(action, confirmText) {
if (confirm(confirmText)) {
fetch('/api/page/'+action, {method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams({ project: '{{pwic.project|slash}}',
page: '{{pwic.page|slash}}',
revision: {{pwic.revision}}}),
credentials: 'same-origin'})
.then(response => {
if (!response.ok)
throw Error(response.status + ' ' + response.statusText);
window.location = '/{{pwic.project|urlencode}}' +
'/{{pwic.page|urlencode}}' +
(action != 'delete' ? '/rev{{pwic.revision|urlencode}}' : '') +
(action == 'delete' ? '?success' : '');
})
.catch(error => alert(error));
}
return false;
}
function page_export(format) {
fetch('/api/page/export', { method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams({ project: '{{pwic.project|slash}}',
page: '{{pwic.page|slash}}',
revision: {{pwic.revision}},
format: format}),
credentials: 'same-origin'})
.then(response => {
if (!response.ok)
throw Error(response.status + ' ' + response.statusText);
var filename = response.headers.get('Content-Disposition').split('"')[1];
filename = filename.substring(10,filename.length-2);
filename = decodeURIComponent(escape(atob(filename)))
response.blob().then(blob => {
var dl = $(document.createElement('A'))
.addClass('pwic_hidden')
.attr('href', window.URL.createObjectURL(new Blob([blob], {type: blob.type})))
.attr('download', filename)
.appendTo('body')
.trigger('click')
.remove();
window.URL.revokeObjectURL(dl.href);
return true;
});
})
.catch(error => alert(error));
return false;
}
{% if not pwic.env.no_copy_code %}
function page_copy_code() {
var code = $(this).parent().text().substring($(this).text().length);
navigator.clipboard.writeText(code).then(
() => alert({% trans %}'The code has been copied successfully to the clipboard.'{% endtrans %}),
() => alert({% trans %}'The code cannot be copied to the clipboard.'{% endtrans %})
);
}
$('CODE').each((i, e) => {
if ((e.clientHeight >= 100) || (e.clientWidth >= 300))
$(e).prepend($(document.createElement('SPAN'))
.addClass('pwic_copy_code' + (e.clientHeight <= 50 ? '_tiny' : ''))
.attr('title', 'Copy')
.html('{{pwic.emojis.notes}}')
.on('click', page_copy_code));
});
{% endif %}
{% if not pwic.env.no_table_csv %}
function page_export_table() {
var csv, row, x, y, val,
table = this.parentElement;
// Prepare the table
csv = [];
for (y=0; y<table.rows.length; y++) {
row = [];
for (x=0; x<table.rows[y].cells.length; x++) {
val = table.rows[y].cells[x].textContent;
if ((val.indexOf('"') != -1) || (val.indexOf(';') != -1))
val = '"' + val.replaceAll('"', '""') + '"';
row.push(val);
}
csv.push(row.join(';'));
}
// Download the file
var blob = window.URL.createObjectURL(new Blob([csv], {type: 'text/csv'}));
$(document.createElement('A'))
.addClass('pwic_hidden')
.attr('href', blob)
.attr('download', 'table.csv')
.appendTo('BODY')
.trigger('click')
.remove();
window.URL.revokeObjectURL(blob);
}
$('ARTICLE > TABLE').each((i, e) => {
if (e.rows.length >= 10)
$(e).append($(document.createElement('CAPTION'))
.html('<span class="pwic_desktop">' + {% trans %}'Download this table as CSV file'{% endtrans %} + '<\/span><span class="pwic_mobile">&#x1F4BE;&nbsp;CSV<\/span>')
.on('click', page_export_table));
});
{% endif %}
</script>
+20
View File
@@ -0,0 +1,20 @@
<script>
'use strict';
function page_start_search() {
var args = {q: $('#page_search').val()};
if (args['q'].length > 0) {
if ($('#page_search_withrev').prop('checked'))
args['rev'] = 'on';
if ($('#page_search_casesensitive').prop('checked'))
args['cs'] = 'on';
window.location = '/{{pwic.project|urlencode}}/special/search?' + (new URLSearchParams(args).toString());
}
}
function page_search(event) {
event = event || window.event;
if (event.key == 'Enter')
page_start_search();
}
</script>
@@ -0,0 +1,28 @@
<script>
'use strict';
function create_submit() {
var project = $('#create_project').val(),
user = $('#create_user').val().trim().toLowerCase();
if ((project == '') || (user.substring(0, 4) == 'pwic'))
alert({% trans %}'The parameters are not acceptable.'{% endtrans %});
else {
$('INPUT[type=button]').attr('disabled', '');
fetch('/api/user/create', { method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams({ project: project,
user: user}),
credentials: 'same-origin'})
.then(response => {
$('INPUT[type=button]').removeAttr('disabled');
if (!response.ok)
throw Error(response.status + ' ' + response.statusText);
window.location = '/' + project + '/special/roles';
})
.catch(error => {
alert(error);
$('INPUT[type=button]').removeAttr('disabled');
});
}
}
</script>
@@ -0,0 +1,33 @@
<script>
'use strict';
function roles_toggle(id, project, user, role) {
var element = $('#roles_tag_' + id);
if (element.length > 0) {
element.toggleClass('pwic_hidden'); // Hide until the request is completed
fetch('/api/user/roles/set', { method: 'POST',
body: new URLSearchParams({ project: project,
name: user,
role: role}),
credentials: 'same-origin'})
.then(response => {
if (!response.ok)
throw Error(response.status + ' ' + response.statusText);
response.text().then(text => {
setTimeout(() => {
if (element.attr('type') == 'checkbox')
element.prop('checked', text == 'X');
if (text != 'OK')
element.toggleClass('pwic_hidden');
}, 2000);
});
})
.catch(error => setTimeout(() => element.toggleClass('pwic_hidden'), 2000));
}
return false; // The element is updated async later
}
function roles_delete(text, id, project, user) {
return confirm(text) && roles_toggle(id, project, user, 'delete');
}
</script>
+55
View File
@@ -0,0 +1,55 @@
<script>
'use strict';
function user_password_popup() {
$('#user_password_popup').toggleClass('pwic_hidden');
$('BODY').toggleClass('pwic_nooverflow');
if ($('#user_password_popup').hasClass('pwic_hidden'))
$('#user_password_current, #user_password_new1, #user_password_new2').val('');
else {
window.scrollTo(0, 0);
$('#user_password_notice').toggleClass('pwic_hidden', window.location.toString().startsWith('https'));
document.getElementById('user_password_current').focus();
}
return false;
}
$('body').on('keydown', event => {
if ((event.key == 'Escape') && (!$('#user_password_popup').hasClass('pwic_hidden')))
user_password_popup();
});
function user_password_submit() {
var cur = $('#user_password_current').val(),
new1 = $('#user_password_new1').val(),
new2 = $('#user_password_new2').val();
if (([cur, new1, new2].indexOf('') !== -1) || (new1 != new2) || (new1 == cur))
alert({% trans %}'The form is inconsistent.'{% endtrans %});
else {
fetch('/api/user/password/change', {method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams({ password_current: cur,
password_new1: new1,
password_new2: new2}),
credentials: 'same-origin'})
.then(response => {
if (!response.ok) {
document.getElementById('user_password_new1').focus();
throw Error({% trans %}'Failure to save your new password. Verify that it matches with the security rules.'{% endtrans %} + ' ['+response.status+']');
}
user_password_popup();
$('#user_password_status').html('{{pwic.emojis.green_check}}');
alert({% trans %}'Your password has been changed successfully.'{% endtrans %});
})
.catch(error => alert(error));
}
}
function user_language_set() {
fetch('/api/user/language/set', { method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams({language: $('#user_language').val()}),
credentials: 'same-origin'})
.then(response => { if (response.ok) location.reload() });
}
</script>