document.Body ComponentQuery - javascript

I am using an awesome html2canvas function but I have a noob question. How do I change the field it is capturing from document.body to a specific panel?
In short i need to change document.body to the panel I want to capture, I just don't know the code to get the panel I want.
I have tried Ext.ComponentQuery.query('#testPanel') without any success.
testButtonClicked: function (btn) {
html2canvas(document.body, {
onrendered: function (canvas) {
new Ext.Window({
title: 'Screenshot',
//width: 500,
height: 800,
resizable: true,
autoScroll: true,
preventBodyReset: true,
html: '<img src="' + canvas.toDataURL("image/png") + '" height="800"/>'
}).show();
}
});

You want getEl().dom. Here's a standalone example (tested with Ext 4.2.x):
Ext.onReady(function () {
Ext.define('Panel', {
extend: 'Ext.panel.Panel',
frame: true,
title: 'Test Panel',
width: 300,
height: 300,
onClick: function () {
html2canvas(this.getEl().dom, {
onrendered: function (canvas) {
new Ext.Window({
title: 'Screenshot',
width: 300,
height: 300,
html: '<img src="' + canvas.toDataURL("image/png") + '"/>'
}).show();
}
});
},
initComponent: function () {
var config = {
items: [
{
xtype: 'datepicker'
},
{
xtype: 'button',
text: 'CAPTURE THIS PANEL',
handler: this.onClick,
scope: this
}
]
};
Ext.apply(this, Ext.apply(this.initialConfig, config));
this.callParent(arguments);
}
});
var panel = Ext.create('Panel', {
renderTo: Ext.getBody()
});
});

html2canvas() appears to require a DOM element. Ext.ComponentQuery.query() returns an array of matched elements, so if you use precisely the code you provided, it won't work since the array returned from query() is obviously not a DOM element.
So if query() is actually returning something, you could use the first position:
Ext.ComponentQuery.query("#testPanel")[0]
Or, since you seem to have an ID assigned to the panel, you could simply use getCmp(), which will return only the element which is matched, and not an array:
Ext.getCmp( "testPanel" )

Related

EXTJS - Load Mask

I want to present the source code, which is taken from inside a div with jQuery, inside an Ext.Window. I have managed to do that, but my problem is that sometimes the source code is huge, since it contains encoded images and the Ext.Window takes some time to appear in the screen after it is triggered via click event. I would like to present the Ext.Window but with a loading icon until the data is ready.
win = new Ext.Window ({
title:'Source Code',
width:800,
height:300,
items: [{
xtype : 'textarea',
readOnly: true,
value: sourceCode
}]
});
win.show();
Try with a undefined function and a setTimeout function. Do not forget the config layout: 'fit'.
Ext.application({
name : 'Fiddle',
launch : function() {
var win = Ext.create('Ext.window.Window', {
title:'Source Code',
width:800,
height:300,
layout: 'fit',
items: [{
xtype : 'textarea',
readOnly: true,
value: 'test'
}]
});
win.show(undefined, function(){
win.getEl().mask('Loading...');
setTimeout(function() {
win.getEl().unmask();
}, 3000);
});
}
});
Or
Ext.application({
name : 'Fiddle',
launch : function() {
Ext.create('Ext.window.Window', {
title:'Source Code',
width:800,
height:300,
layout: 'fit',
items: [{
xtype : 'textarea',
readOnly: true,
value: 'test'
}]
}).show(undefined, function(){
win.getEl().mask('Loading...');
setTimeout(function() {
win.getEl().unmask();
}, 3000);
});
}
});
TRY
win.show(undefined, function(){
win.getEl().mask('Loading...');
win.suspendEvents();
win.down('textarea').setValue(sourceCode);
win.down('textarea').focus();
win.resumeEvents();
setTimeout(function() {
win.getEl().unmask();
}, 2000);
});
What you can try is to set the value only after the window is already displayed:
win = new Ext.Window ({
title:'Source Code',
width:800,
height:300,
items: [{
xtype : 'textarea',
readOnly: true
}],
listeners: {
afterrender: function(sourceWindow) {
sourceWindow.down('textarea').setValue(sourceCode)
}
}
});
win.show();
Then you can add josei's mask/unmask approach on top of that, although I would recommend that you search some event that happens after the value has been set to remove the mask (you can try the change event on the textarea), because that way your wait wouldn't be a fixed amount of time, but related to the time it takes to render the textarea value.

Optimizing performance in an ExtJS app

I've got an application that is heavy on field usage. I noticed that adding new fields can be fairly expensive, even when using suspend/resumelayouts. Observing the timeline in Chrome, I can see quite a lot of recalculation of styles and forced layouts (seems like one per fields) for the panel div.
The code below is a simple representation of what I'm doing.
util = {
createTextField: function(myItemId) {
return Ext.create('Ext.form.field.Text', {
fieldLabel: 'Field' + myItemId + ':',
name: 'field',
itemId: myItemId,
autofocus: true,
enableKeyEvents: true,
labelAlign: 'left',
labelWidth: 50,
labelStyle: 'font-size: 16px;',
width: 500
});
}
}
Ext.onReady(function() {
Ext.create('Ext.Button', {
text: 'Click me',
renderTo: Ext.getBody(),
handler: function() {
for(i=0; i<100; i++)
{
Ext.suspendLayouts();
formPanel.add(util.createTextField(i));
Ext.resumeLayouts(true);
}
}
});
var formPanel = Ext.create('Ext.form.Panel', {
frame: true,
title: 'Form Fields',
width: 340,
height: 600,
bodyPadding: 5,
autoScroll: true,
fieldDefaults: {
labelAlign: 'left',
labelWidth: 90
}});
formPanel.render('form-ct');
});
The page itself is fairly straightforward:
<body>
<div id="form-ct"></div>
</body>
Right now pressing the button takes roughly ~2 seconds in Chrome and almost 4 in IE11. My question is whether this can be somehow optimized. Note that the fields must be rendered dynamically. I'm using ExtJS 4.1.
Start with moving suspendLayout/resumeLayout pair outside of the loop:
Ext.suspendLayouts();
for(i=0; i<100; i++)
{
formPanel.add(util.createTextField(i));
}
Ext.resumeLayouts(true);
Calling these inside the loop basically defeats the whole purpose of suspending layouts because you are forcing a relayout no less than 100 times in a row.
The add method is firing two events, add and beforeadd. You can instead using an array with components to add all at ones. Besides that you can use defaults and defaultType, but that will not do much I guess.
util = {
createTextField: function(myItemId) {
return Ext.create('Ext.form.field.Text', {
fieldLabel: 'Field' + myItemId + ':',
name: 'field' + myItemId // names are unique, we will use this to query components
});
}
}
Ext.onReady(function() {
Ext.create('Ext.Button', {
text: 'Click me',
renderTo: Ext.getBody(),
handler: function() {
// array to hold all components
var components = new Array();
// optimize the for loop and introduce y
for(var i = 0, y = 100; i < y; i++)
components.push(util.createTextField(i));
// add all components at ones to prevent multiple events fired
Ext.suspendLayouts();
formPanel.add(components);
Ext.resumeLayouts(true);
}
});
var formPanel = Ext.create('Ext.form.Panel', {
frame: true,
title: 'Form Fields',
width: 340,
height: 600,
bodyPadding: 5,
autoScroll: true,
// use defaultType and defaults to clean the code
defaultTypes: 'textfield',
defaults: {
autofocus: true,
enableKeyEvents: true, // this is heavy, consider if it is required
labelAlign: 'left',
labelWidth: 50,
labelStyle: 'font-size: 16px;',
width: 500
}
});
formPanel.render('form-ct');
});

A unique pop-up called from different buttons - ExtJS

My aim is simple, for some needs, I have to test the "pop-up function" in ExtJS via the widget.window.
I've created a button in HTML and a pop-u in a JS file, when I click it, everything works fine, the pop-up is well displayed.
The HTML button is coded this way :
<input type="button" id="popup-map" value="Pop Up"/>
And the JS refers to the button this way :
Ext.application({
name: 'popup',
launch: function() {
var popup,
button = Ext.get('popup-map');
button.on('click', function(){
if (!popup) {
popup = Ext.create('widget.window', {
title: 'Pop-Up',
header: {
titlePosition: 2,
titleAlign: 'center'
},
border: false,
closable: true,
closeAction: 'hide',
width: 800,
minWidth: 400,
maxWidth: 1200,
height: 500,
minHeight: 550,
maxHeight: 800,
tools: [{type: 'help'}],
layout: {
type: 'border',
padding: 2
},
items: [
{
region: 'center',
xtype: 'tabpanel',
items: [
mappanel,
{
title: 'Description',
html: 'Attributs de l\'objet sous forme de tableau'
}
]
}
]
});
}
button.dom.disabled = true;
if (popup.isVisible()) {
popup.hide(this, function() {
button.dom.disabled = false;
});
} else {
popup.show(this, function() {
button.dom.disabled = false;
});
}
});
Problem, if I have two buttons that contains the id "popup-map", only the first one declared is working. I guess it's pretty normal the way I've coded it.
How can I call the popup contains in the JS file by clicking several buttons in HTML ?
Thanks :-)
Use a CSS class instead of a duplicated id. Duplicated ids are bad, you know that... Then use Ext.query instead of Ext.get. Your code should look something like this:
Ext.onReady(function() {
var popup;
function handler(button) {
if (!popup) {
// ...
}
// you've got button and popup, do your things
}
// adds the handler to every button with class 'popup-map' on the page
Ext.query('button.popup-map', function(button) {
button.on('click', handler);
});
});
I'm using Ext.onReady to wait for the DOM to be ready before searching for buttons on the page. That also gives us a closure for our local variables popup and handler.
Thanks to #rixo, here's the code working.
I've created a empty css class called customizer.
Ext.onReady(function() {
var popup, popup_visible;
function popup_constructor() {
//alert(this.getAttribute('pwet'));
if (!popup) {
popup = Ext.create('widget.window', {
title: 'Pop-Up',
id: 'popup',
header: {
titlePosition: 2,
titleAlign: 'center',
height: 30
},
border: false,
closable: true,
closeAction: 'hide',
width: 800,
minWidth: 400,
maxWidth: 1200,
height: 500,
minHeight: 550,
maxHeight: 800,
tools: [{type: 'help'}],
layout: {
type: 'border',
padding: 10
},
items: [
{
region: 'center',
xtype: 'tabpanel',
plain: true,
items: [
{
title: 'Carte',
html: 'On mettra la carte ici',
border: false,
},
{
title: 'Description',
html: 'Attributs de l\'objet sous forme de tableau',
border: false,
}
]
}
]
});
}
popup_visible = true;
if (popup.isVisible())
{
popup.hide(this, function() {
popup_visible = false;
});
}
else
{
popup.show(this, function() {
popup_visible = false;
});
}
}
var popup_show = Ext.query('.customizer');
Ext.each(popup_show, function (item) {
item = Ext.get(item);
item.on('click', popup_constructor);
}, this);
});

ExtJS drag event listeners work differently on Chrome and Firefox

I have added an input field to Window's title bar (header). On Chrome selecting and editing the input field works, and I can still drag the window around. On Firefox I can drag the window around the viewport, but I am unable to select the input field and edit it. How should I correct this code so that it would work on both browsers?
Quick'n'dirty demonstration of the problem:
Ext.define('Demo.DemoWindow', {
extend: 'Ext.window.Window',
xtype: 'demowindow',
height: 300,
width: 400,
title: 'Window',
autoShow: true,
items: [{
xtype: 'button',
text : 'Press!',
listeners: {
click: function() {
var win = this.up('window');
var header = win.getHeader();
header.setTitle('');
var killDrag = false;
var dragEvent = win.dd.on({
beforedragstart: function(dd, e) {
if (killDrag) {
return false;
}
}
});
var field = Ext.create('Ext.form.field.Text', {
name: 'Title',
allowBlank: false,
value: 'Type here something!',
listeners: {
el: {
delegate: 'input',
mouseout: function() {
killDrag = false;
},
mouseenter: function() {
killDrag = true;
}
}
}
});
header.insert(0, field);
}
}
}]
});
Ext.application({
name: 'Demo',
launch: function() {
Ext.create('Ext.container.Viewport', {
layout: 'absolute',
items: [
{
xtype: 'demowindow',
x: 20,
y: 20,
}
]
});
}
});
Using the mouseover event instead of mouseenter seems to work well with both.

How can i insert an handler for an HTML object?

question is simple!
I have an object like this:
new Ext.Panel({
id: 'Panel',
fullscreen: true,
dockedItems: [
dock:...,
width: ...,
listeners: { el: /*TOUCHEVENTS*/ },
html: '<object id='objectID' data="blabla"/>'
]
});
How can i add an event (like tap or pinch) on the HTML object with id= ObjectID ???
Thanks in advance ;)
I suggest you to use event delegation to makes possibile what you request.
Event delegation allow you to set tap listeners on a specific target on your panel inner HTML object. I write you an example that show you how to do that:
Ext.setup({
onReady: function() {
//Definition of a handler function
var myHandler = function(){
Ext.Msg.alert('What???','Did you Tap me?');
};
//Definition of a simple Panel
var p = new Ext.Panel({
fullscreen: true,
dockedItems: [{
xtype: 'panel',
dock: 'top',
height: '30',
html: '<div id="myObject">Tap me please</div>',
listeners: {
body: {
tap: myHandler,
delegate: '#myObject'
}
}
}]
});
}
});
If you run this code, you will see that, when you tap on the "Tap me Please!" div, your event will be fired.
Hope this helps.
Something like:
var p = new Ext.Panel({
id: 'Panel',
fullscreen: true,
dockedItems: [
html: '<object id='objectID' data="blabla"/>'
]
});
p.on('render', function() {
Ext.get("objectID").on('click', function() {
alert('imclicket');
});
});

Categories