mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-12-23 15:18:58 +01:00
* All apps: printing of lists improved a lot, asks now how many lines to print
r51437: Work in progress of printing nextmatches, still needs some prettying up & edge case testing r51453: Bug fixes on nextmatch printing - fix loaded rows check - fix hidden etemplate check r51454: Printing CSS improvements r51588: Attempt to get nextmatch printing always on the page (landscape) r51589: Attempt to get nextmatch printing always on the page (landscape) - put things back if they cancel at nextmatch dialog r51612: disable footer for print
This commit is contained in:
parent
4249dca91d
commit
6625ffdde4
@ -144,3 +144,20 @@ var et2_IDetachedDOM = new Interface({
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for widgets that need to do something special before printing
|
||||||
|
*/
|
||||||
|
var et2_IPrint = new Interface({
|
||||||
|
/**
|
||||||
|
* Set up for printing
|
||||||
|
*
|
||||||
|
* @return {undefined|Deferred} Return a jQuery Deferred object if not done setting up
|
||||||
|
* (waiting for data)
|
||||||
|
*/
|
||||||
|
beforePrint: function() {},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset after printing
|
||||||
|
*/
|
||||||
|
afterPrint: function() {}
|
||||||
|
});
|
@ -68,7 +68,7 @@ var et2_INextmatchSortable = new Interface({
|
|||||||
*
|
*
|
||||||
* @augments et2_DOMWidget
|
* @augments et2_DOMWidget
|
||||||
*/
|
*/
|
||||||
var et2_nextmatch = et2_DOMWidget.extend([et2_IResizeable, et2_IInput],
|
var et2_nextmatch = et2_DOMWidget.extend([et2_IResizeable, et2_IInput, et2_IPrint],
|
||||||
{
|
{
|
||||||
attributes: {
|
attributes: {
|
||||||
// These normally set in settings, but broken out into attributes to allow run-time changes
|
// These normally set in settings, but broken out into attributes to allow run-time changes
|
||||||
@ -1836,6 +1836,141 @@ var et2_nextmatch = et2_DOMWidget.extend([et2_IResizeable, et2_IInput],
|
|||||||
set_value: function(_value)
|
set_value: function(_value)
|
||||||
{
|
{
|
||||||
this.value = _value;
|
this.value = _value;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Printing
|
||||||
|
/**
|
||||||
|
* Prepare for printing
|
||||||
|
*
|
||||||
|
* We check for un-loaded rows, and ask the user what they want to do about them.
|
||||||
|
* If they want to print them all, we ask the server and print when they're loaded.
|
||||||
|
*/
|
||||||
|
beforePrint: function() {
|
||||||
|
// Add the class, if needed
|
||||||
|
this.div.addClass('print');
|
||||||
|
|
||||||
|
// Trigger resize, so we can fit on a page
|
||||||
|
this.dynheight.outerNode.css('max-width',this.div.css('max-width'));
|
||||||
|
this.resize();
|
||||||
|
|
||||||
|
// Check for rows that aren't loaded yet, or lots of rows
|
||||||
|
var range = this.controller._grid.getIndexRange();
|
||||||
|
this.old_height = this.controller._grid._scrollHeight;
|
||||||
|
var loaded_count = range.bottom - range.top +1;
|
||||||
|
var total = this.controller._grid.getTotalCount();
|
||||||
|
if(loaded_count != total ||
|
||||||
|
this.controller._grid.getTotalCount() > 100)
|
||||||
|
{
|
||||||
|
// Defer the printing
|
||||||
|
var defer = jQuery.Deferred();
|
||||||
|
|
||||||
|
// Something not in the grid, lets ask
|
||||||
|
et2_dialog.show_prompt(jQuery.proxy(function(button, value) {
|
||||||
|
if(button == 'dialog[cancel]') {
|
||||||
|
// Give dialog a chance to close, or it will be in the print
|
||||||
|
window.setTimeout(function() {defer.reject();}, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
value = parseInt(value);
|
||||||
|
if(value > total)
|
||||||
|
{
|
||||||
|
value = total;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If they want the whole thing, treat it as all
|
||||||
|
if(button == 'dialog[ok]' && value == this.controller._grid.getTotalCount())
|
||||||
|
{
|
||||||
|
button = 'dialog[all]';
|
||||||
|
// Add the class, gives more reliable sizing
|
||||||
|
this.div.addClass('print');
|
||||||
|
}
|
||||||
|
// We need more rows
|
||||||
|
if(button == 'dialog[all]' || value > loaded_count)
|
||||||
|
{
|
||||||
|
var count = 0;
|
||||||
|
var fetchedCount = 0;
|
||||||
|
var cancel = false;
|
||||||
|
var nm = this;
|
||||||
|
var dialog = et2_dialog.show_dialog(
|
||||||
|
// Abort the long task if they canceled the data load
|
||||||
|
function() {count = total; cancel=true;window.setTimeout(function() {defer.reject();},0)},
|
||||||
|
egw.lang('Loading'), egw.lang('please wait...'),{},[
|
||||||
|
{"button_id": et2_dialog.CANCEL_BUTTON,"text": 'cancel',id: 'dialog[cancel]',image: 'cancel'}
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
// dataFetch() is asyncronous, so all these requests just get fired off...
|
||||||
|
// 200 rows chosen arbitrarily to reduce requests.
|
||||||
|
do {
|
||||||
|
var ctx = {
|
||||||
|
"self": this.controller,
|
||||||
|
"start": count,
|
||||||
|
"count": Math.min(value,200),
|
||||||
|
"lastModification": this.controller._lastModification
|
||||||
|
};
|
||||||
|
if(nm.controller.dataStorePrefix)
|
||||||
|
{
|
||||||
|
ctx.prefix = nm.controller.dataStorePrefix;
|
||||||
|
}
|
||||||
|
nm.controller.dataFetch({start:count, num_rows: Math.min(value,200)}, function(data) {
|
||||||
|
// Keep track
|
||||||
|
if(data && data.order)
|
||||||
|
{
|
||||||
|
fetchedCount += data.order.length;
|
||||||
|
}
|
||||||
|
nm.controller._fetchCallback.apply(this, arguments);
|
||||||
|
|
||||||
|
if(fetchedCount >= value)
|
||||||
|
{
|
||||||
|
if(cancel)
|
||||||
|
{
|
||||||
|
dialog.destroy();
|
||||||
|
defer.reject();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
nm.controller._grid.setScrollHeight(nm.controller._grid.getAverageHeight() * (value+1));
|
||||||
|
// Grid needs to redraw before it can be printed, so wait
|
||||||
|
window.setTimeout(jQuery.proxy(function() {
|
||||||
|
dialog.destroy();
|
||||||
|
// Should be OK to print now
|
||||||
|
defer.resolve();
|
||||||
|
},nm),ET2_GRID_INVALIDATE_TIMEOUT);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
},ctx);
|
||||||
|
count += 200;
|
||||||
|
} while (count < value)
|
||||||
|
nm.controller._grid.setScrollHeight(nm.controller._grid.getAverageHeight() * (value+1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Don't need more rows, limit to requested and finish
|
||||||
|
this.controller._grid.setScrollHeight(this.controller._grid.getAverageHeight() * (value+1));
|
||||||
|
// Give dialog a chance to close, or it will be in the print
|
||||||
|
window.setTimeout(function() {defer.resolve();}, 0);
|
||||||
|
}
|
||||||
|
//this.controller._gridCallback(0, button == et2_dialog.OK_BUTTON ? value : this.controller._grid.getTotalCount());
|
||||||
|
},this),
|
||||||
|
egw.lang('How many rows to print'), egw.lang('Print'),
|
||||||
|
Math.min(100, total),
|
||||||
|
[
|
||||||
|
{"button_id": 1,"text": egw.lang('Ok'), id: 'dialog[ok]', image: 'check', "default":true},
|
||||||
|
// Nice for small lists, kills server for large lists
|
||||||
|
//{"button_id": 2,"text": egw.lang('All'), id: 'dialog[all]', image: ''},
|
||||||
|
{"button_id": 0,"text": egw.lang('Cancel'), id: 'dialog[cancel]', image: 'cancel'},
|
||||||
|
]
|
||||||
|
);
|
||||||
|
return defer;
|
||||||
|
}
|
||||||
|
// Don't return anything, just work normally
|
||||||
|
},
|
||||||
|
afterPrint: function() {
|
||||||
|
this.div.removeClass('print');
|
||||||
|
this.controller._grid.setScrollHeight(this.old_height);
|
||||||
|
delete this.old_height;
|
||||||
|
this.dynheight.outerNode.css('max-width','inherit');
|
||||||
|
this.resize();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
et2_register_widget(et2_nextmatch, ["nextmatch"]);
|
et2_register_widget(et2_nextmatch, ["nextmatch"]);
|
||||||
|
@ -904,6 +904,69 @@ etemplate2.app_refresh = function(_msg, _app, _id, _type)
|
|||||||
return refresh_done;
|
return refresh_done;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* "Intelligently" print a given app
|
||||||
|
*
|
||||||
|
* Mostly, we let the nextmatch change how many rows it's showing, so you don't
|
||||||
|
* get just one printed page.
|
||||||
|
*/
|
||||||
|
etemplate2.print = function(_app)
|
||||||
|
{
|
||||||
|
// Allow any widget to change for printing
|
||||||
|
var et2 = etemplate2.getByApplication(_app);
|
||||||
|
|
||||||
|
// Sometimes changes take time
|
||||||
|
var deferred = [];
|
||||||
|
for(var i = 0; i < et2.length; i++)
|
||||||
|
{
|
||||||
|
// Skip hidden templates
|
||||||
|
if(!jQuery(et2[i].DOMContainer).filter(':visible').length) continue;
|
||||||
|
|
||||||
|
et2[i].widgetContainer.iterateOver(function(_widget) {
|
||||||
|
// Skip widgets from a different etemplate (home)
|
||||||
|
if(_widget.getInstanceManager() != et2[i]) return;
|
||||||
|
var result = _widget.beforePrint();
|
||||||
|
if (typeof result == "object" && result.done)
|
||||||
|
{
|
||||||
|
deferred.push(result);
|
||||||
|
}
|
||||||
|
},et2,et2_IPrint);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to clean up after - not guaranteed
|
||||||
|
var afterPrint = function() {
|
||||||
|
for(var i = 0; i < et2.length; i++)
|
||||||
|
{
|
||||||
|
// Skip hidden templates
|
||||||
|
if(!jQuery(et2[i].DOMContainer).filter(':visible')) continue;
|
||||||
|
et2[i].widgetContainer.iterateOver(function(_widget) {
|
||||||
|
_widget.afterPrint();
|
||||||
|
},et2,et2_IPrint);
|
||||||
|
}
|
||||||
|
var mediaQueryList = window.matchMedia('print');
|
||||||
|
mediaQueryList
|
||||||
|
};
|
||||||
|
if(egw.window.matchMedia) {
|
||||||
|
var mediaQueryList = window.matchMedia('print');
|
||||||
|
var listener = function(mql) {
|
||||||
|
if (!mql.matches) {
|
||||||
|
afterPrint();
|
||||||
|
mediaQueryList.removeListener(listener);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
mediaQueryList.addListener(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
egw.window.onafterprint = afterPrint;
|
||||||
|
|
||||||
|
// Wait for everything to be loaded, then send it off
|
||||||
|
jQuery.when.apply(jQuery, deferred).done(function() {
|
||||||
|
egw.window.print();
|
||||||
|
}).fail(function() {
|
||||||
|
afterPrint();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Some static things to make getting into widget context a little easier //
|
// Some static things to make getting into widget context a little easier //
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -462,6 +462,21 @@ which caused click on free space infront of a tag stops nm row selection*/
|
|||||||
.et2_nextmatch .egwGridView_grid tr td div.et2_vbox a {
|
.et2_nextmatch .egwGridView_grid tr td div.et2_vbox a {
|
||||||
display: table-row;
|
display: table-row;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
These are set via javascript before printing to help tame nextmatch's layout
|
||||||
|
for printing
|
||||||
|
*/
|
||||||
|
.et2_nextmatch.print .egwGridView_scrollarea {
|
||||||
|
height: auto !important;
|
||||||
|
width: auto !important;
|
||||||
|
}
|
||||||
|
.et2_nextmatch.print > div {
|
||||||
|
height: auto !important;
|
||||||
|
}
|
||||||
|
.et2_nextmatch.print {
|
||||||
|
/* This is fairly arbitrary, but makes it fit in Chrome and Firefox*/
|
||||||
|
max-width: 700pt !important;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Diff widget
|
* Diff widget
|
||||||
*/
|
*/
|
||||||
@ -1115,13 +1130,19 @@ div.message.floating {
|
|||||||
.et2_nextmatch .egwGridView_grid > tbody > tr {
|
.et2_nextmatch .egwGridView_grid > tbody > tr {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
.et2_nextmatch .egwGridView_spacer {
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
.egwGridView_grid > tbody > tr {
|
.egwGridView_grid > tbody > tr {
|
||||||
page-break-inside: avoid;
|
page-break-inside: avoid;
|
||||||
-webkit-region-break-inside: avoid;
|
-webkit-region-break-inside: avoid;
|
||||||
}
|
}
|
||||||
.et2_nextmatch > div {
|
.et2_nextmatch > div {
|
||||||
width: 100% !important;
|
width: auto !important;
|
||||||
height: auto;
|
height: auto !important;
|
||||||
|
}
|
||||||
|
.et2_nextmatch table.egwGridView_outer thead tr th div.innerContainer {
|
||||||
|
max-height: inherit;
|
||||||
}
|
}
|
||||||
#cke_1_top.cke_top {
|
#cke_1_top.cke_top {
|
||||||
display: none;
|
display: none;
|
||||||
|
@ -18,21 +18,35 @@
|
|||||||
@media print {
|
@media print {
|
||||||
|
|
||||||
html, body {
|
html, body {
|
||||||
width: 100% !important;
|
width: auto !important;
|
||||||
|
height: auto !important;
|
||||||
}
|
}
|
||||||
#egw_fw_sidebar, #egw_fw_topmenu, .egw_fw_ui_tabs_header, #egw_fw_topmenu_slide,#egw_fw_print,#egw_fw_logout {
|
#egw_fw_sidebar, #egw_fw_topmenu, .egw_fw_ui_tabs_header, #egw_fw_topmenu_slide,#egw_fw_print,#egw_fw_logout {
|
||||||
display: none;
|
display: none;
|
||||||
|
width: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#egw_fw_main, #egw_fw_tabs {
|
#egw_fw_main, #egw_fw_tabs {
|
||||||
margin: 0px !important;
|
margin: 0px !important;
|
||||||
float: none !important;
|
float: none !important;
|
||||||
|
width: auto !important;
|
||||||
}
|
}
|
||||||
#egw_fw_basecontainer {
|
#egw_fw_basecontainer {
|
||||||
position: inherit;
|
position: inherit;
|
||||||
|
width: auto;
|
||||||
}
|
}
|
||||||
.egw_fw_ui_tab_content, .egw_fw_ui_tab_content > div {
|
.egw_fw_ui_tab_content {
|
||||||
height: auto;
|
position: relative;
|
||||||
|
float: none;
|
||||||
|
width: auto !important;
|
||||||
|
}
|
||||||
|
#egw_fw_main .egw_fw_ui_tab_content > div {
|
||||||
|
width: auto !important;
|
||||||
|
}
|
||||||
|
.egw_fw_ui_tab_content, .egw_fw_ui_tab_content div.egw_fw_content_browser_div {
|
||||||
|
height: auto !important;
|
||||||
|
overflow-y: hidden;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
body {
|
body {
|
||||||
background: white;
|
background: white;
|
||||||
|
@ -958,7 +958,17 @@ var fw_base = Class.extend({
|
|||||||
if (appWindow)
|
if (appWindow)
|
||||||
{
|
{
|
||||||
appWindow.focus();
|
appWindow.focus();
|
||||||
appWindow.print();
|
|
||||||
|
// et2 available, let its widgets prepare
|
||||||
|
if(typeof etemplate2 == "function" && etemplate2.print)
|
||||||
|
{
|
||||||
|
etemplate2.print(this.activeApp.appName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Print
|
||||||
|
appWindow.print();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
@media print {
|
@media print {
|
||||||
#egw_fw_topmenu_addons, #egw_fw_header {
|
#egw_fw_topmenu_addons, #egw_fw_header, #egw_fw_footer {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
} /* @media print */
|
} /* @media print */
|
Loading…
Reference in New Issue
Block a user