Datatables - fixedHeader with scrollX - datatables

I am trying to use Datatables with fixedheader (v3) as well as enable horizontal scrolling. Attached is the fiddle http://jsfiddle.net/xF8hZ/344/
$(document).ready(function() {
var table = $('#example').DataTable({
searching: false,
paging: false,
ordering: false,
info: false,
fixedHeader: true,
scrollX: true
});
} );
.
When scrolling the fixedheader width doesn't align with the rest of the table. Can you help me solve this please?
Thanks

Pure css solution using css sticky (not work in ie 11):
remove the fixHeader plugin
add this css
.dataTables_scrollHead {
position: sticky !important;
top: 119px;
z-index: 99;
background-color: white;
box-shadow: 0px 5px 5px 0px rgba(82, 63, 105, 0.08);
}

I have read for 2 days about this, so joining all of them together, here's my contribution.
I got it figured out, hopefully this is useful for someone or help in the development as well.
My datatables is in a DIV and horizontal Scrolling enable due to huge table. When fixed header was set it was set as FIXED, and a new table is inserted at the BODY rather than inside the div.
I made it appended to the DIV instead of BODY so that the overflow rule might be inherited.
File:
dataTables.fixedHeader.min.js (search for "appendTo")
From:
e.table().node().cloneNode(!1)).removeAttr("id").append(f).appendTo("body")
To:
e.table().node().cloneNode(!1)).removeAttr("id").append(f).appendTo(".dataTables_scroll")
Now that it's appended to the the datatables-created-div, same level as dataTables_scrollHead, dataTables_scrollBody rather than stranded alone at body, whatever overflow still showing/sticking out.
File:
fixedHeader.bootstrap.min.css
From:
table.dataTable.fixedHeader-floating{position:fixed !important}
To
table.dataTable.fixedHeader-floating{position:absolute !important}
or File:
fixedHeader.dataTables.min.css
From:
table.fixedHeader-floating{position:fixed !important;background-color:white;}
To
table.fixedHeader-floating{position:absolute !important;background-color:white;}
Careful of CACHE of the CSS and JS files.
Now that the floating sticky row has appeared but out of place and overflow in effect.
Have this JS running, detecting when fixedHeader-floating appears, keep adjusting them to follow the horizontal scroll and stick to the top.
setInterval(function(){
if($('.fixedHeader-floating').is(':visible')){
var myoffset = Math.round($(window).scrollTop() - $('#Detail2Container').position().top + $('.topbar').height() - 145);
var positionleft = $('.dataTables_scrollHeadInner').position();
$('.fixedHeader-floating').css({ 'top': myoffset, 'left': positionleft.left + 10 });
}
}, 50); //every 50ms
Detail2Container is the DIV that wrap the Datatables.
I couldn't use dataTables_wrapper as reference as there are a few of them in the same page. In my page, I only one table that needs fixedHeader, if I need 2, it will be tough. But I will deal with it when the needs arise.
You could adjust the calculation according to your own design.
2 days for me to figure this out. So I feel like sharing it too.

I found a solution on my project by doing this:
$('#example').scroll(function() {
if ( $(".fixedHeader-floating").is(":visible") ) {
$(".fixedHeader-floating").scrollLeft( $(this).scrollLeft() );
}
});
DataTables creates a new table as the fixedHeader when you scroll down, what I'm doing here is to detect when the user scrolls horizontally on the $('#example') table and then I use scrollLeft() on the fixedHeader to match the scroll position.
I also added this to my .css so the user won't be able to scroll on the fixedHeader table:
.fixedHeader-floating {
overflow: hidden;
}

Following is working to me
$('.dataTables_scrollBody').on('scroll', function () {
$('.dataTables_scrollHead', $(this).parent()).scrollLeft($(this).scrollLeft());
});

This fixed the problem.
let tableParams = {
autoWidth: false,
// etc...
scrollX: true,
fixedHeader: true,
initComplete: function(settings, json) {
// To fix the issue of when scrolling on the X axis, the header needs also to scroll as well.
this.find('.dataTables_scrollBody').on('scroll', function() {
this.find('.dataTables_scrollHeadInner').scrollLeft($(this).scrollLeft());
});
},
};
Also to hide the vertical scroll bar.
me.containerElement.find('.dataTables_scrollBody').css({'overflow-y': 'hidden'});
where containerElement is the parent element of the datatable element.

Based on this, I was able to make it working (issue: when FixedHeader is floating, sorting would not work ==> see update 1 below to fix it)
Explanations:
FixedHeader (.dataTables_scrollHeadInner) is a different table outside of datatable (.dataTables_scrollBody)
when scrolling vertically, it will check scrolltop and set FixedHeader top accordingly.
when scrolling horizontally, it will scroll FixedHeader with body ($('.dataTables_scrollHeadInner').scrollLeft($(this).scrollLeft()))
JS
// sorry - had to use global variable
// global variable for scroll-body y position
var yPositionOfScrollBody;
function adjustDatatableInnerBodyPadding(){
let $dtScrollHeadInner = $('.dataTables_scrollHeadInner');
let outerHeightOfInnerHeader = $dtScrollHeadInner.outerHeight(true);
//console.log('outerHeightOfInnerHeader => ' + outerHeightOfInnerHeader);
$('.dataTables_scrollBody').css('padding-top', outerHeightOfInnerHeader);
}
function setFixedHeaderTop(header_pos){
//console.log("header_pos : " + header_pos);
$('.dataTables_scrollHeadInner').css({"top": header_pos});
}
function fixDatatableHeaderTopPosition(){
//console.log("fixHeaderTop...");
yPositionOfScrollBody = window.scrollY + document.querySelector('.dataTables_scrollBody').getBoundingClientRect().top;
//console.log("yPositionOfScrollBody: " + yPositionOfScrollBody);
setFixedHeaderTop(yPositionOfScrollBody);
}
function onDataTableInitComplete(settings, json) {
// for vertical scolling
yPositionOfScrollBody = window.scrollY + document.querySelector('.dataTables_scrollBody').getBoundingClientRect().top;
// datatable padding adjustment
adjustDatatableInnerBodyPadding();
// data table fixed header F5 (refresh/reload) fix
let scrollTop = window.pageYOffset || document.documentElement.scrollTop;
//console.log("scrollTop => " + scrollTop);
if(scrollTop > 1){
let header_pos;
if (scrollTop < yPositionOfScrollBody){
header_pos = yPositionOfScrollBody - scrollTop;
} else {
header_pos = 0;
}
setFixedHeaderTop(header_pos);
}
let $dtScrollHeadInner = $('.dataTables_scrollHeadInner');
// horizontal scrolling
$('.dataTables_scrollBody').on('scroll', function () {
let $dtScrollBody = $(this);
// synchronize
let amountOfLeftScroll = $dtScrollBody.scrollLeft();
$dtScrollHeadInner.scrollLeft(amountOfLeftScroll);
let scrollDiff = $dtScrollHeadInner.scrollLeft() - amountOfLeftScroll;
//console.log("scrollDiff: " + scrollDiff);
if(scrollDiff < 0){
$dtScrollHeadInner.css('left', scrollDiff);
}else{
//console.log("scroll back to left side");
$dtScrollHeadInner.css('left', '');
}
});
//console.log("adjusment mergin: " + yPositionScrollHeadInner);
$(document).on('scroll', function () {
let scroll_pos = $(this).scrollTop();
if(scroll_pos <= 0){
fixDatatableHeaderTopPosition();
}else{
let margin = yPositionOfScrollBody; // Adjust it to your needs
let cur_pos = $('.dataTables_scrollHeadInner').position();
let header_pos = cur_pos.top;
if (scroll_pos < margin){
header_pos = margin - scroll_pos;
} else {
header_pos = 0;
}
setFixedHeaderTop(header_pos);
}
});
}
$(function(){
$("#tableId").DataTable({
scrollX: true,
fixedHeader: true,
initComplete: onDataTableInitComplete,
// ... : ...
});
});
CSS
/* data table - scroll and fixed header */
table.dataTable.fixedHeader-floating {
display: none !important; /*Hide the fixedHeader since we dont need it*/
}
.dataTables_scrollHeadInner{
margin-left: 0px;
width: 100% !important;
position: fixed;
display: block;
overflow: hidden;
/*margin-right: 30px;*/
background: white;
z-index: 1;
}
.dataTables_scrollBody{
padding-top: 2.5em;
}
div.dataTables_scrollHead table.dataTable {
padding-right: 0;
}
Update 1 - sort issue fix
use fixedHeader: false
$(function(){
$("#tableId").DataTable({
scrollX: true,
fixedHeader: false,
initComplete: onDataTableInitComplete,
// ... : ...
});
});

You can change 'left' but saving initial value first:
var initLeft = 0;
$(".dataTables_scrollBody").scroll(function () {
if ($(".fixedHeader-floating").is(":visible")) {
if (initLeft == 0)
initLeft = $(".fixedHeader-floating").position().left;
$(".fixedHeader-floating").css("left", $(this).scrollLeft() * (-1) + initLeft);
}
});

$(document).ready(function() {
var table = $('#example').DataTable({
searching: true,
paging: true,
ordering: true,
info: false,
scrollY: 400,
dom: 'Blfrtip',
});
} );

Related

WebRTC AGC (Automatic Gain Control): can it really be disabled?

:)
I've installed AppRTC (https://github.com/webrtc/apprtc) to a separate server to try out more flexible control of the WebRTC parameters.
The main task is to disable Automatic Gain Control (AGC).
The following steps have been performed:
The parameters for the audio-stream:
{
video:
{
frameRate: 30,
width: 640,
height: 480
},
audio:
{
echoCancellation: true,
noiseSuppression: true,
autoGainControl: false
}
}
The GainNode filter has been added via audioContext.createGain() and has received a fixed value via gainNode.gain.value
To be able to test the AGC absence - a graphical audio meter has been added using audioContext.createScriptProcessor(...).onaudioprocess
The problem is that in fact the AGC is not disabled and Gain still remains dynamic.
During a long monotone loud sound the analyzer drops to a significantly lower value after 5-6 seconds.
And after 5-6 seconds of silence gets back to previous range.
All this has been tested on macOs Catalina 10.15.7, in the following browsers:
Mozilla Firefox 82.0.3,
Google Chrome 86.0.4240.198,
Safari 14.0 (15610.1.28.1.9, 15610),
and also on iOS 14.2 Safari.
The question: is there a functioning possibility to turn off AGC and to follow that not only "by hearing" but also by the meter values?
The full code of the gain fixation method:
src/web_app/html/index_template.html
var loadingParams = {
errorMessages: [],
isLoopback: false,
warningMessages: [],
roomId: '101',
roomLink: 'https://www.xxxx.com/r/101',
// mediaConstraints: {"audio": true, "video": true},
mediaConstraints: {video: {frameRate: 30, width: 640, height: 480}, audio: {echoCancellation: true, noiseSuppression: true, autoGainControl: false}},
offerOptions: {},
peerConnectionConfig: {"bundlePolicy": "max-bundle", "iceServers": [{"urls": ["turn:www.xxxx.com:3478?transport=udp", "turn:www.xxxx.com:3478?transport=tcp"], "username": "demo", "credential": "demo"}, {"urls": ["stun:www.xxxx.com:3478"], "username": "demo", "credential": "demo"}], "rtcpMuxPolicy": "require"},
peerConnectionConstraints: {"optional": []},
iceServerRequestUrl: 'https://www.xxxx.com//v1alpha/iceconfig?key=',
iceServerTransports: '',
wssUrl: 'wss://www.xxxx.com:8089/ws',
wssPostUrl: 'https://www.xxxx.com:8089',
bypassJoinConfirmation: false,
versionInfo: {"time": "Wed Sep 23 12:49:00 2020 +0200", "gitHash": "78600dbe205774c115cf481a091387d928c99d6a", "branch": "master"},
};
src/web_app/js/appcontroller.js
AppController.prototype.gainStream = function (stream, gainValue) {
var max_level_L = 0;
var old_level_L = 0;
var cnvs = document.createElement('canvas');
cnvs.style.cssText = 'position:fixed;width:320px;height:30px;z-index:100;background:#000';
document.body.appendChild(cnvs);
var cnvs_cntxt = cnvs.getContext("2d");
var videoTracks = stream.getVideoTracks();
var context = new AudioContext();
var mediaStreamSource = context.createMediaStreamSource(stream);
var mediaStreamDestination = context.createMediaStreamDestination();
var gainNode = context.createGain();
var javascriptNode = context.createScriptProcessor(1024, 1, 1);
mediaStreamSource.connect(gainNode);
mediaStreamSource.connect(javascriptNode);
gainNode.connect(mediaStreamDestination);
javascriptNode.connect(mediaStreamDestination);
javascriptNode.onaudioprocess = function(event){
var inpt_L = event.inputBuffer.getChannelData(0);
var instant_L = 0.0;
var sum_L = 0.0;
for(var i = 0; i < inpt_L.length; ++i) {
sum_L += inpt_L[i] * inpt_L[i];
}
instant_L = Math.sqrt(sum_L / inpt_L.length);
max_level_L = Math.max(max_level_L, instant_L);
instant_L = Math.max( instant_L, old_level_L -0.008 );
old_level_L = instant_L;
cnvs_cntxt.clearRect(0, 0, cnvs.width, cnvs.height);
cnvs_cntxt.fillStyle = '#00ff00';
cnvs_cntxt.fillRect(10,10,(cnvs.width-20)*(instant_L/max_level_L),(cnvs.height-20)); // x,y,w,h
}
gainNode.gain.value = gainValue;
var controlledStream = mediaStreamDestination.stream;
for (const videoTrack of videoTracks) {
controlledStream.addTrack(videoTrack);
}
return controlledStream;
};
AppController.prototype.onLocalStreamAdded_ = function(stream) {
trace('User has granted access to local media.');
this.localStream_ = this.gainStream(stream, 100);
this.infoBox_.getLocalTrackIds(this.localStream_);
if (!this.roomSelection_) {
this.attachLocalStream_();
}
};
Thank you!
Best Regards,
Andrei Costenco
I think the problem you ran into is that echoCancellation and noiseSuppression do modify the signal as well. Since you mentioned that you are using a long monotone sound to test your code it could very well be that the noiseSuppression algorithm tries to reduce that "noise".
Unfortunately there is no way to tell why the signal was modified. You have to trust the browser here that it actually has switched off the gain control and that all remaining modifications come from the other two algorithms.
If you don't want to fully trust the browser you could also experiment a bit by using other sounds to run your tests. It should not be "noisy" but it's difficult to say what get's detected by the browser as noise and what doesn't.

Angular Animations - Dynamic and Responsive translations

I have a component that is usually dormant (by which I simply mean it is of little interest to the user), but in a certain state this component becomes 'activated' and I want to put it in the exact center of the screen and enlarge it to grab the user's attention.
There are several of these components in the dormant state, but only ever 1 activated. The dormant components could be anywhere on the screen, so I wanted a solution that would translate the component from wherever it was originally to the middle of the screen while activated, and then return it back to its original dormant position when done.
Attempting to do this:
template:
<div #myElement [#isActivated]="activated">
Hello Stack Overflow
<button (click)="activated = activated === 'activated' ? 'dormant' : 'activated">
Toggle
</button>
</div>
typescript:
#Component({
// ...
animations: [
trigger('isActivated', [
state('dormant', style($transitionToActivated)),
state('activated', style({
transform: 'translateX(0%) translateY(0%) scale(1)'
})),
transition('dormant => activated', animate('1000ms ease')),
transition('activated => dormant', animate('1000ms ease'))
])
]
})
export class MyComponent implements OnInit {
#ViewChild('myElement') myElement: ElementRef;
activated = 'dormant';
transitionToActivated: any;
ngOnInit() {
let rect = this.myElement.nativeElement.getBoundingClinetRect();
this.transitionToActivated = {
transform: ''translateX(' + ((window.screen.width / 2) - (rect.right + rect.left) / 2) + ') translateY(' +
((window.screen.height / 2) - (rect.top + rect.bottom) / 2) + ') scale(1.5)'
}
}
}
My syntax here is off: the $transitionToActivated inside of the Component decorator is invalid. Is it possible to this kind of responsive animations with Angular Animations? Or will I need to look into a pure CSS solution?
[here's a plunker of what I'm trying... currently my attempt to put it in the exact center is commented out, and just some static animation instructions]
I figured out a couple things.
First, above I'm using window.screen for width and height of the 'screen.' This is actually giving me the resolution of the monitor (resizing the window doesn't affect it). I wanted document.documentElement to get the size of the viewport.
Second, I solved the issue of dynamic animations by using the AnimationPlayer to define the animations programmatically [rather than defining them in the Component decorator as I was trying to above].
I'm still curious as to whether the animations can be dynamically changed via the animation property inside the component decorator... I expect there must be a way, but I've been rather frustrated by the hand-wavy-ness of the Angular animations API and still can't figure it out.
Also, my solution acts funky when the viewport size is changed while in the 'activated state' (doesn't respond to resizing [as would be expected] and jumps at the start of its 'return' animation to the new middle of the viewport [again as expected].
Here's code and plunker to my solution:
export class App implements OnInit {
#ViewChild('myElement') myElement: ElementRef;
activated: BehaviorSubject<string> = new BehaviorSubject<string>('dormant');
transitionToActivated: any;
player: AnimationPlayer;
factory: any;
constructor(private builder: AnimationBuilder) {}
ngOnInit() {
console.log('viewport width: ' + document.documentElement.clientWidth);
console.log('viewport height: ' + document.documentElement.clientHeight);
let rect = this.myElement.nativeElement.getBoundingClientRect();
console.log('rect right: ' + rect.right);
console.log('rect left: ' + rect.left);
this.transitionToActivated = 'translateX(' + ((document.documentElement.clientWidth / 2) -
(rect.right + rect.left) / 2) + 'px) translateY(' +
((document.documentElement.clientHeight / 2) - (rect.top + rect.bottom) / 2) +
'px) scale(1)';
this.activated.subscribe(newValue => {
this.transitionToActivated = 'translateX(' + ((document.documentElement.clientWidth / 2) -
(rect.right + rect.left) / 2) + 'px) translateY(' +
((document.documentElement.clientHeight / 2) - (rect.top + rect.bottom) / 2) +
'px) scale(1)';
console.log(this.transitionToActivated);
if(newValue === 'activated'){
this.factory = this.builder.build([
style({ transform: 'translateX(0) translateY(0) scale(1)' }),
animate(
'1000ms',
style({ transform: this.transitionToActivated })
)
]);
this.player = this.factory.create(this.myElement.nativeElement, {});
this.player.play()
} else if(newValue === 'dormant'){
this.factory = this.builder.build([
style({ transform: this.transitionToActivated })
animate(
'1000ms',
style({ transform: 'translateX(0) translateY(0) scale(1)' }),
)
]);
this.player = this.factory.create(this.myElement.nativeElement, {});
this.player.play()
}
})
}
}

Collision Physics P2 and Arcade not working as desired

Hi all so I have a small problem, basically I'm trying to kill a moving sprite, it does not matters if it comes from left to right or right to left, but all I want to kill is the one colliding and not the whole group, so to test go to the far right and shoot the block, you will see the new block disappear but not the one that collided is this possible I'm providing my game.js below but I created a demo that you can download and test to get a better feel of my problem please help, thanks.
Link to Demo
BasicGame.Game = function (game) {
// When a State is added to Phaser it automatically has the following properties set on it, even if they already exist:
this.game; // a reference to the currently running game (Phaser.Game)
this.add; // used to add sprites, text, groups, etc (Phaser.GameObjectFactory)
this.camera; // a reference to the game camera (Phaser.Camera)
this.cache; // the game cache (Phaser.Cache)
this.input; // the global input manager. You can access this.input.keyboard, this.input.mouse, as well from it. (Phaser.Input)
this.load; // for preloading assets (Phaser.Loader)
this.math; // lots of useful common math operations (Phaser.Math)
this.sound; // the sound manager - add a sound, play one, set-up markers, etc (Phaser.SoundManager)
this.stage; // the game stage (Phaser.Stage)
this.time; // the clock (Phaser.Time)
this.tweens; // the tween manager (Phaser.TweenManager)
this.state; // the state manager (Phaser.StateManager)
this.world; // the game world (Phaser.World)
this.particles; // the particle manager (Phaser.Particles)
this.physics; // the physics manager (Phaser.Physics)
this.rnd; // the repeatable random number generator (Phaser.RandomDataGenerator)
// You can use any of these from any function within this State.
// But do consider them as being 'reserved words', i.e. don't create a property for your own game called "world" or you'll over-write the world reference.
this.bulletTimer = 0;
};
BasicGame.Game.prototype = {
create: function () {
//Enable physics
// Set the physics system
this.game.physics.startSystem(Phaser.Physics.ARCADE);
//End of physics
// Honestly, just about anything could go here. It's YOUR game after all. Eat your heart out!
this.createBullets();
this.createTanque();
this.makeOneBloque();
this.timerBloques = this.time.events.loop(1500, this.makeBloques, this);
},
update: function () {
if(this.game.input.activePointer.isDown){
this.fireBullet();
}
this.game.physics.arcade.overlap(this.bullets, this.bloque, this.collisionBulletBloque, null, this);
},
createBullets: function() {
this.bullets = this.game.add.group();
this.bullets.enableBody = true;
this.bullets.physicsBodyType = Phaser.Physics.ARCADE;
this.bullets.createMultiple(100, 'bulletSprite');
this.bullets.setAll('anchor.x', 0.5);
this.bullets.setAll('anchor.y', 1);
this.bullets.setAll('outOfBoundsKill', true);
this.bullets.setAll('checkWorldBounds', true);
},
fireBullet: function(){
if (this.bulletTimer < this.game.time.time) {
this.bulletTimer = this.game.time.time + 1400;
this.bullet = this.bullets.getFirstExists(false);
if (this.bullet) {
this.bullet.reset(this.tanque.x, this.tanque.y - 20);
this.bullet.body.velocity.y = -800;
}
}
},
makeOneBloque: function(){
this.bloquecs = ["bloqueSprite","bloquelSprite"];
this.bloque = this.game.add.group();
for (var i = 0; i < 4; i++){
this.bloque.createMultiple(5, this.bloquecs[Math.floor(Math.random()*this.bloquecs.length)], 0, false);
}
this.bloque.enableBody = true;
this.game.physics.arcade.enable(this.bloque);
this.bloque.setAll('anchor.x', 0.5);
this.bloque.setAll('anchor.y', 0.5);
this.bloque.setAll('outOfBoundsKill', true);
this.bloque.setAll('checkWorldBounds', true);
},
makeBloques: function(){
this.bloques = this.bloque.getFirstExists(false);
if (this.bloques) {
this.bloques.reset(0, 300);
this.bloques.body.kinematic = true;
this.bloques.body.velocity.x = 500;
}
},
createTanque: function() {
this.tanqueBounds = new Phaser.Rectangle(0, 600, 1024, 150);
this.tanque = this.add.sprite(500, 700, 'tanqueSprite');
this.tanque.inputEnabled = true;
this.tanque.input.enableDrag(true);
this.tanque.anchor.setTo(0.5,0.5);
this.tanque.input.boundsRect = this.tanqueBounds;
},
collisionBulletBloque: function(bullet, bloques) {
this.bloques.kill();
this.bullet.kill();
},
quitGame: function (pointer) {
// Here you should destroy anything you no longer need.
// Stop music, delete sprites, purge caches, free resources, all that good stuff.
// Then let's go back to the main menu.
this.state.start('MainMenu');
}
};

How to print a custom grid app?

I have added a print button and a PrintDialog to my custom app and now need to write a print function.
Do I need to open up a new window and build a table containing the grid data formatted with css styles fitted to A4 paper size or is there something built into Rally that I can use?
I am new to Rally and Ext JS, so any advice would be appreciated!
Ext.create('Rally.ui.dialog.PrintDialog', {
height: 250,
autoShow: true,
autoCenter: false,
shouldShowFormatOptions: false,
defaultTitle: 'Book Of Work Report',
listeners: {
print: function(event) {
//How do I print a grid?
},
To print the grid, I created a Rally.data.WsapiDataStore and loaded the store into an array. I passed this array(StoreData) to the below function which opens a print window displaying the grid in a table.
_printDetails: function(Storedata) {
var myData = Storedata;
var htmlTable ='<table>';
htmlTable +='<width="100%">';
var r,c;
for(r= 0 ; r<myData.length; r++){
htmlTable+= '<tr>';
for(c = 0 ; c<myData[0].length; c++){
htmlTable+='<td>'+myData[r][c]+'</td>';
}
htmlTable+='</tr>';
}
htmlTable+='</table>';
var cssTable = '<style type="text/css">';
cssTable +='table {border-collapse:collapse;...}';
cssTable +='th {color:#080808;border-bottom-style: solid; ...}';
cssTable +='tr {color:#000000; border-bottom-style: solid; ..}';
cssTable +='td {padding:3px 4px; text-align:left; vertical-align:top;}';
cssTable +='#filter {text-align:left; ...}';
cssTable += '</style>';
var printwindow=window.open('', '', 'width=1000,height=500');
var myDate = new Date;
printwindow.document.write('<div id="todayDate">' + Ext.Date.format(myDate,'F j, Y, g:i a') + '</div>');
printwindow.document.write('<div id="header">Book Of Work Report</div>');
printwindow.document.write('<div id="filter"><p>' + this._GetFilterString() + '</p></div>');
printwindow.document.write(htmlTable);
printwindow.document.write(cssTable);
printwindow.document.close();
printwindow.focus();
printwindow.print();
printwindow.close();
},
Your inclination is correct - the best option here is to open a window that you populate with table output/grid content and apply whatever CSS formatting you prefer. Rally doesn't have any server-side printing output functionality (at least that is exposed to AppSDK2).

Fade-to certain opacity using dojo

I'm using dojo toolkit. (version 1.6)
I'm unable to stop the fading effect at certain opacity (say 0.5)
Here is the code I'm using
var fadeArgs = {node: "disabled_div", duration: 3000};
dojo.style("disabled_div", "opacity", "0");
dojo.fadeIn(fadeArgs).play();
But the above code is fading the element's opacity from 0 to 1.
My requirement is to stop fading effect at 0.5 opacity.
Please help me out
Thanks in advance!
SuryaPavan
you may try like this:
var w = dojo.animateProperty({
node:"disabled_div",
duration: 3000,
properties: {
opacity: 0
},
onAnimate:function(a){
if(a.opacity <= .5)
w.stop();
}
})
OR
dojo.style("disabled_div", "opacity", "1");
var fadeArgs = {node: "disabled_div", duration: 3000,onAnimate:function(o){
if(o.opacity <= .5){
anim.stop()
}
}};
anim = dojo.fadeOut(fadeArgs);
anim.play();
You could use fadeTo from the DojoX extensions