Merge branch 'fixes' into 'v1.1.x'

Various fixes

Closes #566

See merge request framasoft/framadate/framadate!498
This commit is contained in:
Thomas Citharel 2021-12-17 14:23:42 +00:00
commit 2995851e2a
34 changed files with 557 additions and 468 deletions

View File

@ -46,6 +46,7 @@ $ALLOWED_LANGUAGES = [
'de' => 'Deutsch', 'de' => 'Deutsch',
'it' => 'Italiano', 'it' => 'Italiano',
'br' => 'Brezhoneg', 'br' => 'Brezhoneg',
'ca' => 'Català',
]; ];
const DEFAULT_LANGUAGE = 'en'; const DEFAULT_LANGUAGE = 'en';
require_once ROOT_DIR . 'app/inc/i18n.php'; require_once ROOT_DIR . 'app/inc/i18n.php';
@ -182,7 +183,7 @@ usort($messages, 'compareCheckMessage');
<body> <body>
<div class="container ombre"> <div class="container ombre">
<div class="row"> <div class="row">
<form method="get" action="" class="hidden-print"> <form method="get" class="hidden-print">
<div class="input-group input-group-sm pull-right col-xs-12 col-sm-2"> <div class="input-group input-group-sm pull-right col-xs-12 col-sm-2">
<select name="lang" class="form-control" title="<?=__('Language selector', 'Select the language')?>" > <select name="lang" class="form-control" title="<?=__('Language selector', 'Select the language')?>" >
<?php foreach ($ALLOWED_LANGUAGES as $lang_key => $language) { ?> <?php foreach ($ALLOWED_LANGUAGES as $lang_key => $language) { ?>

View File

@ -80,7 +80,7 @@ $messagePollCreated = $sessionService->get("Framadate", "messagePollCreated", FA
if ($messagePollCreated) { if ($messagePollCreated) {
$sessionService->remove("Framadate", "messagePollCreated"); $sessionService->remove("Framadate", "messagePollCreated");
$message = new Message('success', __('adminstuds', 'The poll is created.')); $message = new Message('success', __('adminstuds', 'The poll is created.'));
} }
@ -137,9 +137,9 @@ if (isset($_POST['update_poll_info'])) {
break; break;
} }
} elseif ($field === 'expiration_date') { } elseif ($field === 'expiration_date') {
$expiration_date = $inputService->filterDate($_POST['expiration_date']); $expiration_date = $inputService->validateDate($_POST['expiration_date'], $pollService->minExpiryDate(), $pollService->maxExpiryDate());
if ($expiration_date) { if ($expiration_date) {
$poll->end_date = $expiration_date; $poll->end_date = $expiration_date->getTimestamp();
$updated = true; $updated = true;
} }
} elseif ($field === 'name') { } elseif ($field === 'name') {

View File

@ -120,9 +120,22 @@ class InputService {
return $this->returnIfNotBlank($comment); return $this->returnIfNotBlank($comment);
} }
public function filterDate($date) { public function validateDate(string $date, DateTime $maxDate, DateTime $minDate): DateTime {
$dDate = DateTime::createFromFormat(__('Date', 'datetime_parseformat'), $date)->setTime(0, 0, 0); $dDate = $this->parseDate($date);
return $dDate->format('Y-m-d H:i:s'); if (!$dDate) return $maxDate;
if ($dDate < $minDate) {
return $minDate;
} elseif ($maxDate < $dDate) {
return $maxDate;
}
return $dDate;
}
/**
* @return DateTime|false
*/
private function parseDate(string $date) {
return DateTime::createFromFormat(__('Date', 'datetime_parseformat'), $date)->setTime(0, 0, 0);
} }
/** /**

View File

@ -18,6 +18,8 @@
*/ */
namespace Framadate\Services; namespace Framadate\Services;
use DateInterval;
use DateTime;
use Framadate\Exception\AlreadyExistsException; use Framadate\Exception\AlreadyExistsException;
use Framadate\Exception\ConcurrentEditionException; use Framadate\Exception\ConcurrentEditionException;
use Framadate\Exception\ConcurrentVoteException; use Framadate\Exception\ConcurrentVoteException;
@ -95,12 +97,12 @@ class PollService {
*/ */
public function updateVote($poll_id, $vote_id, $name, $choices, $slots_hash) { public function updateVote($poll_id, $vote_id, $name, $choices, $slots_hash) {
$this->checkVoteConstraints($choices, $poll_id, $slots_hash, $name, $vote_id); $this->checkVoteConstraints($choices, $poll_id, $slots_hash, $name, $vote_id);
// Update vote // Update vote
$choices = implode($choices); $choices = implode($choices);
return $this->voteRepository->update($poll_id, $vote_id, $name, $choices); return $this->voteRepository->update($poll_id, $vote_id, $name, $choices);
} }
/** /**
* @param $poll_id * @param $poll_id
* @param $name * @param $name
@ -113,7 +115,7 @@ class PollService {
*/ */
function addVote($poll_id, $name, $choices, $slots_hash) { function addVote($poll_id, $name, $choices, $slots_hash) {
$this->checkVoteConstraints($choices, $poll_id, $slots_hash, $name); $this->checkVoteConstraints($choices, $poll_id, $slots_hash, $name);
// Insert new vote // Insert new vote
$choices = implode($choices); $choices = implode($choices);
$token = $this->random(16); $token = $this->random(16);
@ -124,7 +126,7 @@ class PollService {
if ($this->commentRepository->exists($poll_id, $name, $comment)) { if ($this->commentRepository->exists($poll_id, $name, $comment)) {
return true; return true;
} }
return $this->commentRepository->insert($poll_id, $name, $comment); return $this->commentRepository->insert($poll_id, $name, $comment);
} }
@ -232,18 +234,18 @@ class PollService {
} }
/** /**
* @return int The max timestamp allowed for expiry date * @return DateTime The max date allowed for expiry date
*/ */
public function maxExpiryDate() { public function maxExpiryDate(): DateTime {
global $config; global $config;
return time() + (86400 * $config['default_poll_duration']); return (new DateTime())->add(new DateInterval('P' . $config['default_poll_duration'] . 'D'));
} }
/** /**
* @return int The min timestamp allowed for expiry date * @return DateTime The min date allowed for expiry date
*/ */
public function minExpiryDate() { public function minExpiryDate() {
return time() + 86400; return (new DateTime())->add(new DateInterval('P1D'));
} }
/** /**
@ -251,7 +253,10 @@ class PollService {
*/ */
public function sortSlorts(&$slots) { public function sortSlorts(&$slots) {
uasort($slots, function ($a, $b) { uasort($slots, function ($a, $b) {
return $a->title > $b->title; if ($a->title === $b->title) {
return 0;
}
return $a->title > $b->title ? 1 : -1;
}); });
return $slots; return $slots;
} }
@ -292,7 +297,7 @@ class PollService {
private function random($length) { private function random($length) {
return Token::getToken($length); return Token::getToken($length);
} }
/** /**
* @param $choices * @param $choices
* @param $poll_id * @param $poll_id
@ -310,20 +315,20 @@ class PollService {
} else { } else {
$exists = $this->voteRepository->existsByPollIdAndNameAndVoteId($poll_id, $name, $vote_id); $exists = $this->voteRepository->existsByPollIdAndNameAndVoteId($poll_id, $name, $vote_id);
} }
if ($exists) { if ($exists) {
throw new AlreadyExistsException(); throw new AlreadyExistsException();
} }
$poll = $this->findById($poll_id); $poll = $this->findById($poll_id);
// Check that no-one voted in the meantime and it conflicts the maximum votes constraint // Check that no-one voted in the meantime and it conflicts the maximum votes constraint
$this->checkMaxVotes($choices, $poll, $poll_id); $this->checkMaxVotes($choices, $poll, $poll_id);
// Check if slots are still the same // Check if slots are still the same
$this->checkThatSlotsDidntChanged($poll, $slots_hash); $this->checkThatSlotsDidntChanged($poll, $slots_hash);
} }
/** /**
* This method checks if the hash send by the user is the same as the computed hash. * This method checks if the hash send by the user is the same as the computed hash.
* *

View File

@ -60,17 +60,17 @@ class Utils {
<link rel="stylesheet" href="' . self::get_server_name() . 'css/style.css" /> <link rel="stylesheet" href="' . self::get_server_name() . 'css/style.css" />
<link rel="stylesheet" href="' . self::get_server_name() . 'css/frama.css" /> <link rel="stylesheet" href="' . self::get_server_name() . 'css/frama.css" />
<link rel="stylesheet" href="' . self::get_server_name() . 'css/print.css" media="print" /> <link rel="stylesheet" href="' . self::get_server_name() . 'css/print.css" media="print" />
<script type="text/javascript" src="' . self::get_server_name() . 'js/jquery-1.12.4.min.js"></script> <script src="' . self::get_server_name() . 'js/jquery-1.12.4.min.js"></script>
<script type="text/javascript" src="' . self::get_server_name() . 'js/bootstrap.min.js"></script> <script src="' . self::get_server_name() . 'js/bootstrap.min.js"></script>
<script type="text/javascript" src="' . self::get_server_name() . 'js/bootstrap-datepicker.js"></script>'; <script src="' . self::get_server_name() . 'js/bootstrap-datepicker.js"></script>';
if ('en' !== $locale) { if ('en' !== $locale) {
echo ' echo '
<script type="text/javascript" src="' . self::get_server_name() . 'js/locales/bootstrap-datepicker.' . $locale . '.js"></script>'; <script src="' . self::get_server_name() . 'js/locales/bootstrap-datepicker.' . $locale . '.js"></script>';
} }
echo ' echo '
<script type="text/javascript" src="' . self::get_server_name() . 'js/core.js"></script>'; <script src="' . self::get_server_name() . 'js/core.js"></script>';
if (is_file($_SERVER['DOCUMENT_ROOT'] . "/nav/nav.js")) { if (is_file($_SERVER['DOCUMENT_ROOT'] . "/nav/nav.js")) {
echo '<script src="/nav/nav.js" id="nav_js" type="text/javascript" charset="utf-8"></script><!-- /Framanav -->'; echo '<script src="/nav/nav.js" id="nav_js" charset="utf-8"></script><!-- /Framanav -->';
} }
echo ' echo '

View File

@ -55,6 +55,7 @@ if (is_file(CONF_FILENAME)) {
'de' => 'Deutsch', 'de' => 'Deutsch',
'it' => 'Italiano', 'it' => 'Italiano',
'br' => 'Brezhoneg', 'br' => 'Brezhoneg',
'ca' => 'Català'
]; ];
} }

View File

@ -28,7 +28,7 @@ function bandeau_titre($titre)
echo ' echo '
<header role="banner">'; <header role="banner">';
if(count($ALLOWED_LANGUAGES) > 1){ if(count($ALLOWED_LANGUAGES) > 1){
echo '<form method="post" action="" class="hidden-print"> echo '<form method="post" class="hidden-print">
<div class="input-group input-group-sm pull-right col-md-2 col-xs-4"> <div class="input-group input-group-sm pull-right col-md-2 col-xs-4">
<select name="lang" class="form-control" title="' . __('Language selector', 'Select the language') . '" >' . liste_lang() . '</select> <select name="lang" class="form-control" title="' . __('Language selector', 'Select the language') . '" >' . liste_lang() . '</select>
<span class="input-group-btn"> <span class="input-group-btn">
@ -43,7 +43,7 @@ function bandeau_titre($titre)
<hr class="trait" role="presentation" /> <hr class="trait" role="presentation" />
</header> </header>
<main role="main">'; <main role="main">';
global $connect; global $connect;
$tables = $connect->allTables(); $tables = $connect->allTables();
$diff = array_diff([Utils::table('comment'), Utils::table('poll'), Utils::table('slot'), Utils::table('vote')], $tables); $diff = array_diff([Utils::table('comment'), Utils::table('poll'), Utils::table('slot'), Utils::table('vote')], $tables);

View File

@ -54,10 +54,15 @@
"email": "raphael.droz@gmail.com" "email": "raphael.droz@gmail.com"
} }
], ],
"scripts": {
"cs:check": "php-cs-fixer fix --dry-run --diff",
"cs:fix": "php-cs-fixer fix",
"lint": "find . -name \\*.php -not -path './vendor/*' -not -path './build/*' -not -path './tests/integration/vendor/*' -print0 | xargs -0 -n1 php -l"
},
"require": { "require": {
"php": ">=7.3.0", "php": ">=7.3.0",
"ext-pdo": "*", "ext-pdo": "*",
"smarty/smarty": "^3.1", "smarty/smarty": "^4.0",
"o80/i18n": "dev-develop", "o80/i18n": "dev-develop",
"phpmailer/phpmailer": "~6.2", "phpmailer/phpmailer": "~6.2",
"ircmaxell/password-compat": "dev-master", "ircmaxell/password-compat": "dev-master",

615
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -17,6 +17,7 @@
* Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft) * Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
*/ */
use Framadate\Choice; use Framadate\Choice;
use Framadate\Services\InputService;
use Framadate\Services\LogService; use Framadate\Services\LogService;
use Framadate\Services\MailService; use Framadate\Services\MailService;
use Framadate\Services\PollService; use Framadate\Services\PollService;
@ -33,6 +34,7 @@ $pollService = new PollService($connect, $logService);
$mailService = new MailService($config['use_smtp'], $config['smtp_options']); $mailService = new MailService($config['use_smtp'], $config['smtp_options']);
$purgeService = new PurgeService($connect, $logService); $purgeService = new PurgeService($connect, $logService);
$sessionService = new SessionService(); $sessionService = new SessionService();
$inputService = new InputService();
if (is_file('bandeaux_local.php')) { if (is_file('bandeaux_local.php')) {
include_once('bandeaux_local.php'); include_once('bandeaux_local.php');
@ -49,10 +51,6 @@ if (empty($form->title) || empty($form->admin_name) || (($config['use_smtp']) ?
$smarty->display('error.tpl'); $smarty->display('error.tpl');
exit; exit;
} }
// Min/Max archive date
$min_expiry_time = $pollService->minExpiryDate();
$max_expiry_time = $pollService->maxExpiryDate();
// The poll format is other (A) if we are in this file // The poll format is other (A) if we are in this file
if (!isset($form->format)) { if (!isset($form->format)) {
$form->format = 'A'; $form->format = 'A';
@ -66,28 +64,8 @@ if (empty($form->title) || empty($form->admin_name) || (($config['use_smtp']) ?
// Step 4 : Data prepare before insert in DB // Step 4 : Data prepare before insert in DB
if (isset($_POST['confirmation'])) { if (isset($_POST['confirmation'])) {
// Define expiration date // Define expiration date
$enddate = filter_input(INPUT_POST, 'enddate', FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => '#^[0-9]{2}/[0-9]{2}/[0-9]{4}$#']]); $expiration_date = $inputService->validateDate($_POST['expiration_date'], $pollService->minExpiryDate(), $pollService->maxExpiryDate());
$form->end_date = $expiration_date->getTimestamp();
if (!empty($enddate)) {
$registredate = explode('/', $enddate);
if (is_array($registredate) && count($registredate) === 3) {
$time = mktime(0, 0, 0, $registredate[1], $registredate[0], $registredate[2]);
if ($time < $min_expiry_time) {
$form->end_date = $min_expiry_time;
} elseif ($max_expiry_time < $time) {
$form->end_date = $max_expiry_time;
} else {
$form->end_date = $time;
}
}
}
if (empty($form->end_date)) {
// By default, expiration date is 6 months after last day
$form->end_date = $max_expiry_time;
}
// Insert poll in database // Insert poll in database
$ids = $pollService->createPoll($form); $ids = $pollService->createPoll($form);
@ -137,7 +115,7 @@ if (empty($form->title) || empty($form->admin_name) || (($config['use_smtp']) ?
} }
// Expiration date is initialised with config parameter. Value will be modified in step 4 if user has defined an other date // Expiration date is initialised with config parameter. Value will be modified in step 4 if user has defined an other date
$form->end_date = $max_expiry_time; $form->end_date = $pollService->maxExpiryDate()->format('Y-m-d H:i:s');
// Summary // Summary
$summary = '<ol>'; $summary = '<ol>';
@ -163,7 +141,7 @@ if (empty($form->title) || empty($form->admin_name) || (($config['use_smtp']) ?
} }
$summary .= '</ol>'; $summary .= '</ol>';
$end_date_str = utf8_encode(strftime($date_format['txt_date'], $max_expiry_time)); //textual date $end_date_str = utf8_encode(strftime($date_format['txt_date'], $pollService->maxExpiryDate()->getTimestamp())); //textual date
$_SESSION['form'] = serialize($form); $_SESSION['form'] = serialize($form);
@ -181,7 +159,7 @@ if (empty($form->title) || empty($form->admin_name) || (($config['use_smtp']) ?
bandeau_titre(__('Step 2 classic', 'Poll subjects (2 on 3)')); bandeau_titre(__('Step 2 classic', 'Poll subjects (2 on 3)'));
echo ' echo '
<form name="formulaire" action="' . Utils::get_server_name() . 'create_classic_poll.php" method="POST" class="form-horizontal" role="form"> <form name="formulaire" action="' . Utils::get_server_name() . 'create_classic_poll.php" method="POST" class="form-horizontal">
<div class="row"> <div class="row">
<div class="col-md-8 col-md-offset-2">'; <div class="col-md-8 col-md-offset-2">';
echo ' echo '
@ -255,8 +233,8 @@ if (empty($form->title) || empty($form->admin_name) || (($config['use_smtp']) ?
</div> </div>
</form> </form>
<script type="text/javascript" src="js/app/framadatepicker.js"></script> <script src="js/app/framadatepicker.js"></script>
<script type="text/javascript" src="js/app/classic_poll.js"></script> <script src="js/app/classic_poll.js"></script>
' . "\n"; ' . "\n";
bandeau_pied(); bandeau_pied();

View File

@ -40,10 +40,6 @@ if (is_readable('bandeaux_local.php')) {
include_once('bandeaux_local.php'); include_once('bandeaux_local.php');
} }
// Min/Max archive date
$min_expiry_time = $pollService->minExpiryDate();
$max_expiry_time = $pollService->maxExpiryDate();
$form = unserialize($_SESSION['form']); $form = unserialize($_SESSION['form']);
// The poll format is DATE if we are in this file // The poll format is DATE if we are in this file
@ -175,7 +171,7 @@ switch ($step) {
} }
$summary .= '</ul>'; $summary .= '</ul>';
$end_date_str = utf8_encode(strftime($date_format['txt_date'], $max_expiry_time)); // textual date $end_date_str = utf8_encode(strftime($date_format['txt_date'], $pollService->maxExpiryDate()->getTimestamp())); // textual date
$_SESSION['form'] = serialize($form); $_SESSION['form'] = serialize($form);
@ -192,28 +188,8 @@ switch ($step) {
// Step 4 : Data prepare before insert in DB // Step 4 : Data prepare before insert in DB
// Define expiration date // Define expiration date
$enddate = filter_input(INPUT_POST, 'enddate', FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => '#^[0-9]{2}/[0-9]{2}/[0-9]{4}$#']]); $expiration_date = $inputService->validateDate($_POST['enddate'], $pollService->minExpiryDate(), $pollService->maxExpiryDate());
$form->end_date = $expiration_date->getTimestamp();
if (!empty($enddate)) {
$registredate = explode('/', $enddate);
if (is_array($registredate) && count($registredate) === 3) {
$time = mktime(0, 0, 0, $registredate[1], $registredate[0], $registredate[2]);
if ($time < $min_expiry_time) {
$form->end_date = $min_expiry_time;
} elseif ($max_expiry_time < $time) {
$form->end_date = $max_expiry_time;
} else {
$form->end_date = $time;
}
}
}
if (empty($form->end_date)) {
// By default, expiration date is 6 months after last day
$form->end_date = $max_expiry_time;
}
// Insert poll in database // Insert poll in database
$ids = $pollService->createPoll($form); $ids = $pollService->createPoll($form);

7
css/easymde.min.css vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -17,13 +17,13 @@
*/ */
$(document).ready(function () { $(document).ready(function () {
/** /**
* Error check when submitting form * Error check when submitting form
*/ */
$("#formulaire").submit(function (event) { $("#formulaire").submit(function (event) {
var isHidden = $("#hidden").prop('checked'); var isHidden = $("#hidden").prop("checked");
var isOptionAllUserCanModifyEverything = $("#editableByAll").is(":checked"); var isOptionAllUserCanModifyEverything =
$("#editableByAll").is(":checked");
if (isHidden && isOptionAllUserCanModifyEverything) { if (isHidden && isOptionAllUserCanModifyEverything) {
event.preventDefault(); event.preventDefault();
@ -44,22 +44,23 @@ $(document).ready(function () {
} }
}); });
/** /**
* Enable/Disable ValueMax options * Enable/Disable ValueMax options
*/ */
$("#use_ValueMax").change(function () { const useValueMax = document.querySelector("#use_ValueMax");
if ($(this).prop("checked")) { useValueMax.addEventListener("change", function () {
$("#ValueMax").removeClass("hidden"); const valueMaxOptions = document.querySelector("#value_max_options");
if (useValueMax.checked) {
valueMaxOptions.classList.remove("hidden");
} else { } else {
$("#ValueMax").addClass("hidden"); valueMaxOptions.classList.add("hidden");
} }
}); });
/** /**
* Hide/Show password options * Hide/Show password options
*/ */
$("#use_password").change(function(){ $("#use_password").change(function () {
if ($(this).prop("checked")) { if ($(this).prop("checked")) {
$("#password_options").removeClass("hidden"); $("#password_options").removeClass("hidden");
} else { } else {
@ -88,9 +89,12 @@ $(document).ready(function () {
document.getElementById("cookie-warning").setAttribute("style", ""); document.getElementById("cookie-warning").setAttribute("style", "");
} }
var wrapper = new MDEWrapper($('#poll_comments')[0], $('#rich-editor-button'), $('#simple-editor-button')); var wrapper = new MDEWrapper(
if ($('#rich-editor-button').hasClass('active')) { $("#poll_comments")[0],
$("#rich-editor-button"),
$("#simple-editor-button")
);
if ($("#rich-editor-button").hasClass("active")) {
wrapper.enable(); wrapper.enable();
} }
}); });

7
js/easymde.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,12 +1,12 @@
function myPreviewRender (text) { function myPreviewRender(text) {
text = text.replace(/[\u00A0-\u9999<>\&]/gim, function(i) { text = text.replace(/[\u00A0-\u9999<>\&]/gim, function (i) {
return '&#'+i.charCodeAt(0)+';'; return "&#" + i.charCodeAt(0) + ";";
}); });
text = SimpleMDE.prototype.markdown(text); text = SimpleMDE.prototype.markdown(text);
text = DOMPurify.sanitize(text); text = DOMPurify.sanitize(text);
return text; return text;
}; }
function MDEWrapper(textarea, enableButton, disableButton) { function MDEWrapper(textarea, enableButton, disableButton) {
this.element = textarea; this.element = textarea;
@ -17,47 +17,53 @@ function MDEWrapper(textarea, enableButton, disableButton) {
var wrapper = this; var wrapper = this;
if (this.enableButton) { if (this.enableButton) {
this.enableButton.on('click', function() {wrapper.enable()}); this.enableButton.on("click", function () {
wrapper.enable();
});
} }
if (this.disableButton) { if (this.disableButton) {
this.disableButton.on('click', function() {wrapper.disable()}); this.disableButton.on("click", function () {
wrapper.disable();
});
} }
} }
MDEWrapper.prototype.enable = function() { MDEWrapper.prototype.enable = function () {
var wrapper = this; var wrapper = this;
if (this.simplemde == null) { if (this.simplemde == null) {
this.simplemde = new SimpleMDE({ this.simplemde = new EasyMDE({
element: wrapper.element, element: wrapper.element,
forceSync: true, forceSync: true,
status: true, status: true,
previewRender: myPreviewRender, previewRender: myPreviewRender,
spellChecker: false, spellChecker: false,
promptURLs: true, promptURLs: true,
autoDownloadFontAwesome: false minHeight: "200px",
maxHeight: "300px",
autoDownloadFontAwesome: false,
}); });
if (this.enableButton) { if (this.enableButton) {
this.enableButton.addClass('active'); this.enableButton.addClass("active");
} }
if (this.disableButton) { if (this.disableButton) {
this.disableButton.removeClass('active'); this.disableButton.removeClass("active");
} }
} }
} };
MDEWrapper.prototype.disable = function() { MDEWrapper.prototype.disable = function () {
if (this.simplemde != null) { if (this.simplemde != null) {
this.simplemde.toTextArea(); this.simplemde.toTextArea();
this.simplemde = null; this.simplemde = null;
if (this.disableButton) { if (this.disableButton) {
this.disableButton.addClass('active'); this.disableButton.addClass("active");
} }
if (this.enableButton) { if (this.enableButton) {
this.enableButton.removeClass('active'); this.enableButton.removeClass("active");
} }
} }
} };
MDEWrapper.prototype.isEnabled = function() { MDEWrapper.prototype.isEnabled = function () {
return this.simplemde != null; return this.simplemde != null;
} };

15
js/simplemde.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -436,7 +436,7 @@
"Remove the column": "Effacer la colonne", "Remove the column": "Effacer la colonne",
"Remove the comments": "Supprimer les commentaires", "Remove the comments": "Supprimer les commentaires",
"Remove the votes": "Supprimer les votes", "Remove the votes": "Supprimer les votes",
"The poll is created.": "The poll was created.", "The poll is created.": "Le sondage a été créé.",
"Vote added": "Vote ajouté", "Vote added": "Vote ajouté",
"Vote deleted": "Vote supprimé", "Vote deleted": "Vote supprimé",
"Vote updated": "Vote mis à jour", "Vote updated": "Vote mis à jour",

View File

@ -1,5 +1,6 @@
User-agent: * User-agent: *
Allow: / Allow: /
Allow: /abc/
Allow: /index.php Allow: /index.php
Allow: /create_poll.php Allow: /create_poll.php
Disallow: /* Disallow: /*

View File

@ -1,13 +1,13 @@
{extends file='page.tpl'} {extends file='page.tpl'}
{block name="header"} {block name="header"}
<script type="text/javascript"> <script>
window.date_formats = { window.date_formats = {
DATE: '{__('Date', 'DATE')}', DATE: '{__('Date', 'DATE')}',
DATEPICKER: '{__('Date', 'datepicker')}' DATEPICKER: '{__('Date', 'datepicker')}'
}; };
</script> </script>
<script type="text/javascript" src="{'js/app/framadatepicker.js'|resource}"></script> <script src="{'js/app/framadatepicker.js'|resource}"></script>
{/block} {/block}
{block name=main} {block name=main}
@ -50,4 +50,4 @@
</div> </div>
</div> </div>
</form> </form>
{/block} {/block}

View File

@ -59,6 +59,7 @@ $ALLOWED_LANGUAGES = [
'nl' => 'Dutch', 'nl' => 'Dutch',
'it' => 'Italiano', 'it' => 'Italiano',
'br' => 'Brezhoneg', 'br' => 'Brezhoneg',
'ca' => 'Català',
]; ];
// Path to image file with the title // Path to image file with the title

View File

@ -3,7 +3,7 @@
{block 'main'} {block 'main'}
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">
<form action="" method="POST"> <form method="POST">
{if $error} {if $error}
<div id="result" class="alert alert-danger"> <div id="result" class="alert alert-danger">

View File

@ -1,14 +1,14 @@
{extends 'admin/admin_page.tpl'} {extends 'admin/admin_page.tpl'}
{block name="header"} {block name="header"}
<script src="{"js/app/admin/polls.js"|resource}" type="text/javascript"></script> <script src="{"js/app/admin/polls.js"|resource}"></script>
{/block} {/block}
{block 'admin_main'} {block 'admin_main'}
<div class="panel panel-default" id="poll_search"> <div class="panel panel-default" id="poll_search">
<div class="panel-heading">{__('Generic', 'Search')}</div> <div class="panel-heading">{__('Generic', 'Search')}</div>
<div class="panel-body" style="display: none;"> <div class="panel-body" style="display: none;">
<form action="" method="GET"> <form method="GET">
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-6">
<div class="form-group"> <div class="form-group">
@ -44,7 +44,7 @@
</div> </div>
</div> </div>
<form action="" method="POST"> <form method="POST">
<input type="hidden" name="csrf" value="{$crsf}"/> <input type="hidden" name="csrf" value="{$crsf}"/>
{if $poll_to_delete} {if $poll_to_delete}
<div class="alert alert-warning text-center"> <div class="alert alert-warning text-center">

View File

@ -4,7 +4,7 @@
{if $message} {if $message}
<div class="alert alert-dismissible alert-info" role="alert">{$message|html}<button type="button" class="close" data-dismiss="alert" aria-label="{__('Generic', 'Close')}"><span aria-hidden="true">&times;</span></button></div> <div class="alert alert-dismissible alert-info" role="alert">{$message|html}<button type="button" class="close" data-dismiss="alert" aria-label="{__('Generic', 'Close')}"><span aria-hidden="true">&times;</span></button></div>
{/if} {/if}
<form action="" method="POST"> <form method="POST">
<input type="hidden" name="csrf" value="{$crsf}"/> <input type="hidden" name="csrf" value="{$crsf}"/>
<div class="text-center"> <div class="text-center">
<button type="submit" name="action" value="purge" class="btn btn-danger">{__('Admin', 'Purge the polls')} <span class="glyphicon glyphicon-trash"></span></button> <button type="submit" name="action" value="purge" class="btn btn-danger">{__('Admin', 'Purge the polls')} <span class="glyphicon glyphicon-trash"></span></button>

View File

@ -1,17 +1,17 @@
{extends file='page.tpl'} {extends file='page.tpl'}
{block name="header"} {block name="header"}
<script type="text/javascript"> <script>
window.date_formats = { window.date_formats = {
DATE: '{__('Date', 'DATE')}', DATE: '{__('Date', 'DATE')}',
DATEPICKER: '{__('Date', 'datepicker')}' DATEPICKER: '{__('Date', 'datepicker')}'
}; };
</script> </script>
<script type="text/javascript" src="{'js/app/framadatepicker.js'|resource}"></script> <script src="{'js/app/framadatepicker.js'|resource}"></script>
{/block} {/block}
{block name="main"} {block name="main"}
<form name="formulaire" method="POST" class="form-horizontal" role="form"> <form name="formulaire" method="POST" class="form-horizontal">
<div class="row"> <div class="row">
<div class="col-md-8 col-md-offset-2"> <div class="col-md-8 col-md-offset-2">
<div class="well summary"> <div class="well summary">
@ -45,4 +45,4 @@
</div> </div>
</div> </div>
</form> </form>
{/block} {/block}

View File

@ -1,18 +1,18 @@
{extends file='page.tpl'} {extends file='page.tpl'}
{block name="header"} {block name="header"}
<script type="text/javascript"> <script>
window.date_formats = { window.date_formats = {
DATE: '{__('Date', 'DATE')}', DATE: '{__('Date', 'DATE')}',
DATEPICKER: '{__('Date', 'datepicker')}' DATEPICKER: '{__('Date', 'datepicker')}'
}; };
</script> </script>
<script type="text/javascript" src="{'js/app/framadatepicker.js'|resource}"></script> <script src="{'js/app/framadatepicker.js'|resource}"></script>
<script type="text/javascript" src="{'js/app/date_poll.js'|resource}"></script> <script src="{'js/app/date_poll.js'|resource}"></script>
{/block} {/block}
{block name=main} {block name=main}
<form name="formulaire" action="" method="POST" class="form-horizontal" role="form"> <form name="formulaire" method="POST" class="form-horizontal">
<div class="row" id="selected-days"> <div class="row" id="selected-days">
<div class="col-md-10 col-md-offset-1"> <div class="col-md-10 col-md-offset-1">
<h3>{__('Step 2 date', 'Choose the dates of your poll')}</h3> <h3>{__('Step 2 date', 'Choose the dates of your poll')}</h3>

View File

@ -1,19 +1,19 @@
{extends file='page.tpl'} {extends file='page.tpl'}
{block name="header"} {block name="header"}
<script src="{"js/simplemde.min.js"|resource}" type="text/javascript"></script> <script src="{"js/easymde.min.js"|resource}"></script>
<script src="{"js/dompurify.js"|resource}" type="text/javascript"></script> <script src="{"js/dompurify.js"|resource}"></script>
<script src="{"js/mde-wrapper.js"|resource}" type="text/javascript"></script> <script src="{"js/mde-wrapper.js"|resource}"></script>
<script src="{"js/app/create_poll.js"|resource}" type="text/javascript"></script> <script src="{"js/app/create_poll.js"|resource}"></script>
<link rel="stylesheet" href="{"css/app/create_poll.css"|resource}"> <link rel="stylesheet" href="{"css/app/create_poll.css"|resource}">
<link rel="stylesheet" href="{"css/simplemde.min.css"|resource}"> <link rel="stylesheet" href="{"css/easymde.min.css"|resource}">
{/block} {/block}
{block name=main} {block name=main}
<div class="row" style="display:none" id="form-block"> <div class="row" style="display:none" id="form-block">
<div class="col-md-8 col-md-offset-2"> <div class="col-md-8 col-md-offset-2">
<form name="formulaire" id="formulaire" action="" method="POST" class="form-horizontal" role="form"> <form name="formulaire" id="formulaire" method="POST" class="form-horizontal">
<div class="alert alert-info"> <div class="alert alert-info">
<p> <p>
@ -129,36 +129,30 @@
{* Value MAX *} {* Value MAX *}
<div class="form-group {$errors['ValueMax']['class']}"> <div class="form-group {$errors['ValueMax']['class']}">
<label for="use_valueMax" class="col-sm-4 control-label"> <label for="use_valueMax" class="col-sm-4 control-label">
{__('Step 1', 'Value Max')}<br/> {__('Step 1', 'Value Max')}<br/>
</label> </label>
<div class="col-sm-8"> <div class="col-sm-8">
<div class="checkbox"> <div class="checkbox">
<label>
<input id="use_ValueMax" name="use_ValueMax" type="checkbox" {if $use_ValueMax}checked{/if}>
{__('Step 1', "Limit the amount of voters per option")}
</label>
</div>
</div>
</div>
<div class="form-group {$errors['ValueMax']['class']}">
<div id="ValueMax" {if !$use_ValueMax}class="hidden"{/if}>
<div class="col-sm-offset-4 col-sm-8">
<label> <label>
<input id="ValueMax" type="number" min="0" name="ValueMax" value="{$ValueMax|html}" {$errors['ValueMax']['aria']}> <input id="use_ValueMax" name="use_ValueMax" type="checkbox" {if $use_ValueMax}checked{/if} />
{__('Step 1', "Limit the amount of voters per option")}
{__('Step 1', "ValueMax instructions")}
</label> </label>
</div> </div>
</div> </div>
</div> <div id="value_max_options" {if !$use_ValueMax}class="hidden"{/if}>
<div class="col-sm-offset-4 col-sm-8">
<label for="ValueMax">
<input id="ValueMax" type="number" min="0" name="ValueMax" value="{$ValueMax|html}" {$errors['ValueMax']['aria']} />
{__('Step 1', "ValueMax instructions")}
</label>
</div>
</div>
</div>
{if !empty($errors['ValueMax']['msg'])} {if !empty($errors['ValueMax']['msg'])}
<div class="alert alert-danger"> <div class="alert alert-danger">
<p id="poll_customized_url_error"> <p id="poll_value_max_error">
{$errors['ValueMax']['msg']} {$errors['ValueMax']['msg']}
</p> </p>
</div> </div>
@ -209,7 +203,7 @@
{* Password *} {* Password *}
<div class="form-group"> <div class="form-group">
<label for="poll_id" class="col-sm-4 control-label"> <label for="use_password" class="col-sm-4 control-label">
{__('Step 1', 'Poll password')} {__('Step 1', 'Poll password')}
</label> </label>
@ -263,7 +257,7 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="poll_id" class="col-sm-4 control-label"> <label class="col-sm-4 control-label">
{__('Step 1', 'Permissions')} {__('Step 1', 'Permissions')}
</label> </label>
<div class="col-sm-8"> <div class="col-sm-8">
@ -335,7 +329,7 @@
class="btn btn-success">{__('Step 1', 'Go to step 2')}</button> class="btn btn-success">{__('Step 1', 'Go to step 2')}</button>
</p> </p>
<script type="text/javascript">document.formulaire.title.focus();</script> <script>document.formulaire.title.focus();</script>
</form> </form>
</div> </div>

View File

@ -4,7 +4,7 @@
{if !empty($message)} {if !empty($message)}
<div class="alert alert-dismissible alert-{$message->type|html}" role="alert">{$message->message|html}{if $message->link != null}<br/><a href="{$message->link}">{$message->link}</a>{/if}<button type="button" class="close" data-dismiss="alert" aria-label="{__('Generic', 'Close')}"><span aria-hidden="true">&times;</span></button></div> <div class="alert alert-dismissible alert-{$message->type|html}" role="alert">{$message->message|html}{if $message->link != null}<br/><a href="{$message->link}">{$message->link}</a>{/if}<button type="button" class="close" data-dismiss="alert" aria-label="{__('Generic', 'Close')}"><span aria-hidden="true">&times;</span></button></div>
{/if} {/if}
<form action="" method="post"> <form method="post">
<div class="row"> <div class="row">
<div class="col-md-6 col-md-offset-3 text-center"> <div class="col-md-6 col-md-offset-3 text-center">
<div class="form-group"> <div class="form-group">

View File

@ -1,6 +1,6 @@
<header role="banner" class="clearfix"> <header class="clearfix">
{if count($langs)>1} {if count($langs)>1}
<form method="post" action="" class="hidden-print"> <form method="post" class="hidden-print">
<div class="input-group input-group-sm pull-right col-xs-12 col-sm-2"> <div class="input-group input-group-sm pull-right col-xs-12 col-sm-2">
<select name="lang" class="form-control" title="{__('Language selector', 'Select the language')}" > <select name="lang" class="form-control" title="{__('Language selector', 'Select the language')}" >
{foreach $langs as $lang_key=>$lang_value} {foreach $langs as $lang_key=>$lang_value}
@ -22,4 +22,4 @@
{if !empty($title)}<h2 class="lead col-xs-12"><i>{$title|html}</i></h2>{/if} {if !empty($title)}<h2 class="lead col-xs-12"><i>{$title|html}</i></h2>{/if}
<div class="trait col-xs-12" role="presentation"></div> <div class="trait col-xs-12" role="presentation"></div>
</header> </header>
<main role="main"> <main>

View File

@ -23,20 +23,20 @@
{if $provide_fork_awesome} {if $provide_fork_awesome}
<link rel="stylesheet" href="{'css/fork-awesome.min.css'|resource}"> <link rel="stylesheet" href="{'css/fork-awesome.min.css'|resource}">
{/if} {/if}
<script type="text/javascript" src="{'js/jquery-1.12.4.min.js'|resource}"></script> <script src="{'js/jquery-1.12.4.min.js'|resource}"></script>
<script type="text/javascript" src="{'js/bootstrap.min.js'|resource}"></script> <script src="{'js/bootstrap.min.js'|resource}"></script>
<script type="text/javascript" src="{'js/bootstrap-datepicker.js'|resource}"></script> <script src="{'js/bootstrap-datepicker.js'|resource}"></script>
{if 'en' != $locale} {if 'en' != $locale}
<script type="text/javascript" src="{$locale|datepicker_path|resource}"></script> <script src="{$locale|datepicker_path|resource}"></script>
{/if} {/if}
<script type="text/javascript" src="{'js/core.js'|resource}"></script> <script src="{'js/core.js'|resource}"></script>
{block name="header"}{/block} {block name="header"}{/block}
</head> </head>
<body> <body>
{if $use_nav_js} {if $use_nav_js}
<script src="https://framasoft.org/nav/nav.js" type="text/javascript"></script> <script src="https://framasoft.org/nav/nav.js"></script>
{/if} {/if}
<div class="container ombre"> <div class="container ombre">

View File

@ -3,7 +3,7 @@
<div class="panel panel-danger password_request alert-danger"> <div class="panel panel-danger password_request alert-danger">
<div class="col-md-6 col-md-offset-3"> <div class="col-md-6 col-md-offset-3">
<form action="" method="POST" class="form-inline"> <form method="POST" class="form-inline">
<input type="hidden" name="poll" value="{$poll_id}"/> <input type="hidden" name="poll" value="{$poll_id}"/>
<div class="form-group"> <div class="form-group">
<label for="password" class="control-label">{__('Password', 'Password')}</label> <label for="password" class="control-label">{__('Password', 'Password')}</label>

View File

@ -255,7 +255,7 @@
</p> </p>
</div> </div>
</div> </div>
<script type="text/javascript"> <script>
$(document).ready(function () { $(document).ready(function () {
$('#showChart').on('click', function() { $('#showChart').on('click', function() {
$('#showChart') $('#showChart')

View File

@ -319,7 +319,7 @@
</p> </p>
</div> </div>
</div> </div>
<script type="text/javascript"> <script>
$(document).ready(function () { $(document).ready(function () {
$('#showChart').on('click', function() { $('#showChart').on('click', function() {
$('#showChart') $('#showChart')

View File

@ -1,17 +1,22 @@
{extends file='page.tpl'} {extends file='page.tpl'}
{block name="header"} {block name="header"}
<script src="{"js/Chart.min.js"|resource}" type="text/javascript"></script> <script src="{"js/Chart.min.js"|resource}"></script>
<script src="{"js/Chart.StackedBar.js"|resource}" type="text/javascript"></script> <script src="{"js/Chart.StackedBar.js"|resource}"></script>
<script src="{"js/app/studs.js"|resource}" type="text/javascript"></script> <script src="{"js/app/studs.js"|resource}"></script>
<link rel="stylesheet" href="{'css/jquery-ui.min.css'|resource}"> <link rel="stylesheet" href="{'css/jquery-ui.min.css'|resource}">
{if $admin} {if $admin}
<script src="{"js/simplemde.min.js"|resource}" type="text/javascript"></script> <script src="{"js/easymde.min.js"|resource}"></script>
<script src="{"js/dompurify.js"|resource}" type="text/javascript"></script> <script src="{"js/dompurify.js"|resource}"></script>
<script src="{"js/mde-wrapper.js"|resource}" type="text/javascript"></script> <script src="{"js/mde-wrapper.js"|resource}"></script>
<script src="{"js/app/adminstuds.js"|resource}" type="text/javascript"></script> <script src="{"js/app/adminstuds.js"|resource}"></script>
<link rel="stylesheet" href="{'css/simplemde.min.css'|resource}"> <link rel="stylesheet" href="{'css/easymde.min.css'|resource}">
{/if}
<meta name="twitter:card" content="summary" />
<meta property="og:title" content="{$poll->title|html} - {$APPLICATION_NAME|html}" />
{if $poll->description}
<meta property="og:description" content="{$poll->description|markdown:true}" />
{/if} {/if}
{/block} {/block}