Skip to content

Commit

Permalink
Merge pull request #205 from vsimakhin/feature/custom-pdf-title-page
Browse files Browse the repository at this point in the history
custom title page for pdf export
  • Loading branch information
vsimakhin authored Mar 23, 2024
2 parents 8483ea5 + cde335b commit 66ff740
Show file tree
Hide file tree
Showing 13 changed files with 305 additions and 68 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
logbook.pdf
*.pdf
map.png
.logbook.json

Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## [Unreleased]

- New: Add support for a custom title page for PDF A4/A5 exports.
- Update: Update openlayers lib from 7.3.0 to 9.0.0. No UI changes.
- Update: Update golang from 1.20.3 to 1.21.8. No UI changes.
- Fix: Finally fixed the unit tests. No UI changes.
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ You also can easily export all flight records into EASA style pdf format, print

## [Unreleased]

- New: Add support for a custom title page for PDF A4/A5 exports.
- Update: Update openlayers lib from 7.3.0 to 9.0.0. No UI changes.
- Update: Update golang from 1.20.3 to 1.21.8. No UI changes.
- Fix: Finally fixed the unit tests. No UI changes.
Expand Down
8 changes: 7 additions & 1 deletion cmd/web/handlers_export.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,20 @@ func (app *application) HandlerExportLogbook(w http.ResponseWriter, r *http.Requ
Signature: settings.SignatureText,
SignatureImage: settings.SignatureImage,
}
var customTitleUUID string

if format == exportA4 {
logbook.Export = settings.ExportA4
customTitleUUID = settings.ExportA4.CustomTitle

} else if format == exportA5 {
logbook.Export = settings.ExportA5
customTitleUUID = settings.ExportA5.CustomTitle
}

att, _ := app.db.GetAttachmentByID(customTitleUUID)
logbook.Export.CustomTitleBlob = att.Document

err = logbook.ExportPDF(format, flightRecords, w)

} else if format == exportCSV {
Expand All @@ -89,7 +96,6 @@ func (app *application) HandlerExportLogbook(w http.ResponseWriter, r *http.Requ

} else {
err = errors.New("unknown export format")

}

if err != nil {
Expand Down
41 changes: 39 additions & 2 deletions cmd/web/templates/export-a4.partials.gohtml
Original file line number Diff line number Diff line change
Expand Up @@ -375,8 +375,10 @@
</div>
<div class="col-md-6">
<div class="row mb-2">
<div class="col">
<label for="time_field_format_a4" class="col-sm-8 col-form-label">Time fields autoformat</label>
<div class="col-sm-8">
<label for="time_field_format_a4" class="col-form-label">Time fields autoformat</label>
</div>
<div class="col-sm-4 text-end">
<div class="btn-group" role="group" id="time_field_format_a4" name="time_field_format_a4">
<input type="radio" class="btn-check" name="time_field_format_radio_a4" id="time_field_format_radio1_a4" autocomplete="off" {{if eq $settings.ExportA4.TimeFieldsAutoFormat 0}}checked{{end}}>
<label class="btn btn-sm btn-outline-secondary" for="time_field_format_radio1_a4">None</label>
Expand All @@ -389,6 +391,14 @@
</div>
</div>
</div>
<div class="row mb-2">
<div class="col-sm-8">
<label for="custom_title_a4" class="col-sm-5 col-form-label">Custom A4 title page</label>
</div>
<div class="col-sm-4 text-end">
<button type="button" class="btn btn-sm btn-secondary" onclick="wlbExport.showCustomTitleModal('A4');"><i class="bi bi-file-pdf"></i> Manage...</button>
</div>
</div>
</div>
</div>

Expand All @@ -397,4 +407,31 @@
<button class="btn btn-sm btn-outline-secondary" type="button" onclick="wlbExport.saveExportA4()" id="save_a4"><i class="bi bi-save-fill"></i> Save</button>
<button class="btn btn-sm btn-outline-secondary" type="button" onclick="wlbCommon.runExport('{{$api.ExportFormatA4}}')" id="export_a4"><i class="bi bi-file-pdf-fill"></i> Export PDF A4</button>


<!-- Modal -->
<div class="modal fade" id="custom_title_a4_modal" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="custom_title_a4_modal" aria-hidden="true">
<div class="modal-dialog modal-xl">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="custom_title_a4_modal">Custom title page</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="col">
<div class="input-group">
<input type="file" accept=".pdf" class="form-control form-control-sm" id="custom_title_a4" name="custom_title_a4" />

<button type="button" class="btn btn-sm btn-secondary" onclick="wlbExport.deleteCustomTitle('A4');"><i class="bi bi-file-x"></i> Delete</button>
</div>
</div>
<br>
<div id="custom_title_a4_document"></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-sm btn-outline-secondary" data-bs-dismiss="modal" onclick="wlbExport.saveExportA4()"><i class="bi bi-save-fill"></i> Save</button>
<button type="button" class="btn btn-sm btn-outline-secondary" data-bs-dismiss="modal"><i class="bi bi-arrow-counterclockwise"></i> OK</button>
</div>
</div>
</div>
</div>
{{end}}
40 changes: 38 additions & 2 deletions cmd/web/templates/export-a5.partials.gohtml
Original file line number Diff line number Diff line change
Expand Up @@ -383,8 +383,10 @@
</div>
<div class="col-md-6">
<div class="row mb-2">
<div class="col">
<label for="time_field_format_a5" class="col-sm-8 col-form-label">Time fields autoformat</label>
<div class="col-sm-8">
<label for="time_field_format_a5" class="col-form-label">Time fields autoformat</label>
</div>
<div class="col-sm-4 text-end">
<div class="btn-group" role="group" id="time_field_format_a5" name="time_field_format_a5">
<input type="radio" class="btn-check" name="time_field_format_radio_a5" id="time_field_format_radio1_a5" autocomplete="off" {{if eq $settings.ExportA5.TimeFieldsAutoFormat 0}}checked{{end}}>
<label class="btn btn-sm btn-outline-secondary" for="time_field_format_radio1_a5">None</label>
Expand All @@ -397,6 +399,14 @@
</div>
</div>
</div>
<div class="row mb-2">
<div class="col-sm-8">
<label for="custom_title_a5" class="col-sm-5 col-form-label">Custom A5 title page</label>
</div>
<div class="col-sm-4 text-end">
<button type="button" class="btn btn-sm btn-secondary" onclick="wlbExport.showCustomTitleModal('A5');"><i class="bi bi-file-pdf"></i> Manage...</button>
</div>
</div>
</div>
</div>

Expand All @@ -405,4 +415,30 @@
<button class="btn btn-sm btn-outline-secondary" type="button" onclick="wlbExport.saveExportA5()" id="save_a5"><i class="bi bi-save-fill"></i> Save</button>
<button class="btn btn-sm btn-outline-secondary" type="button" onclick="wlbCommon.runExport('{{$api.ExportFormatA5}}')" id="export_a5"><i class="bi bi-file-pdf-fill"></i> Export PDF A5</button>

<!-- Modal -->
<div class="modal fade" id="custom_title_a5_modal" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="custom_title_a5_modal" aria-hidden="true">
<div class="modal-dialog modal-xl">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="custom_title_a5_modal">Custom title page</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="col">
<div class="input-group">
<input type="file" accept=".pdf" class="form-control form-control-sm" id="custom_title_a5" name="custom_title_a5" />

<button type="button" class="btn btn-sm btn-secondary" onclick="wlbExport.deleteCustomTitle('A5');"><i class="bi bi-file-x"></i> Delete</button>
</div>
</div>
<br>
<div id="custom_title_a5_document"></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-sm btn-outline-secondary" data-bs-dismiss="modal" onclick="wlbExport.saveExportA5()"><i class="bi bi-save-fill"></i> Save</button>
<button type="button" class="btn btn-sm btn-outline-secondary" data-bs-dismiss="modal"><i class="bi bi-arrow-counterclockwise"></i> OK</button>
</div>
</div>
</div>
</div>
{{end}}
156 changes: 123 additions & 33 deletions cmd/web/templates/export-js.partials.gohtml
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,102 @@
// WebLogbook Export Namespace
wlbExport = function () {

function saveExportA4() {
const formatMap = {
"A4": "custom_title_a4",
"A5": "custom_title_a5"
};

async function getCustomTitle(format) {
const attachments_url = "{{index .API "LogbookUUIDAttachments"}}";

if (!formatMap[format]) {return;}

const url = attachments_url.replace("{uuid}", formatMap[format]);
const data = await wlbCommon.getJSON(url);
if (data.length > 0) {
return data[0].uuid;
} else {
return ""
}
}

async function deleteCustomTitle(format) {
// drop current saved file from attachments
const attachments_url = "{{index .API "LogbookUUIDAttachments"}}".replace("{uuid}", formatMap[format]);
const data = await wlbCommon.getJSON(attachments_url);

if (data.length > 0) {
for (let i = 0; i < data.length; i++) {
const payload = {uuid: data[i].uuid}
const requestOptions = {method: "post", body: JSON.stringify(payload)};
await fetch("{{index .API "LogbookAttachmentsDelete"}}", requestOptions)
}
document.getElementById(`${formatMap[format]}_document`).innerHTML = "";
}
}

async function saveCustomTitle(format) {
const custom_title_element = document.getElementById(formatMap[format]);
const file = custom_title_element.files[0];

if (file) {
await deleteCustomTitle(format);

// upload new file as attachment
let payload = new FormData();
payload.append("document", file);
payload.append("record_id", formatMap[format]);

const requestOptions = {method: "post", body: payload};
await fetch("{{index .API "LogbookAttachmentsUpload"}}", requestOptions)

// update uuid in settings
const attachments_url = "{{index .API "LogbookUUIDAttachments"}}".replace("{uuid}", formatMap[format]);
const data = await wlbCommon.getJSON(attachments_url);
if (data.length > 0) {
return data[0].uuid;
} else {
return ""
}
} else {
const uuid = await getCustomTitle(format);
return uuid;
}
}

function showCustomTitleModal(format) {
const modal = new bootstrap.Modal(document.getElementById(`${formatMap[format]}_modal`), {});

getCustomTitle(format).then(uuid => {
if (uuid !== "") {
const data = "{{$api.LogbookAttachmentsDownload}}"+uuid;
fetch(data).then(response => response.blob()).then(blob => {
const reader = new FileReader();
reader.onload = function() {
const text = `<object data="${reader.result}" width="100%" height="700px">
<p>Your browser does not support preview of the document</p>
</object>`;

document.getElementById(`${formatMap[format]}_document`).innerHTML = text;
};
reader.readAsDataURL(blob);
});
}
});

modal.show();
}

async function saveExportA4() {
let time_fields_auto_format = 0;
if (document.getElementById("time_field_format_radio2_a4").checked) {
time_fields_auto_format = 1;
} else if (document.getElementById("time_field_format_radio3_a4").checked) {
time_fields_auto_format = 2;
}

let custom_title_a4 = await saveCustomTitle("A4");

let payload = {
export_a4: {
logbook_rows: parseInt(document.getElementById("logbook_rows_a4").value),
Expand All @@ -26,6 +114,7 @@ wlbExport = function () {
include_signature: document.getElementById("include_signature_a4").checked,
is_extended: document.getElementById("is_extended_a4").checked,
time_fields_auto_format: time_fields_auto_format,
custom_title: custom_title_a4,
columns: {
col1: parseFloat(document.getElementById("col1_a4").value),
col2: parseFloat(document.getElementById("col2_a4").value),
Expand Down Expand Up @@ -88,36 +177,36 @@ wlbExport = function () {
};

const requestOptions = {
method: 'post',
method: "post",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
"Accept": "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
};

fetch("{{$api.Export}}/{{$api.ExportFormatA4}}", requestOptions)
.then(response => response.json())
.then(function(data) {
if (data.ok) {
wlbCommon.showInfoMessage(data.message);
if (typeof data.redirect_url !== 'undefined') {
location.href = data.redirect_url;
}
} else {
wlbCommon.showErrorMessage(data.message);
}
});
const response = await fetch("{{$api.Export}}/{{$api.ExportFormatA4}}", requestOptions);
const data = await response.json();
if (data.ok) {
wlbCommon.showInfoMessage(data.message);
if (typeof data.redirect_url !== "undefined") {
location.href = data.redirect_url;
}
} else {
wlbCommon.showErrorMessage(data.message);
}
}

function saveExportA5() {
async function saveExportA5() {
let time_fields_auto_format = 0;
if (document.getElementById("time_field_format_radio2_a5").checked) {
time_fields_auto_format = 1;
} else if (document.getElementById("time_field_format_radio3_a5").checked) {
time_fields_auto_format = 2;
}

let custom_title_a5 = await saveCustomTitle("A5");

let payload = {
export_a5: {
logbook_rows: parseInt(document.getElementById("logbook_rows_a5").value),
Expand All @@ -132,6 +221,7 @@ wlbExport = function () {
include_signature: document.getElementById("include_signature_a5").checked,
is_extended: document.getElementById("is_extended_a5").checked,
time_fields_auto_format: time_fields_auto_format,
custom_title: custom_title_a5,
columns: {
col1: parseFloat(document.getElementById("col1_a5").value),
col2: parseFloat(document.getElementById("col2_a5").value),
Expand Down Expand Up @@ -194,26 +284,24 @@ wlbExport = function () {
};

const requestOptions = {
method: 'post',
method: "post",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
"Accept": "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
};

fetch("{{$api.Export}}/{{$api.ExportFormatA5}}", requestOptions)
.then(response => response.json())
.then(function(data) {
if (data.ok) {
wlbCommon.showInfoMessage(data.message);
if (typeof data.redirect_url !== 'undefined') {
location.href = data.redirect_url;
}
} else {
wlbCommon.showErrorMessage(data.message);
}
});
const response = await fetch("{{$api.Export}}/{{$api.ExportFormatA5}}", requestOptions);
const data = await response.json();
if (data.ok) {
wlbCommon.showInfoMessage(data.message);
if (typeof data.redirect_url !== "undefined") {
location.href = data.redirect_url;
}
} else {
wlbCommon.showErrorMessage(data.message);
}
}

function saveExportXLS() {
Expand Down Expand Up @@ -317,7 +405,9 @@ wlbExport = function () {
saveExportCSV:saveExportCSV,
saveExportXLS:saveExportXLS,
restoreDefaults:restoreDefaults,
showTab:showTab
showTab:showTab,
deleteCustomTitle:deleteCustomTitle,
showCustomTitleModal:showCustomTitleModal
}
}();

Expand Down
Loading

0 comments on commit 66ff740

Please sign in to comment.