ExtJS 5: Resize panel on image loaded - javascript

It seems like a trivial task to do but I'm still unable to accomplish it.
I'm building an application with ExtJS 5 and I have a panel with an image component on it. The panel has to resize (shrinkWrap : true) to the original size of the image. The problem is that when the layout manager is calculating the size of the panel, the image isn't yet loaded completely so it's size is 0,0. I tried to add different listeners like afterrender, render, boxready and practically all of the rest but nothing seems to work fo me - the image size is always equals to 0. I also tried to bind the sizes of the two components as you'll see in the code below, but this doesn't worked either. If i configure the boxready event with a delay of 1 second the image size is finally computed and I can call updateLayout() but this is a very unreliable solution because the image is loaded from remote server and I'm unable to predict the exact time of server response. I know that at some point of the application lifecycle the image is loaded and I need to find which event is being fired in order to resize my panel.
Example code
Ext.application({ name : 'MyApp',
launch : function() {
/*
* I was hoping that taking the image out of the panel
* will 'force' it to be created earlier.
*/
var img = Ext.create('Ext.Img', {
src : 'img.jpg',
reference : 'bgimg',
publishes : {
width : true,
height: true
}
listeners : {
boxready : { fn : 'imgReady', scope : this, delay : 100 }
}
});
Ext.create('Ext.Panel', {
renderTo : Ext.get('extjs-content'),
width : 1000,
height: 700,
defaults : {
border : true
},
layout : 'border',
items : [{
region : 'north',
height : 80,
}, {
region : 'east',
width : 200,
collapsible : true
}, {
region : 'center',
autoScroll : true,
items : [{
/*
* This is the container of the image. Please note that
* I need it to preserve its absolute layout.
*/
id : 'canvas',
layout : 'absolute',
shrinkWrap : true,
// bind : {
// width : '{bgimg.width}',
// height: '{bgimg.height}'
// },
items : [img]
}]
}]
});
},
/*
* If I call this with delay of 1000ms the image size is 'ready'
* otherwise it is 0, 0.
*/
imgReady : function(img) {
console.log('Image size: %o', img.getSize());
Ext.ComponentQuery.query('#canvas')[0].updateLayout();
}
});

You can track when the image is loaded with the load event of the img element.
var img = Ext.create('Ext.Img', {
src : 'img.jpg',
reference : 'bgimg',
publishes : {
width : true,
height: true
},
listeners : {
load : {
element : 'el',
fn : 'imgReady'
}
}
});

Related

Content inside fancy box need to be responsive

I would like to create a gallery that is inside a fancy box , so firstly I downloaded all the content of the gallery and appended to the html container.
<div id="popup" style="display:none;"><div class="galleria"></div></div>
The jquery part
$("#hidden_content").instagram({
clientId: blockInstaSettings.clientId
, hash: hash
, userId: blockInstaSettings.userId
, next_url: insta_next_url
, show: 10
, image_size: image_size
, onComplete: function (photos, data) {
var album_html = "";
$.each(photos, function( index, val ) {
album_html += "<img src='" + val.images.standard_resolution.url + "' data-title='' data-description='" + val.caption.text.replace("'","’") + "' longdesc='" + val.link + "'>";
});
$(".galleria").html(album_html);
$('#block_instagram').on('click', function () {
openPop();
return false;
});
}
});
Notice that I set up the listener in the button that show the fancybox
function openPop(){
$.fancybox({
'autoScale': true,
'transitionIn': 'elastic',
'transitionOut': 'elastic',
'speedIn': 500,
'speedOut': 300,
'autoDimensions': true,
'centerOnScroll': true,
'href' : '#popup'
});
Galleria.run('.galleria', {
transition: 'fade',
popupLinks: true,
show: no,
extend: function(options) {
Galleria.get(0).$('info-link').click();
}
});
}
Attempted to call galleria.run when fancybox's afterShow event; but it is still the same.
Also for CSS, it need to be :
.galleria{
width:700px;
height:500px;
}
Otherwise ,it can not generate the gallery
How to fix that?
Reference
My site:
http://internal001.zizsoft.com/be_pure/
(When you scroll to bottom, there is a slider showing instagram photos, click on the photo and you will see the gallery)
The plugin used:
http://galleria.io/
http://fancyapps.com/fancybox/
As others mentioned in the commants all those plugins you are using are responsive already. When i visit your site if i resize the window after opening the fancybox its not resized as defined as "responsive". I thought this is what you are worrying about. You can invoke this by resize galleria on window resize event. Please refer this resize script for galleria to achieve. Thanks
Update: (Essential code blocks from the referred link)
to re-initialize the galleria while window resize.
First, set up the resize function:
function ResizeGallery() {
gWidth = $(window).width();
gHeight = $(window).height();
gWidth = gWidth - ((gWidth > 200) ? 100 : 0);
gHeight = gHeight - ((gHeight > 100) ? 50 : 0);
$("#gallerycontainer").width(gWidth);
$("#gallery").width(gWidth);
$("#gallery").height(gHeight);
// Reload theme
Galleria.loadTheme('js/galleria/themes/classic/galleria.classic.js', { show: curIdx });
}
Then bind it to the window resize event:
var TO = false;
$(window).resize(function () {
if (TO !== false)
clearTimeout(TO);
TO = setTimeout(ResizeGallery, 200); //200 is time in miliseconds
});
This will essentially re-initialize by reloading the default theme. In this example, I am using the second parameter to specify which image to show- otherwise it will display the first image. Be aware that this may cause another instance of Galleria. I believe this to be a bug, and posted on their forums. You can remove the older instances as follows:
var gcount = Galleria.get().length;
if (gcount > 1) {
Galleria.get().splice(0, gcount - 1);
}
Run it after the loadTheme method. Use settimeout to delay it, because loadTheme takes some time to complete. I use 200ms. Ugly, but I need some of the features in Galleria. Hope this helps.
every thing is responsive and works good. Elaborate your problem .
if you want your popup thumbnails appear in middle of your popup use the following code
.galleria-thumbnails {
text-align: center;
width: 100% !important;
}
.galleria-image {
display: inline-block;
float: none !important;
}
I found that using the javascript to handle that worked best for me you could have your script calculate height and then do something like this where you initialized fancybox
fitToView : true,
autoSize : true,
width : 100%,
height : 'auto',
you can play with fitToView and autoSize till you get the desired effect much like pinterest
you can do this with a simple css trick .
in the responsive media screen you have to set the css as
.tp-simpleresponsive .slotholder *, .tp-simpleresponsive img {
background-size: 100% auto !important;
}

UI-Grid does not take 100% width on page load

I am using ui-grid to showing data in table. when i load the page and leave for few second and then click on the tab (which containing ui-grid), the ui-grid css break. it does not show width of ui-grid 100% of container.but when i load page and just click on tab (containg ui-grid). ui-grid is showing perfect, i mean width of that is 100% of container. I don't know what is the problem.this is the code, i am working on :
Js:
$scope.gridOptions= {
enableFiltering: true,
enableGridMenu : true,
enableRowSelection: true,
enableSelectAll: true,
selectionRowHeaderWidth: 50,
// rowHeight: 35,
// infiniteScrollRowsFromEnd: 50,
// infiniteScrollUp: true,
infiniteScrollDown: true,
columnDefs : [
{ displayName:"Attribute",field: 'attributeId',filter: {placeholder: 'Search Attribute'},width:'10%'},
{ displayName:"Section",field: 'sectionRef.attributeSectionId' ,filter: {placeholder: 'Search Section'}},
{ displayName:"Type",field: 'types',filter: { placeholder: 'Search Types'} }
]
}
Html:
<div class="grid m-b-20" ui-grid="gridOptions" ui-grid-move-columns ui-grid-edit ui-grid-resize-columns ui-grid-pinning ui-grid-selection ui-grid-grouping ui-grid-infinite-scroll>
</div>
Note: ui-grid is inside Angular bootstrap Tab
and here is the snapshot of collapse grid :
Are you using an animation on page load - perhaps a tab or a modal? If so, then the usual workaround is the one we use in the modal tutorial: http://ui-grid.info/docs/#/tutorial/110_grid_in_modal
The problem is that the grid isn't responsive, it gets it's size on render. If you haven't given a fixed size it gets it from the container size. If your container is being animated at the time, the size may not be the real size.
$timeout(function () {
$scope.gridApi.core.handleWindowResize();
}, 500);
$scope.gridApi.core.refresh();
This did the job for me.
use $scope.gridApi.core.handleWindowResize(); this method in interval time to solve this problem
onRegisterApi: function(gridApi) {
$scope.gridApi = gridApi;
$scope.mySelectedRows = $scope.gridApi.selection.getSelectedRows();
//$scope.gridApi.grid.registerRowsProcessor($scope.singleFilter);
gridApi.selection.on.rowSelectionChanged($scope, function(row) {
$scope.selectedUser = row.entity.dev_id;
console.log(row);
console.log(row.grid.selection.lastSelectedRow.isSelected);
/*$http.get('./api/ioni_developers/' + $scope.selectedUser).then(function(response) {
if(row.grid.selection.lastSelectedRow.isSelected === true){
$scope.data.dev_id = response.data.dev_id;
$scope.data.dev_name = response.data.dev_name;
$scope.data.dev_email = response.data.dev_email;
$scope.selected = false;
}else{
$scope.data.dev_id = '';
$scope.data.dev_name = '';
$scope.data.dev_email = '';
$scope.selected = true;
}
})*/
});
$scope.selected = true;
$interval( function() {
$scope.gridApi.core.handleWindowResize();
}, 500, 10);
}
The workaround for this is adding the width and rowHeight
for row and cell. As I indicated this is a workaround and I am sure there must other ways of doing this but this a quick fix and should get you what you at least going :)
$scope.gridOptions={
//set the row height to a fixed length
rowHeight: 80,
enableFiltering: true,
enableGridMenu : true,
enableRowSelection: true,
enableSelectAll: true,
selectionRowHeaderWidth: 50,
infiniteScrollDown: true,
columnDefs : [
{ displayName:"Attribute",field: 'attributeId',filter: {placeholder: 'Search Attribute'},width:100},
{ displayName:"Section",field: 'sectionRef.attributeSectionId' ,filter: {placeholder: 'Search Section'}, width:100},
{ displayName:"Type",field: 'types',filter: { placeholder: 'Search Types'} , width:100}
]}
With the suggested polling approach, the function is called after a specified wait, so each width change occurs suddenly. This results in substantial judder when the user quickly changes the table size.
A much better approach is to bind a resize handler to call a resize function when the viewport changes
angular.element($window).bind('resize', () => {
this.updateTableWidth();
});
My project uses a sidebar, so I account for the sidebar width or padding width (if sidebar is open or not), then just set a variable bound to an ng-style on my table wrapper
private updateTableWidth() {
let width = this.$window.innerWidth;
let modifier = (width >= 1280) ? this.sidebarWidth : this.paddingWidth;
this.tableWidth = (width - modifier) + 'px';
}
<div ng-style="{'width': ctrl.tableWidth}">
<div ui-grid></div> <!-- Whatever your grid is -->
</div>
This is what worked for me like a charm!
Add say ng-style="windowResize" to the ui grid markup in HTML template, and on $scope.windowResize, add width: 100% within onRegisterApi function within the scope.
So, basically onRegisterApi() is the default function from ui-grid that triggers when grid is actually drawn, and so basically we are conditionally adding width 100% to grid and making it responsive for all viewports.
Remove ui-grid-resize-columns from your HTML div tags.

Show spinner ($.mobile.showPageLoadingMsg()) on just one element?

Is there a simple way to show the spinner ($.mobile.showPageLoadingMsg()) on just one element/region ?
I'm loading this element's content via AJAX, so until it's finished I have to block it and show this spinner.
You can set the CSS position of the loading spinner to appear over a certain region. Here is a code example that both shows and hides the loading spinner over an element:
//this is an IIFE, it creates an enclosure around the code that separates it from global code
(function ($) {
//a flag so we know what state the loading spinner is in
var isShowing = false;
//this example is binding to all link elements
$('a').on('click', function () {
//check if the loading spinner is already showing
if (isShowing === false) {
//the loader is not showing, so create an overlay in the container element
var $con = $('#container').append('<div class="container-overlay"></div>');
//now position the loader over the container
$('.ui-loader').css({
position : 'absolute',
top : ($con.offset().top + ($con.height() / 2)),
left : ($con.offset().left + ($con.width() / 2))
});
//fade-in the overlay and show the loading spinner
$con.children('.container-overlay').fadeIn(500);
$.mobile.showPageLoadingMsg();
//set the flag so next time around we hide the spinner
isShowing = true;
} else {
//fade-out the overlay
$('#container').children('.container-overlay').fadeOut(500, function () {
//remove the overlay from the DOM
$(this).remove();
//hide the loader
$.mobile.hidePageLoadingMsg();
//reset the CSS of the loader element
$el.css({
position : 'fixed',
top : '50%',
left : '50%'
});
});
//set the flag so next time around we show the loading spinner
isShowing = false;
}
});​
})(jQuery);
Here is a demo: http://jsfiddle.net/CkUZf/
For the demo (link) above, I used this CSS for the overlay element:
#container .container-overlay {
display : none;
height : 100%;
background : #000;
background : rgba(0, 0, 0, 0.75);
}​
It would also be possible to append the loader element to whatever container you want to "load" but $.mobile.showPageLoadingMsg() automatically resets the loader element so you'd have to disable that code in the jQuery Mobile include (which is why I went this the lighter CSS version above).
Update
This is probably more like what you were thinking:
$.fn.customMobileSpinner = function (options) {
var defaults = {
url : null,
fadeDuration : 500,
bgColor : 'rgba(0, 0, 0, 0.75)',
bgColorFallback : '#000'
};
//merge the defaults and options objects
options = $.extend({}, defaults, options);
//make sure the URL is specified
if (options.url !== null) {
//only work with the first element passed-in
var $element = this.eq(0);
$element.append(
$('<div class="container-overlay" />').css({
display : 'none',
height : '100%',
width : '100%',
background : options.bgColorFallback,
background : options.bgColor
})
).children('.container-overlay').fadeIn(options.fadeDuration);
//update loader CSS
$('.ui-loader').css({
position : 'absolute',
top : ($element.offset().top + ($element.height() / 2)),
left : ($element.offset().left + ($element.width() / 2))
});
//show spinner
$.mobile.showPageLoadingMsg();
//create AJAX call
$.ajax({
url : options.url,
success : function (response) {
$element.fadeOut(options.fadeDuration, function () {
$element.html(response).fadeIn(options.fadeDuration);
$.mobile.hidePageLoadingMsg();
//reset loader CSS
$(".ui-loader").css({
position : 'fixed',
top : '50%',
left : '50%'
});
});
}
});
}
};
Then you just call this method on a jQuery object:
$('#some-container').customMobileSpinner({
url : 'some-url'
});
I'm afraid you can't. Take a look at the docs, you can just customize the message or hide the spinner, but not making it fit to a element.
If you just want to show a spinner on some element loading, use the beforeSend and complete options of the ajax method to hide/show it

moving boxes plugin callback function

this kind of emergency, so please, can someone help me...
I'm using movingboxes plugin for slideshow(this is the original plugin:http://css-tricks.com/moving-boxes/)
I need help with setting callback function add to the end of animation. I need to add fading effect, when currentSlidecomplete sliding,it should start fading into another view of the same image, for example,surrentSlide src is images/dr1.jpg and i need it to fade to images/dr1b.jpg and come back to images/dr1.jpg. looping through each current Slide
something like
completed :
function(e, slider, tar){
//fading for each currentSlide goes here;//
}
Something like you describe is already in the documentation
see the documentation here [1] and more specifically here [2].
EDIT: check jsfiddle here, i used a jquery add-on http://jsfiddle.net/r6yWC/157/
the add-on is here http://jqueryfordesigners.com/image-cross-fade-transition/
I also edited the code section below. I added the class "fade" to the img tag like this:
<img class="fade" src="http://chriscoyier.github.com/MovingBoxes/demo/4.jpg" alt="picture" style="background: url(http://chriscoyier.github.com/MovingBoxes/demo/2.jpg);"/>
In the 2nd link you will find a movingBoxes sample with a completed callback.
(function ($) {
$.fn.cross = function (options) {
return this.each(function (i) {
// cache the copy of jQuery(this) - the start image
var $$ = $(this);
// get the target from the backgroundImage + regexp
var target = $$.css('backgroundImage').replace(/^url|[\(\)'"]/g, '');
// nice long chain: wrap img element in span
$$.wrap('<span style="position: relative;"></span>')
// change selector to parent - i.e. newly created span
.parent()
// prepend a new image inside the span
.prepend('<img>')
// change the selector to the newly created image
.find(':first-child')
// set the image to the target
.attr('src', target);
// the CSS styling of the start image needs to be handled
// differently for different browsers
if ($.browser.msie || $.browser.mozilla) {
$$.css({
'position' : 'absolute',
'left' : 0,
'background' : '',
'top' : this.offsetTop
});
} else if ($.browser.opera && $.browser.version < 9.5) {
// Browser sniffing is bad - however opera < 9.5 has a render bug
// so this is required to get around it we can't apply the 'top' : 0
// separately because Mozilla strips the style set originally somehow...
$$.css({
'position' : 'absolute',
'left' : 0,
'background' : '',
'top' : "0"
});
} else { // Safari
$$.css({
'position' : 'absolute',
'left' : 0,
'background' : ''
});
}
// similar effect as single image technique, except using .animate
// which will handle the fading up from the right opacity for us
$$.hover(function () {
$$.stop().animate({
opacity: 0
}, 250);
}, function () {
$$.stop().animate({
opacity: 1
}, 250);
});
});
};
})(jQuery);
$('#slider').movingBoxes({
// **** Appearance ****
// start with this panel
...
...
//-----> here is your callback
// callback after animation completes
completed: function(e, slider, tar){
var img = slider.$panels.eq(tar).find('img');
img.cross();
img.stop().animate({opacity: 0}, 1250).delay(500).animate({opacity: 1}, 2550);
}
});​
[1] https://github.com/chriscoyier/MovingBoxes/wiki
[2] http://jsfiddle.net/Mottie/r6yWC/2/

qTip tooltip does not appear, jQuery

I have a site that displays items, 12 items per page and I can paginate through the pages using jquery. On the same page I implemented a the tooltip feature with qTip.
Hovering over the items some information appear. That works until I use the paginator to go to the next page.
The pagination reloads the content. But it has the same structure as when I refresh the page.
Here's my code:
$(document).ready(function() {
$(".cornerize").corner("5px");
$('a#verd').live('click', exSite);
$("a.tp").live('click', thumpsUp);
$("a#next").click(getProgramms);
$("a#previous").click(getProgramms);
$("a#page").each(function() {
$(this).click(getProgramms);
});
$('a.ppname[rel]').each(function(){
$(this).qtip( {
content : {url :$(this).attr('rel')},
position : {
corner : {
tooltip : 'leftBottom',
target : 'rightBottom'
}
},
style : {
border : {
width : 5,
radius : 10
},
padding : 10,
textAlign : 'center',
tip : true,
name : 'cream'
}
});
});
});
The html/dom does not change:
<a class="ppname" rel="link" href="#">...</a>
qTip takes from every a.ppname the rel value end loads the content.
This is happening because new elements are not automatically "qTiped" when they are loaded after page load. For regular events, you would have to use .live() instead of .bind().
This has been solved before (judging from the comment): Problem with qTip - Tips not showing because elements load after the script.
The correct way to do it is (from that answer):
$('a.ppname[rel]').live('mouseover', function() {
var target = $(this);
if (target.data('qtip')) { return false; }
target.qtip({
overwrite: false, // Make sure another tooltip can't overwrite this one without it being explicitly destroyed
show: {
ready: true // Needed to make it show on first mouseover event
},
content : {url :$(this).attr('rel')},
position : {
corner : {
tooltip : 'leftBottom',
target : 'rightBottom'
}
},
style : {
border : {
width : 5,
radius : 10
},
padding : 10,
textAlign : 'center',
tip : true,
name : 'cream'
});
target.trigger('mouseover');
});

Categories

Resources