Category Archives: jQuery

Fixing authors when importing a split WXR file for WordPress

If you have a large WordPress Extended RSS import file, WordPress suggests that you split the file in order to create multiple smaller files.  If you do this, then each file will have the same authors.  If you import the second file, third, fourth, etc… then those authors will be seen as duplicates and dropped (and all imported posts will be credited to ‘admin’) unless you go through each author and select them in the “or assign this post to existing author” combo boxes.   These combo boxes become available after you select a file and press “Import.”

If you are importing multiple files because a single one is too big, there is a chance you could have way too many authors to go through each one and do this.  This post describes a hack method of populating all of these combo boxes using jQuery and the browsers development tools.

I had to import 6 WXR files that i created, each one around 80Megs, and a total of almost 500 authors.

1) Get jQueryify here and add the bookmarklet per the instructions.

2) When you get to the “assign authors” page, right-click on the browser page and select “Inspect Element” (Chrome), or “Inspect with Firebug” in Firefox (install firebug if you haven’t already). In IE press F12 to start the Dev Tools.

3) Press the jQuerify bookmarklet button that you installed from step 1. This will turn on jQuery for the page.

4) Go to the console tab, enable the console if you need to, paste this code in and press RUN:
jQuery.noConflict(); //Disable jQuery $ just incase.

jQuery('#authors li').each(function() {
// Get the author login text
var username = jQuery(this).find('strong').html();
var author_login = jQuery.trim((username.split('('))[0]);

//Figure out which option this author is in the drop down.
var selectOptionval = -1;
jQuery(this).find('select option').each(function(){
if (jQuery(this).html() === author_login) {
selectOptionval = jQuery(this).val();
return false;//quit .each() early.
}
});

// Set the combo box to this author's option key.
jQuery(this).find('select').val(selectOptionval);
// For test...
//console.log(author_login + ": " + selectOptionval);
});


jQuery ready function with holdReady

I used this the other day in GWT, prior to backing it out and placing style classes in better places so i could use straight CSS targeting.  But, I thought it could be useful and it uses the new jQuery.holdReady function so here it is.

My goal was this: In order to get the correct horizontal scrollbar in a GWT app, I had to target the div right ABOVE the root div placed in my Root View (which contains the structural layout of my page). I used jQuery to target that div, but they went back and placed a styleclass in the RootLayoutPanel widget instead so that i could target this more cleanly (within GWT) with CSS’s :nth-of-type / :nth-child selector.  I found the exact DIV that i needed to target by placing overflow-x: auto !important on all the parent divs until it worked ‘correctly.’

The ‘pageScrolling’ style class is defined with only overflow-x: auto !important

/* Startup functions */

/*
* First, place a hold on the document ready function… GWT loads more stuff
* after the DOM loads, and we need to add a little extra delay to account for that.
*
* By using document ready and hold ready together, i am able to make sure that the
* startup function runs after the page is completely ready.
*/
jQuery.holdReady(true);

// Set up the on-DOM-ready function
jQuery(function($) {
// Find the DIV that should handle scrolling for the “body” and mark it
$(‘.myRootPanel’).parent().addClass(‘pageScrolling’);
});

/*
* GWT needs to create its structure, which happens after DOM loads??
* Therefore, hold the document READY function until an expected element
* is detected
*
* (ps.. This holds ALL jQuery ready functions anywhere the system… if there are any)
*/
var waitForPageToLoad = function() {
if (jQuery(‘.myRootPanel’).size() > 0) {
// it exists now.. trigger the ready function
jQuery.holdReady(false);
} else {
// Doesn’t exist yet.. wait some randomly selected time period.
setTimeout( waitForPageToLoad, 200 );
}
};

/*
* Trigger the timeout function to wait for the page to REALLY load,
* and then release the document READY hold.
*/
waitForPageToLoad();


jQuery plugin: working scrollbar on left side of div

I’ve been building JSF views and creating custom components for a while and one issue we worked on was making scrollable tables, where the header and footer stay stationary and the data scrolls.

I’m still cleaning this up, but the general idea is that I wrapped the table in DIVs, which are set up to scroll vertically or horizontally based on the dynamic content of the table. This seems to be the only solution that is cross-browser, and it uses jQuery to dissect the table and move the header and footer so that the scrolling works correctly. Once I finalize that, i’ll post it.

But one thing was missing: the content of the tables sometimes pushes the table off the right side of the view, and the horizontal scrollbar appears. At this point, the vertical scrollbar is way off to the right and pretty much makes the table useless. So I wanted to move the vertical scrollbar to the left side, and I had trouble finding a cross-browser solution … until now.

I just found a jQuery plugin written by Brian Reavis at his website: 3rd Route. I tested it out and it worked immediately. The only thing i had to do to it was swap out all of the ‘$’ for ‘jQuery’ because of my use of the jQuery.noConflict() flag. I originally found it via stackoverflow, but the version on the website looks like it was cleaned up to enable chaining.

I tried other things, like multiple versions of style="direction:trl", but these felt messy when i read about them, and did not work when I implemented them.

Thanks Brian!

Update: I ended up doing a lot of changes because of some issues i found:

  • For very large tables, this code was really slow in IE.  I narrowed it down to the jQuery ‘append’ function and refactored the plugin to not use it at all
  • The original copied all components into the poser div.  I removed all of that and the poser div is basically now just the scrollbar.  Something major was required for using the plugin with JSF, because it was causing duplicate ID issues.  I decided to get rid of all of the extra components instead of just renaming the IDs.
  • I created a second version that has the scrollbar on both sides
  • I added a unique identifier class so that multiple instances could be on the same page.
  • I changed how the scroll updating worked, but the old way wasn’t broken so it wasn’t really an improvement.

So, based on Brian’s original design and implementation, here is what I am using now:

/**
 * jQuery plugin to add a scrollbar to the left side of a div.  It does this by
 * creating a false div on the left side of the table, and then having that div's scroll
 * position set on the original div every scroll event.
 * 
 * @link edited from http://thirdroute.com/css-js-left-vertical-scrollbars/, but heavily changed from the original version.
 */
jQuery.fn.leftAndRightScrollBar = function(){
	var items = jQuery(this);
	
	var randomString = function() {
		var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz";
		var string_length = 8;
		var randomstring = '';
		for (var i=0; i<string_length; i++) {
			var rnum = Math.floor(Math.random() * chars.length);
			randomstring += chars.substring(rnum,rnum+1);
		}
		return randomstring;
	}

	jQuery(function(){
		items.each(function(){
			// create unique classes for targeting the poser div
			var poserTargetingClass = randomString();
			
			var e = jQuery(this);
			var contentHeight = e.children('table:first').height();
			var content = e.html();
			var ie = !jQuery.support.boxModel;
			var w = e[ie?'innerWidth':'width'](), h = e[ie?'innerHeight':'height']();
			
			//calculate paddings
			var pad = {};
			jQuery(['top', 'right', 'bottom', 'left']).each(function(i, side){
				pad[side] = parseInt(e.css('padding-' + side).replace('px',''));
			});
			//detect scrollbar width
			var xfill = jQuery('<div class="xFill">').css({margin:0, padding:0, height:'1px'});
			e.append(xfill);
			var contentWidth = xfill.width();
			var scrollerWidth = e.innerWidth() - contentWidth - pad.left - pad.right;
			e.css('padding', '0');
			e.children('.xFill').remove();
			
			var poserHeight = h - pad.top - pad.bottom;
			var poser = jQuery('<div class="leftAndRightScrollPoser '+poserTargetingClass+'">')
				// create a div that forces height without copying the content to do it.
				.html('<div style="visibility:hidden;height:'+contentHeight+'px">.</div>')
				.css('overflow','auto')
				.height(poserHeight+(ie?pad.top+pad.bottom:0))
				.width(scrollerWidth-(ie?0:pad.left*2)) // only as wide as the scrollbar.
			;
			
			e
				.css({
					width: w+(ie?0:scrollerWidth)-(ie?0:pad.right+pad.left),
					height: h-(ie?0:pad.bottom+pad.top),
					marginTop: -poserHeight-pad.top*2,
					marginLeft: scrollerWidth
				})
				.css('overflow-y', 'auto')
				.css('overflow-x', 'hidden')
			;
				
			jQuery(['top', 'right', 'bottom', 'left']).each(function(i, side){
				 poser.css('padding-'+side, pad[side]);
				 e.css('padding-'+side, pad[side]);
			});
			poser.insertBefore(e);
			
			var hRatio = (e.innerHeight()+pad.bottom) / poser.innerHeight();
			// Set up scrolling update events
			jQuery("." + poserTargetingClass).scroll(function(){e.scrollTop(poser.scrollTop()*hRatio)});
			e.scroll(function(){poser.scrollTop(e.scrollTop()*hRatio)});
		});
	});
	return items;
};


/**
 * jQuery plugin to move the scrollbar to the left side of a div -- no right scrollbar
 * @link http://thirdroute.com/css-js-left-vertical-scrollbars/, but heavily changed from the original version.
 */
jQuery.fn.leftScrollbar = function(){
	var items = jQuery(this);
	
	var randomString = function() {
		var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz";
		var string_length = 8;
		var randomstring = '';
		for (var i=0; i<string_length; i++) {
			var rnum = Math.floor(Math.random() * chars.length);
			randomstring += chars.substring(rnum,rnum+1);
		}
		return randomstring;
	}
	
	jQuery(function(){
		items.each(function(){
			// create unique classes for targeting the poser div
			var poserTargetingClass = randomString();
			
			var e = jQuery(this);
			var content = e.html();
			var contentHeight = e.children('table:first').height();
			var ie = !jQuery.support.boxModel;
			var w = e[ie?'innerWidth':'width'](), h = e[ie?'innerHeight':'height']();
			//calculate paddings
			var pad = {};
			jQuery(['top', 'right', 'bottom', 'left']).each(function(i, side){
				pad[side] = parseInt(e.css('padding-' + side).replace('px',''));
			});
			//detect scrollbar width
			var xfill = jQuery('<div>').css({margin:0, padding:0, height:'1px'});
			e.append(xfill);
			var contentWidth = xfill.width();
			var scrollerWidth = e.innerWidth() - contentWidth - pad.left - pad.right;
			e.css('padding', '0');
			e.children('.xFill').remove();
			
			var poserHeight = h - pad.top - pad.bottom;
			var poser = jQuery('<div class="leftScrollPoser '+poserTargetingClass+'">')
				.html('<div style="visibility:hidden;height:'+contentHeight+'px">.</div>')
				.css('overflow','auto')
				.height(poserHeight+(ie?pad.top+pad.bottom:0))
				.width(scrollerWidth-(ie?0:pad.left*2)) // only as wide as the scrollbar
			;
			
			e
				.css({
					width: w/*-scrollerWidth*/-(ie?0:pad.right+pad.left),
					height: h-(ie?0:pad.bottom+pad.top),
					overflow: 'hidden',
					marginTop: -poserHeight-pad.top*2,
					marginLeft: scrollerWidth
				});
				
			jQuery(['top', 'right', 'bottom', 'left']).each(function(i, side){
				 poser.css('padding-'+side, pad[side]);
				 e.css('padding-'+side, pad[side]);
			});
			poser.insertBefore(e);
			
			var hRatio = (e.innerHeight()+pad.bottom) / poser.innerHeight();
			// Set up scrolling update events
			jQuery("." + poserTargetingClass).scroll(function(){e.scrollTop(poser.scrollTop()*hRatio)});
			e.scroll(function(){poser.scrollTop(e.scrollTop()*hRatio)}); // so mouse wheel scrolls table
		});
	});
	return items;
};


jQuery

I picked up the book jQuery In Action, and I think I love this library!  Actually, I picked it up a while ago and I’m just getting around to writing about it.  I recently built a website for watching the building of the new arena in Pittsburgh (which is down now because the building is big enough to block the webcam), and I used jQuery to do some really nice fades for image thumbnails.  The only problem was, I was following pre-written instructions and did not know what was really going on.  It did, however, introduce me to the magic of jQuery!

CSS consistency across browsers

One of the best things about jQuery is that you can (almost always) just put a line of jQuery in my web page and it will work across all of the major browsers.  I have had some very small issues with this, but nothing major compared to the amount of code it takes in straight javascript to do the same thing.

There’s also the selectors.  If you know CSS, then you can use jQuery.  jQuery works by creating a wrapped set of elements and performing some tasks on each element in the wrapped set.  The book i read uses the term wrapped set, but if that term is confusing you can just think of it as a group of elements that matches the selector you chose to use.

Any CSS selector can be used to query the page and create this wrapped set.  It even allows for CSS3 selectors and a couple of jQuery-specific extended selectors.  For example, consider the child selector #formId > h1 that would select all h1 elements nested inside the element with the id #formId.  This is not supported in IE6, but with jQuery you can use it anyway:

$('#formId > h1').css('color','red');

Simplify, Simplify, Simplify

jQuery is just simple.  You only need to know the CSS selectors to get the maximum power from jQuery, not which browser supports which selectors, etc.  The javascript file is much neater and more readable.  Take this example of code that was used to put focus on the first input on a webpage:

function setFocusOnFirstLocationOfInputType(type){
var elementsInputs = document.getElementsByTagName("input");
for (i=0; i < elementsInputs.length; i++) {
if(elementsInputs[i].type == type){
elementsInputs[i].focus();
break;
}
}
}

and now consider the jQuery that does the same:

function setFocusOnFirstLocationOfInputType(type){
$("input[type="+type+"]:first").focus();
}

Extendable!

The jQuery core library does everything I’ve mentioned and a lot more, and it is small.  If you need more, there are a lot of plugins available that supply very complex features (made simple!) like accordian or sliding menus (jQueryUI plugin), or extended selectors with regular expressions.

Some links to additional info on the library:


Follow

Get every new post delivered to your Inbox.