PDF-Editor: use panel-head as topbar for common commands/tools and preview/save (#4977)

This commit is contained in:
Richard Schreiber
2025-06-30 11:19:39 +02:00
committed by GitHub
parent f66a41f6a7
commit a4c74f6310
3 changed files with 196 additions and 150 deletions

View File

@@ -1,5 +1,6 @@
{% extends "pretixcontrol/event/base.html" %}
{% load i18n %}
{% load icon %}
{% load static %}
{% load compress %}
{% block title %}{% trans "PDF Editor" %}{% endblock %}
@@ -25,27 +26,102 @@
<div class="col-md-9">
<div class="panel panel-default panel-pdf-editor">
<div class="panel-heading">
<div class="pull-right flip">
<form method="post" action="" id="preview-form" target="_blank" class="pull-right flip">
{% csrf_token %}
<input type="hidden" value="" name="data">
<input type="hidden" value="" name="background">
<input type="hidden" value="true" name="preview">
<div class="btn-group">
<button type="button" class="btn btn-default btn-xs" id="toolbox-source"
<button type="button" class="btn btn-default" id="toolbox-source"
title="{% trans "Code" %}">
<span class="fa fa-code"></span>
{% icon "code" %}
</button>
<button type="button" class="btn btn-default btn-xs" id="toolbox-paste"
title="{% trans "Paste" %}">
<span class="fa fa-paste"></span>
</button>
<button type="button" class="btn btn-default btn-xs" id="toolbox-undo"
title="{% trans "Undo" %}">
<span class="fa fa-undo"></span>
</button>
<button type="button" class="btn btn-default btn-xs" id="toolbox-redo"
title="{% trans "Redo" %}">
<span class="fa fa-repeat"></span>
<button type="submit" class="btn btn-default" id="editor-preview">
{% icon "eye" %}
{% trans "Preview" %}
</button>
</div>
<button type="submit" class="btn btn-primary btn-save" id="editor-save">
{% icon "save" %}
{% trans "Save" %}
</button>
</form>
<div class="btn-group add-buttons">
<button class="btn btn-default" id="editor-add-textcontainer" disabled>
{% icon "font" %}
{% trans "Text box" %}
</button>
<div class="btn-group dropdown">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">
<span class="caret"></span>
{% icon "qrcode" %}
{% trans "QR Code" %}
</button>
<ul class="dropdown-menu">
<li>
<button class="btn" id="editor-add-qrcode" data-content="secret" disabled>
{% trans "QR code for Check-In" %}
</button>
</li>
<li>
<button class="btn" id="editor-add-qrcode-lead"
data-content="pseudonymization_id"
disabled>
{% trans "QR code for Lead Scanning" %}
</button>
</li>
<li>
<button class="btn" id="editor-add-qrcode-other"
data-content="other"
disabled>
{% trans "Other QR code" %}
</button>
</li>
</div>
<div class="btn-group dropdown">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">
<span class="caret"></span>
{% icon "image" %}
{% trans "Image" %}
</button>
<ul class="dropdown-menu">
<li>
<button class="btn" id="editor-add-image" disabled
data-toggle="tooltip" title="{% trans "You can use this to add user-uploaded pictures from questions or pictures generated by plugins. If you want to embed a logo or other images, use a custom background instead." %}">
{% trans "Dynamic image" %}
</button>
</li>
<li>
<button class="btn" id="editor-add-poweredby"
data-content="dark"
disabled>
{% trans "pretix Logo" %}
</button>
</li>
</div>
</div>
<div class="btn-group object-buttons">
<button type="button" class="btn btn-default" id="toolbox-duplicate"
title="{% trans "Duplicate" %}">
{% icon "copy" %}
</button>
<button type="button" class="btn btn-default" id="toolbox-delete"
title="{% trans "Delete" %}">
{% icon "trash" class="text-danger" %}
</button>
</div>
<div class="btn-group">
<button type="button" class="btn btn-default" id="toolbox-undo"
title="{% trans "Undo" %}">
{% icon "undo" %}
</button>
<button type="button" class="btn btn-default" id="toolbox-redo"
title="{% trans "Redo" %}">
{% icon "repeat" %}
</button>
</div>
{% trans "Editor" %}
</div>
<div class="panel-body">
<ul class="nav nav-pills" id="page_nav">
@@ -153,22 +229,6 @@
<div class="col-md-3" id="editor-toolbox-area">
<div class="panel panel-default" id="toolbox">
<div class="panel-heading">
<div class="pull-right object-buttons flip">
<div class="btn-group">
<button type="button" class="btn btn-default btn-xs" id="toolbox-cut"
title="{% trans "Cut" %}">
<span class="fa fa-cut"></span>
</button>
<button type="button" class="btn btn-default btn-xs" id="toolbox-copy"
title="{% trans "Copy" %}">
<span class="fa fa-copy"></span>
</button>
<button type="button" class="btn btn-danger btn-xs" id="toolbox-delete"
title="{% trans "Delete" %}">
<span class="fa fa-trash"></span>
</button>
</div>
</div>
<span id="toolbox-heading">
{% trans "Loading…" %}
</span>
@@ -488,63 +548,6 @@
</div>
</div>
</div>
<div class="editor-toolbox-text panel panel-default">
<div class="panel-heading">
{% trans "Add a new object" %}
</div>
<div class="panel-body add-buttons">
<button class="btn btn-default btn-block" id="editor-add-textcontainer" disabled>
<span class="fa fa-font"></span>
{% trans "Text box" %}
</button>
<button class="btn btn-default btn-block" id="editor-add-text" disabled>
<span class="fa fa-font"></span>
{% trans "Text (deprecated)" %}
</button>
<button class="btn btn-default btn-block" id="editor-add-qrcode" data-content="secret" disabled>
<span class="fa fa-qrcode"></span>
{% trans "QR code for Check-In" %}
</button>
<button class="btn btn-default btn-block" id="editor-add-qrcode-lead"
data-content="pseudonymization_id"
disabled>
<span class="fa fa-qrcode"></span>
{% trans "QR code for Lead Scanning" %}
</button>
<button class="btn btn-default btn-block" id="editor-add-qrcode-other"
data-content="secret"
disabled>
<span class="fa fa-qrcode"></span>
{% trans "Other QR code" %}
</button>
<button class="btn btn-default btn-block" id="editor-add-poweredby"
data-content="dark"
disabled>
<span class="fa fa-image"></span>
{% trans "pretix Logo" %}
</button>
<button class="btn btn-default btn-block" id="editor-add-image" disabled
data-toggle="tooltip" title="{% trans "You can use this to add user-uploaded pictures from questions or pictures generated by plugins. If you want to embed a logo or other images, use a custom background instead." %}">
<span class="fa fa-image"></span>
{% trans "Dynamic image" %}
</button>
</div>
</div>
<form method="post" action="" id="preview-form" target="_blank">
<div class="form-group submit-group">
{% csrf_token %}
<input type="hidden" value="" name="data">
<input type="hidden" value="" name="background">
<input type="hidden" value="true" name="preview">
<button type="submit" class="btn btn-default btn-lg" id="editor-preview">
{% trans "Preview" %}
</button>
<button type="submit" class="btn btn-primary btn-save" id="editor-save">
<span class="fa fa-fw fa-save"></span>
{% trans "Save" %}
</button>
</div>
</form>
<p>&nbsp;</p>
<div class="alert alert-info" id="version-notice">
{% blocktrans trimmed with print_version="2.18" scan_version="1.22" %}

View File

@@ -898,6 +898,7 @@ var editor = {
_update_toolbox: function () {
var selected = editor.fabric.getActiveObjects();
$(".object-buttons button").prop("disabled", selected.length == 0);
if (selected.length > 1) {
$("#toolbox").attr("data-type", "group");
$("#toolbox-heading").text(gettext("Group of objects"));
@@ -1048,8 +1049,11 @@ var editor = {
},
_cut: function () {
editor._history_modification_in_progress = true;
var thing = editor.fabric.getActiveObject();
if (!thing) {
return false;
}
editor._history_modification_in_progress = true;
if (thing.type === "activeSelection") {
editor.clipboard = editor.dump(thing._objects);
thing.forEachObject(function (o) {
@@ -1066,15 +1070,16 @@ var editor = {
},
_copy: function () {
editor._history_modification_in_progress = true;
var thing = editor.fabric.getActiveObject();
if (!thing) {
return false;
}
if (thing.type === "activeSelection") {
editor.clipboard = editor.dump(thing._objects);
} else {
editor.clipboard = editor.dump([thing]);
}
editor._history_modification_in_progress = false;
editor._create_savepoint();
return true;
},
_paste: function () {
@@ -1098,8 +1103,19 @@ var editor = {
editor._create_savepoint();
},
_duplicate: function () {
var prevClipboad = editor.clipboard;
if (editor._copy()) {
editor._paste();
editor.clipboard = prevClipboad;
}
},
_delete: function () {
var thing = editor.fabric.getActiveObject();
if (!thing) {
return false;
}
if (thing.type === "activeSelection") {
thing.forEachObject(function (o) {
editor.fabric.remove(o);
@@ -1119,64 +1135,79 @@ var editor = {
if ($("#source-container").is(':visible')) {
return true;
}
switch (e.keyCode) {
case 38: /* Up arrow */
thing.set('top', thing.get('top') - step);
thing.setCoords();
editor._create_savepoint();
break;
case 40: /* Down arrow */
thing.set('top', thing.get('top') + step);
thing.setCoords();
editor._create_savepoint();
break;
case 37: /* Left arrow */
thing.set('left', thing.get('left') - step);
thing.setCoords();
editor._create_savepoint();
break;
case 39: /* Right arrow */
thing.set('left', thing.get('left') + step);
thing.setCoords();
editor._create_savepoint();
break;
case 8: /* Backspace */
case 46: /* Delete */
editor._delete();
break;
case 65: /* A */
if (e.ctrlKey || e.metaKey) {
if (e.ctrlKey || e.metaKey) {
switch (e.key) {
case "a":
editor._selectAll();
}
break;
case 89: /* Y */
if (e.ctrlKey || e.metaKey) {
break;
case "y":
editor._redo();
}
break;
case 90: /* Z */
if (e.ctrlKey || e.metaKey) {
break;
case "z":
editor._undo();
}
break;
case 88: /* X */
if (e.ctrlKey || e.metaKey) {
break;
case "x":
editor._cut();
}
break;
case 86: /* V */
if (e.ctrlKey || e.metaKey) {
break;
case "v":
editor._paste();
}
break;
case 67: /* C */
if (e.ctrlKey || e.metaKey) {
break;
case "c":
editor._copy();
}
break;
default:
return;
break;
case "d":
editor._duplicate();
break;
default:
return;
}
} else {
switch (e.key) {
case "ArrowUp":
thing.set('top', thing.get('top') - step);
thing.setCoords();
editor._create_savepoint();
break;
case "ArrowDown":
thing.set('top', thing.get('top') + step);
thing.setCoords();
editor._create_savepoint();
break;
case "ArrowLeft":
thing.set('left', thing.get('left') - step);
thing.setCoords();
editor._create_savepoint();
break;
case "ArrowRight":
thing.set('left', thing.get('left') + step);
thing.setCoords();
editor._create_savepoint();
break;
case "Backspace":
case "Del":
case "Delete":
editor._delete();
break;
case "Cut":
editor._cut();
break;
case "Copy":
editor._copy();
break;
case "Paste":
editor._paste();
break;
case "Redo":
editor._redo();
break;
case "Undo":
editor._undo();
break;
default:
return;
}
}
e.preventDefault();
editor.fabric.renderAll();
editor._update_toolbox_values();
@@ -1234,6 +1265,9 @@ var editor = {
} else {
$("#editor-save").addClass("btn-success").removeClass("btn-primary").find(".fa").attr("class", "fa fa-fw fa-check");
}
$("#toolbox-undo").prop("disabled", editor._history_pos == editor.history.length-1);
$("#toolbox-redo").prop("disabled", editor._history_pos == 0);
},
_save: function () {
@@ -1417,10 +1451,8 @@ var editor = {
editor._create_savepoint();
});
$("#toolbox .colorpickerfield").bind('changeColor', editor._update_values_from_toolbox);
$("#toolbox-copy").bind('click', editor._copy);
$("#toolbox-cut").bind('click', editor._cut);
$("#toolbox-duplicate").bind('click', editor._duplicate);
$("#toolbox-delete").bind('click', editor._delete);
$("#toolbox-paste").bind('click', editor._paste);
$("#toolbox-undo").bind('click', editor._undo);
$("#toolbox-redo").bind('click', editor._redo);
$("#toolbox-source").bind('click', editor._source_show);

View File

@@ -21,8 +21,7 @@ body {
#toolbox .text,
#toolbox .textarea,
#toolbox .textcontainer,
#toolbox .imagecontent,
#toolbox .object-buttons {
#toolbox .imagecontent {
display: none;
}
#toolbox[data-type] .position,
@@ -37,8 +36,7 @@ body {
#toolbox[data-type=textcontainer] .textcontainer,
#toolbox[data-type=textcontainer] .rectsize,
#toolbox[data-type=textarea] .text,
#toolbox[data-type=textarea] .textarea,
#toolbox[data-type] .object-buttons {
#toolbox[data-type=textarea] .textarea {
display: block;
}
#toolbox[data-type=text] .btn-group-justified > .btn-group.text,
@@ -92,3 +90,16 @@ body {
padding: 15px;
background: #eee;
}
.panel-pdf-editor .panel-heading {
padding: 4px;
position: sticky;
top: 0;
z-index: 1;
}
.panel-pdf-editor .panel-heading [disabled] {
box-shadow: 0px 0px 0px 1px #cccccc inset;
}
.panel-pdf-editor .panel-heading > .btn-group,
.panel-pdf-editor .panel-heading form > .btn-group {
margin-right: 1em;
}