175 lines
5.7 KiB
JavaScript
175 lines
5.7 KiB
JavaScript
/** @odoo-module */
|
|
|
|
import { _t } from "@web/core/l10n/translation";
|
|
import { useService } from "@web/core/utils/hooks";
|
|
|
|
import { ConfirmationDialog } from "@web/core/confirmation_dialog/confirmation_dialog";
|
|
|
|
import { stores } from "@odoo/o-spreadsheet";
|
|
import { useEffect, useExternalListener, useState } from "@odoo/owl";
|
|
|
|
import { loadBundle } from "@web/core/assets";
|
|
|
|
const { useStore, useStoreProvider, NotificationStore } = stores;
|
|
/**
|
|
* Hook that will capture the 'Ctrl+p' press that corresponds to the user intent to print a spreadsheet.
|
|
* It will prepare the spreadsheet for printing by:
|
|
* - displaying it in dashboard mode.
|
|
* - altering the spreadsheet dimensions to ensure we render the whole sheet.
|
|
* The hook will also restore the spreadsheet dimensions to their original state after the print.
|
|
*
|
|
* The hook will return the print preparation function to be called manually in other contexts than pressing
|
|
* the common keybind (through a menu for instance).
|
|
*
|
|
* @param {() => Model | undefined} model
|
|
* @returns {() => Promise<void>} preparePrint
|
|
*/
|
|
export function useSpreadsheetPrint(model) {
|
|
let frozenPrintState = undefined;
|
|
const printState = useState({ active: false });
|
|
|
|
useExternalListener(
|
|
window,
|
|
"keydown",
|
|
async (ev) => {
|
|
const isMeta = ev.metaKey || ev.ctrlKey;
|
|
if (ev.key === "p" && isMeta) {
|
|
if (!model()) {
|
|
return;
|
|
}
|
|
ev.preventDefault();
|
|
ev.stopImmediatePropagation();
|
|
await preparePrint();
|
|
}
|
|
},
|
|
{ capture: true }
|
|
);
|
|
useExternalListener(window, "afterprint", afterPrint);
|
|
|
|
useEffect(
|
|
() => {
|
|
if (printState.active) {
|
|
window.print();
|
|
}
|
|
},
|
|
() => [printState.active]
|
|
);
|
|
|
|
/**
|
|
* Returns the DOM position & dimensions such that the whole spreadsheet content is visible.
|
|
* @returns {Rect}
|
|
*/
|
|
function getPrintRect() {
|
|
const sheetId = model().getters.getActiveSheetId();
|
|
const { bottom, right } = model().getters.getSheetZone(sheetId);
|
|
const { end: width } = model().getters.getColDimensions(sheetId, right);
|
|
const { end: height } = model().getters.getRowDimensions(sheetId, bottom);
|
|
return { x: 0, y: 0, width, height };
|
|
}
|
|
|
|
/**
|
|
* Will alter the spreadsheet dimensions to ensure we render the whole sheet.
|
|
* invoking this function will ultimately trigger a print of the page after a patch.
|
|
*/
|
|
async function preparePrint() {
|
|
if (!model()) {
|
|
return;
|
|
}
|
|
await loadBundle("spreadsheet.assets_print");
|
|
const { width, height } = model().getters.getSheetViewDimension();
|
|
const { width: widthAndHeader, height: heightAndHeader } =
|
|
model().getters.getSheetViewDimension();
|
|
const viewRect = {
|
|
x: widthAndHeader - width,
|
|
y: heightAndHeader - height,
|
|
width,
|
|
height,
|
|
};
|
|
frozenPrintState = {
|
|
viewRect,
|
|
offset: model().getters.getActiveSheetDOMScrollInfo(),
|
|
mode: model().config.mode,
|
|
};
|
|
model().updateMode("dashboard");
|
|
// reset the viewport to A1 visibility
|
|
model().dispatch("SET_VIEWPORT_OFFSET", { offsetX: 0, offsetY: 0 });
|
|
model().dispatch("RESIZE_SHEETVIEW", {
|
|
...getPrintRect(),
|
|
});
|
|
printState.active = true;
|
|
}
|
|
|
|
function afterPrint() {
|
|
if (!model()) {
|
|
return;
|
|
}
|
|
if (frozenPrintState) {
|
|
model().dispatch("RESIZE_SHEETVIEW", frozenPrintState.viewRect);
|
|
const { scrollX: offsetX, scrollY: offsetY } = frozenPrintState.offset;
|
|
model().dispatch("SET_VIEWPORT_OFFSET", { offsetX, offsetY });
|
|
model().updateMode(frozenPrintState.mode);
|
|
frozenPrintState = undefined;
|
|
}
|
|
printState.active = false;
|
|
}
|
|
|
|
return preparePrint;
|
|
}
|
|
|
|
export function useSpreadsheetNotificationStore() {
|
|
/**
|
|
* Open a dialog to ask a confirmation to the user.
|
|
*
|
|
* @param {string} body body content to display
|
|
* @param {Function} confirm Callback if the user press 'Confirm'
|
|
*/
|
|
function askConfirmation(body, confirm) {
|
|
dialog.add(ConfirmationDialog, {
|
|
title: _t("Odoo Spreadsheet"),
|
|
body,
|
|
confirm,
|
|
cancel: () => {}, // Must be defined to display the Cancel button
|
|
confirmLabel: _t("Confirm"),
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Adds a notification to display to the user
|
|
* @param {{text: string, type: string, sticky: boolean }} notification
|
|
*/
|
|
function notifyUser(notification) {
|
|
notifications.add(notification.text, {
|
|
type: notification.type,
|
|
sticky: notification.sticky,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Open a dialog to display an error message to the user.
|
|
*
|
|
* @param {string} body Content to display
|
|
* @param {function} callBack Callback function to be executed when the dialog is closed
|
|
*/
|
|
function raiseError(body, callBack) {
|
|
dialog.add(
|
|
ConfirmationDialog,
|
|
{
|
|
title: _t("Odoo Spreadsheet"),
|
|
body,
|
|
},
|
|
{
|
|
onClose: callBack,
|
|
}
|
|
);
|
|
}
|
|
const dialog = useService("dialog");
|
|
const notifications = useService("notification");
|
|
useStoreProvider();
|
|
const notificationStore = useStore(NotificationStore);
|
|
notificationStore.updateNotificationCallbacks({
|
|
notifyUser: notifyUser,
|
|
raiseError: raiseError,
|
|
askConfirmation: askConfirmation,
|
|
});
|
|
}
|