Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,8 @@ public function edit(Request $request, Response $response, ?int $id = null, stri
'olendsprefs' => $lendsprefs,
'categories' => $categories_list,
'statuses' => $slist,
'picture' => $object->getPicture()
'picture' => $object->getPicture(),
'html_editor' => true
];

// members
Expand Down
2 changes: 1 addition & 1 deletion lib/GaletteObjectsLend/Entity/LendObject.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class LendObject
private array $fields = [
'object_id' => 'integer',
'name' => 'varchar(100)',
'description' => 'varchar(500)',
'description' => 'text',
'serial_number' => 'varchar(30)',
'price' => 'decimal',
'rent_price' => 'decimal',
Expand Down
33 changes: 32 additions & 1 deletion lib/GaletteObjectsLend/IO/PdfObject.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@
*/
class PdfObject extends Pdf
{
/** @var array<string> Tags kept in HTML values */
private const array HTML_TAGS = [
'a', 'b', 'blockquote', 'br', 'em', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'i',
'li', 'ol', 'p', 's', 'span', 'strong', 'sub', 'sup', 'u', 'ul'
];

private Db $zdb;
private LendPreferences $lprefs;

Expand Down Expand Up @@ -121,7 +127,7 @@ public function drawCard(LendObject $object): void

$this->addCell(_T("Name", "objectslend"), $object->getName(), $wpic);
if ($this->lprefs->isEnabled(LendPreferences::VIEW_DESCRIPTION)) {
$this->addCell(_T("Description", "objectslend"), $object->getDescription(), $wpic);
$this->addHtmlCell(_T("Description", "objectslend"), $object->getDescriptionHtml(), $wpic);
}
if ($this->lprefs->isEnabled(LendPreferences::VIEW_CATEGORY)) {
$this->addCell(_T("Category", "objectslend"), $object->getCategoryName() ?? '', $wpic);
Expand Down Expand Up @@ -218,4 +224,29 @@ private function addCell(string $title, string $value, int $width): void
$this->MultiCell(0, 0, $w, 0, 'L');
}
}

/**
* Add a cell whose value is sanitized HTML
*
* Only text formatting is kept: TCPDF would load an image source from the
* server, be it an internal URL or a local file.
*
* @param string $title Cell title
* @param string $html Cell value
* @param int $width Picture width
*/
private function addHtmlCell(string $title, string $html, int $width): void
{
$html = strip_tags($html, self::HTML_TAGS);

if ($width > 0) {
$this->Cell($width, 0, '');
}
$this->SetFont(Pdf::FONT, 'B', 9);
$padding = 50;
$this->Cell($padding, 0, $this->cut($title, $padding));

$this->SetFont(Pdf::FONT, '', 9);
$this->MultiCell(0, 0, $html, 0, 'L', false, 1, null, null, true, 0, true);
}
}
15 changes: 14 additions & 1 deletion lib/GaletteObjectsLend/IO/PdfObjects.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

use Galette\Core\Db;
use Galette\IO\Pdf;
use Galette\Util\Html;
use Galette\Core\Preferences;
use Galette\Core\Login;
use GaletteObjectsLend\Entity\LendObject;
Expand Down Expand Up @@ -199,7 +200,7 @@ public function drawList(array $objects): void
$fill = !$object->inStock();
$this->Cell($w_checkbox, 0, '□', 'B', 0, 'L', $fill);
$this->Cell($w_name, 0, $this->cut($object->getName(), $w_name), 'B', 0, 'L', $fill);
$this->Cell($w_description, 0, $this->cut($object->getDescription(), $w_description), 'B', 0, 'L', $fill);
$this->Cell($w_description, 0, $this->cut($this->oneLine($object->getDescriptionHtml()), $w_description), 'B', 0, 'L', $fill);
$this->Cell($w_serial, 0, $this->cut($object->getSerialNumber(), $w_serial), 'B', 0, 'L', $fill);
$this->Cell($w_price, 0, $this->cut(number_format($object->getPrice(), 2, ',', ' '), $w_price), 'B', 0, 'R', $fill);
$this->Cell($w_price, 0, $this->cut(number_format($object->getRentPrice(), 2, ',', ' '), $w_price) . '€', 'B', 0, 'R', $fill);
Expand Down Expand Up @@ -233,4 +234,16 @@ public function drawList(array $objects): void
$this->Cell($w_price, 0, '', true);
$this->Cell(0, 0, _T("Available", "objectslend"), 0, 1);
}

/**
* HTML description as a single line of text
*
* @param string $html Description
*/
private function oneLine(string $html): string
{
//blocks are only separated by their tags, which are about to go
$html = (string)preg_replace('#<(/?(?:p|br|li|ul|ol|div|h[1-6]|tr|td)\b)#i', ' <$1', $html);
return trim((string)preg_replace('/\s+/u', ' ', Html::strip($html)));
}
}
2 changes: 1 addition & 1 deletion scripts/mysql.sql
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ DROP TABLE IF EXISTS galette_lend_objects;
CREATE TABLE galette_lend_objects (
object_id int(10) unsigned NOT NULL AUTO_INCREMENT,
name varchar(100) NOT NULL,
description varchar(500) NOT NULL,
description text NOT NULL,
serial_number varchar(30) NOT NULL,
price decimal(15,3) NOT NULL,
price_per_day tinyint(1) NOT NULL DEFAULT FALSE,
Expand Down
2 changes: 1 addition & 1 deletion scripts/pgsql.sql
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ DROP TABLE IF EXISTS galette_lend_objects CASCADE;
CREATE TABLE galette_lend_objects (
object_id integer DEFAULT nextval('galette_lend_objects_id_seq'::text) NOT NULL,
name character varying(100) NOT NULL,
description character varying(500) NOT NULL,
description text NOT NULL,
serial_number character varying(30) NOT NULL,
price numeric(15,3) NOT NULL,
price_per_day boolean NOT NULL DEFAULT FALSE,
Expand Down
2 changes: 1 addition & 1 deletion scripts/upgrade-to-1.1-mysql.sql
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ FROM galette_lend_rents;
CREATE TABLE galette_lend_objects_new (
object_id int(10) unsigned NOT NULL AUTO_INCREMENT,
name varchar(100) NOT NULL,
description varchar(500) NOT NULL,
description text NOT NULL,
serial_number varchar(30) NOT NULL,
price decimal(15,3) NOT NULL,
price_per_day tinyint(1) NOT NULL DEFAULT FALSE,
Expand Down
3 changes: 3 additions & 0 deletions scripts/upgrade-to-1.1-pgsql.sql
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ ALTER TABLE galette_lend_objects
ALTER COLUMN weight TYPE numeric(15,3) USING ROUND(CAST(weight AS numeric), 3),
ALTER COLUMN rent_price TYPE numeric(15,3) USING ROUND(CAST(rent_price AS numeric), 3);

-- Description is edited with the HTML editor, its markup does not fit in 500 characters
ALTER TABLE galette_lend_objects ALTER COLUMN description TYPE text;

-- A rent always has an object and a status
UPDATE galette_lend_objects SET rent_id = NULL WHERE rent_id IN (
SELECT rent_id FROM galette_lend_rents WHERE object_id IS NULL OR status_id IS NULL
Expand Down
73 changes: 18 additions & 55 deletions templates/default/categories_list.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,22 @@

{% extends 'elements/list.html.twig' %}
{% import "macros.twig" as macros %}
{% import "@PluginGaletteObjectslend/macros.twig" as lend %}

{% set nb = nb_categories %}

{% set columns = [
{
'label': '#',
'collapse': true
},
{'label': _T("Name", "objectslend"), order: constant('GaletteObjectsLend\\Repository\\Categories::ORDERBY_NAME')},
{
'label': _T("Active", "objectslend"), order: constant('GaletteObjectsLend\\Repository\\Categories::ORDERBY_ACTIVITY'),
'collapse': true
},
] %}

{% set form = {
'order': {
'name': 'objectslend_categories'
Expand All @@ -32,62 +45,13 @@
</a>
{% endblock %}

{% block header %}
{% set columns = [
{
'label': '#',
'collapse': true
},
{'label': _T("Name", "objectslend"), order: constant('GaletteObjectsLend\\Repository\\Categories::ORDERBY_NAME')},
{
'label': _T("Active", "objectslend"), order: constant('GaletteObjectsLend\\Repository\\Categories::ORDERBY_ACTIVITY'),
'collapse': true
},
] %}
{{ parent() }}
{% endblock %}

{% block search %}
<form action="{{ url_for("objectslend_filter_categories") }}" method="post" id="filtre" class="ui form filters">
<div class="ui secondary yellow segment">
<div class="field">
<label for="filter_str">{{ _T("Search:") }}</label>
<input type="text" name="filter_str" id="filter_str" value="{{ filters.filter_str }}" type="search" placeholder="{{ _T("Enter a value") }}"/>
</div>
{{ lend.searchField(filters.filter_str) }}
<div class="two fields last-child">
<div class="field">
<div class="inline fields">
<label for="filter_dc_active">{{ _T("Active:", "objectslend") }}</label>
<div class="field inline">
<div class="ui radio checkbox">
<input type="radio" name="active_filter" id="filter_dc_active" value="{{ constant('GaletteObjectsLend\\Repository\\Categories::ALL_CATEGORIES') }}"{% if filters.active_filter == constant('GaletteObjectsLend\\Repository\\Categories::ALL_CATEGORIES') %} checked="checked"{% endif %}>
<label for="filter_dc_active">{{ _T("Don't care") }}</label>
</div>
</div>
<div class="field inline">
<div class="ui radio checkbox">
<input type="radio" name="active_filter" id="filter_yes_active" value="{{ constant('GaletteObjectsLend\\Repository\\Categories::ACTIVE_CATEGORIES') }}"{% if filters.active_filter == constant('GaletteObjectsLend\\Repository\\Categories::ACTIVE_CATEGORIES') %} checked="checked"{% endif %}>
<label for="filter_yes_active">{{ _T("Yes") }}</label>
</div>
</div>
<div class="field inline">
<div class="ui radio checkbox">
<input type="radio" name="active_filter" id="filter_no_active" value="{{ constant('GaletteObjectsLend\\Repository\\Categories::INACTIVE_CATEGORIES') }}"{% if filters.active_filter == constant('GaletteObjectsLend\\Repository\\Categories::INACTIVE_CATEGORIES') %} checked="checked"{% endif %}>
<label for="filter_no_active">{{ _T("No") }}</label>
</div>
</div>
</div>
</div>
<div class="ui right aligned basic fitted segment field">
<button type="submit" class="tooltip action ui labeled icon primary button" title="{{ _T('Apply filters') }}" name="filter">
<i class="search icon" aria-hidden="true"></i>
{{ _T('Filter') }}
</button>
<button type="submit" name="clear_filter" class="ui labeled icon button tooltip" title="{{ _T('Reset all filters to defaults') }}">
<i class="trash alt red icon" aria-hidden="true"></i>
{{ _T('Clear filter') }}
</button>
</div>
{{ lend.triStateFilter('active_filter', 'active', _T("Active:", "objectslend"), filters.active_filter, {dc: constant('GaletteObjectsLend\\Repository\\Categories::ALL_CATEGORIES'), yes: constant('GaletteObjectsLend\\Repository\\Categories::ACTIVE_CATEGORIES'), no: constant('GaletteObjectsLend\\Repository\\Categories::INACTIVE_CATEGORIES')}) }}
{{ lend.filterButtons() }}
</div>
</div>
</form>
Expand All @@ -110,7 +74,7 @@
{{ categ.getName(false) }}
</td>
<td class="center collapsing" data-col-label="{{ _T("Active", "objectslend") }}">
<i class="{% if categ.isActive() %}check circle green{% else %}times circle red{% endif %} icon tooltip" data-html="{% if categ.isActive() %}{{ _T("Active", "objectslend") }}{% else %}{{ _T("Inactive", "objectslend") }}{% endif %}"></i>
<i class="{% if categ.isActive() %}check circle green{% else %}times circle red{% endif %} icon tooltip" data-html="{% if categ.isActive() %}{{ _T("Active", "objectslend") }}{% else %}{{ _T("Inactive", "objectslend") }}{% endif %}" aria-hidden="true"></i>
<span class="visually-hidden">{% if categ.isActive() %}{{ _T("Active", "objectslend") }}{% else %}{{ _T("Inactive", "objectslend") }}{% endif %}</span>
</td>
{% if login.isAdmin() or login.isStaff() %}
Expand Down Expand Up @@ -148,8 +112,7 @@
</tr>
{% else %}
<tr>
<td colspan="4">{{ _T("No category", "objectslend") }}</td>
<td colspan="{{ columns_count }}" class="emptylist">{{ _T("No category", "objectslend") }}</td>
</tr>
{% endfor %}
</table>
{% endblock %}
14 changes: 5 additions & 9 deletions templates/default/category_edit.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@
#}

{% extends "page.html.twig" %}
{% import "@PluginGaletteObjectslend/macros.twig" as lend %}

{% block content %}
<form action="{% if category.getId() %}{{ url_for("objectslend_category_action_edit", {"id": category.getId()}) }}{% else %}{{ url_for("objectslend_category_action_add") }}{% endif %}" method="post" enctype="multipart/form-data" class="ui form">
<div class="ui styled fluid accordion field">
<div class="active title">
<i class="icon dropdown"></i>
<div class="active title" role="heading" aria-level="2">
<i class="icon dropdown" aria-hidden="true"></i>
{{ _T("Category", "objectslend") }}
</div>
<div class="active content">
Expand All @@ -35,12 +36,7 @@
max_size: olendsprefs.getUploadSize(),
input_id: "picture_file"
} %}
<img
src="{% if category.getId() %}{{ url_for("objectslend_photo", {"type": "category", "mode": "thumbnail", "id": category.getId()}) }}{% else %}{{ url_for("objectslend_photo", {"type": "category", "mode": "thumbnail"}) }}{% endif %}"
class="picture"
width="{{ picture.getOptimalThumbWidth(olendsprefs) }}"
height="{{ picture.getOptimalThumbHeight(olendsprefs) }}"
alt="{{ _T("Category photo", "objectslend") }}"/>
{{ lend.thumbnail("category", category.getId(), picture, olendsprefs, _T("Category photo", "objectslend")) }}
<br/>
{% if picture.hasPicture() %}
{% include "components/forms/checkbox.html.twig" with {
Expand All @@ -57,7 +53,7 @@

<div class="ui basic center aligned fitted segment">
<button type="submit" name="valid" class="action ui labeled icon primary button">
<i class="save icon"></i> {{ _T("Save") }}
<i class="save icon" aria-hidden="true"></i> {{ _T("Save") }}
</button>
<input type="hidden" name="category_id" id="id" value="{{ category.getId() }}"/>
</div>
Expand Down
32 changes: 0 additions & 32 deletions templates/default/headers.html.twig

This file was deleted.

9 changes: 8 additions & 1 deletion templates/default/history_modal.js.twig
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,14 @@
} %}
},
error: function(){
alert("{{ _T("An error occurred loading history display :(", "objectslend")|e("js") }}")
{% include "elements/js/modal.js.twig" with {
modal_title_twig: _T("An error occurred loading history display :(", "objectslend")|e("js"),
modal_without_content: true,
modal_class: "mini",
modal_deny_only: true,
modal_cancel_text: _T("Close")|e("js"),
modal_classname: "redalert",
} %}
}
});
});
Expand Down
Loading
Loading