home | contact us
» » January


I was recently asked by a client to create a scrollable, navigation menu for their site. However, they wanted it to have an onHover submenu that expanded to the side, over the top of the scrollbar.

The problem with this is that there is noway to do this using normal css, over the overflow:scroll hides the sub menu. If you put the submenus into a different div outside the scrollable area, then you can run into problems with the onHover thinking you’ve left the target.

To get round this I put together the following jQuery, HTML and CSS, which I hope will help someone.

<div class="categories">
	<ul>
		<li class="level0 first parent">
			<a href="path/to/link">
			<p>First Item</p>
			</a>
			<ul style="display:none">
				<li class="level1 first parent">
					<a href="path/to/link">
						<p>sublevel-1</p>
					</a>
					<ul style="display:none">
						<li class="level2 first">
							<a href="path/to/link">
								<p>sub-sublevel1</p>
							</a>
						</li>
					</ul>
				</li>
			</ul>
		</li>
		<li class="level0">
			<a href="path/to/link">
				<p>Second Item</p>
			</a>
		</li>
	</ul>
	<div id="hoverMenu" style="display: none; ">
		<div id="subHoverMenu" style="display: none; "></div>
	</div>
</div>
.categories{background:white;height:310px;overflow:scroll;overflow-x:hidden;}
.categories .active{background:red;}
.categories ul{padding:9px 10px 0 10px;}
.categories ul li a{color:black;height:21px;line-height:21px;}
.categories ul li a p{font-size:13px;padding:0 0 0 0;margin:0 0 0 0;white-space:nowrap;}
.categories #hoverMenu{background:white;height:auto;position:absolute;width:auto;z-index:150;} 
.categories #hoverMenu .active{background:red;}
.categories #hoverMenu li{padding:5px 10px 5px 20px;}
.categories #hoverMenu p{color:black;font-size:13px;white-space:nowrap;}
.categories #hoverMenu #subHoverMenu{background:white;width:auto;height:auto;position:absolute;z-index:150;}
.categories #hoverMenu #subHoverMenu .active{background:red;}
	jQuery(document).ready(function() {
		jQuery(".categories li.level0").mouseenter(function() {
			jQuery(this).siblings().removeClass('active');
			jQuery(this).addClass('active');
			if(jQuery(this).hasClass('parent')) {
				jQuery('#hoverMenu ul').remove();
				var pos = jQuery(this).position(); 
				var mouseX = pos.left + 175;
				var mouseY = pos.top; 
				var subMenu=jQuery(this).children('ul:first')
				subMenu.clone(true, true).show().appendTo('#hoverMenu');
				jQuery('#hoverMenu').css({'top':mouseY,'left':mouseX});
				jQuery('#hoverMenu').show();
			} else {
				jQuery('#hoverMenu ul').remove();
				jQuery('#hoverMenu').hide();
			}
		})
		
		jQuery(".categories li.level1").bind('mouseenter', function() {
			jQuery(this).siblings().removeClass('active');
			jQuery(this).addClass('active');
			if(jQuery(this).children('ul').length) {
				jQuery('#subHoverMenu').empty();
				var subPos = jQuery(this).position();
				var subMouseX = jQuery(this).outerWidth();
				var subMouseY = subPos.top; 
				var subSubMenu=jQuery(this).children('ul:first')
				subSubMenu.clone(true, true).show().appendTo('#subHoverMenu');
				jQuery('#subHoverMenu').css({'top':subMouseY,'left':subMouseX});
				jQuery('#subHoverMenu').show();
			} else {
				jQuery('#subHoverMenu').empty().hide();
			}
		})
		
		jQuery(".categories li.level2").bind('mouseenter', function() {
			jQuery(this).siblings().removeClass('active');
			jQuery(this).addClass('active');
		})
		
		jQuery('#hoverMenu').mouseleave(function(){
			jQuery('#hoverMenu ul').remove();
			jQuery('#hovermenu').hide();
			jQuery('#subHoverMenu').empty().hide();
		})
		
		jQuery('#subHoverMenu').mouseleave(function(){
			jQuery(this).empty().hide();
		})
		
		jQuery('.categories').mouseleave(function() {
			jQuery('#hoverMenu ul').remove();
			jQuery('#hoverMenu').hide();
			jQuery('#subHoverMenu').empty().hide();
			jQuery(".col-left .category-list .categories li").removeClass('active');
		})
	})

Obviously, change styles and content as required


 

I rely on multiple desktops in order to keep my workflow organised. However each time I start up my computer I have to move these windows onto the correct desktop, which is a pain. Thankfully there is a way to place each window onto it’s own desktop when your computer starts. This will explain the basics of doing this.

First you need to install a tool called wmcrtl. On ubuntu you can do this by running this command

sudo apt-get install wmctrl

Once this is installed you need to see how it thinks you desktop is set up. You can do this by running this command

wmctrl -d

which give me the following result

0  * DG: 13440x1050  VP: 0,0  WA: 0,24 3360x1002  Workspace 1

The important part is the 13440×1050 – which corresponds to 8 1680×1050 desktops. Some versions of ubuntu put each desktop as a separate workspace, if so you’ll need to modify the instructions slightly.

At this point you can move you windows around so they are where you want them to be. Once you are happy with your layout, run the following command

wmctrl -lG

which will give you something similar to this

0x0340002e  0 3360 48   1680 1002 ross-desktop Add New Post ‹ Edmonds Commerce  WordPress - Chromium
0x02a00077  0 23002 106  253  970  ross-desktop Buddy List
0x02200004  0 0    58   1680 1021 ross-desktop Terminal
0x06400003  0 6720 58   1680 1021 ross-desktop *untitled - Geany
...

This can be broken down as follows

window-id	desktop-number	x-ofset	y-ofset	width	height	machine-name	window-title

Using this information you can put together a script that will run at startup to launch you windows.

NB This script relies on the window title to move a window. This works because the script will be run at startup and it is assumed that you will only have one instance of each program running. If you plan to have multiple windows open, then you will need to get the window-id, go through the man pages for ways of doing this.

#!/bin/bash
geany /tmp/scratch.sql /tmp/scratch.php &
x-terminal-emulator &
# allow the windows to spawn before moving them
sleep 5
# select and move the windows
# format wmctrl -r "window to move" -e gravity,x-pos,y-pos,width,height (-1 keeps the current value)
wmctrl -r "scratch.php - /tmp - Geany" -e 0,6720,0,-1,-1
wmctrl -r "Terminal" -e 0,3360,0,-1,-1

save the file and make it executable, and then run it at startup to have your windows automatically appear where you want them. This is just scratching the surface of what wmctrl can do, so if you want to carry out more windows management from the command line go through the man pages and see if it can do what you want.


 

So you have a plesk backup file and you want to extract and open the files from it? No problem. This blog will show you how.

The file is a mime file. The “mpack” package will let you unpack it.

First we install the “mpack” package

sudo apt-get install mpack

Let’s imagine your file is called “pleskDump.gz”. If it doesn’t have a “.gz” at the end it might not be bad to add it as some environments will complain if it’s absent.

Next we unzip the file

gunzip pleskDump.gz

Now let’s un-mime the file

mkdir pleskDumpOutput
cd pleskDumpOutput
cat ../pleskDump | munpack

Now we have a bunch of regular tar files, but be careful, if we just extract them, the root folders will not be recreated. In order to keep things together, it’s best now to look at the output you have. Let’s take a made up example:

example-domain.com.httpdocs

Note that the format is essentially domain.rootfolder or in another way, the tar files have your domain name they are archiving, then a dot, then the name of the root folder they made up. We take that root folder and create it like this:

mkdir rootfolder

Now let’s apply that idea to our previoud example; “example-domain.com”

mkdir httpdocs

It’s time to untar into the folder you just created, let’s assume you just created “httpdocs”

tar -xvf example-domain.com.httpdocs -C httpdocs

There you go! You can now output any of the folders you wanted.


 

If you want to serve up text files for download (perhaps product feeds etc) then you might like this little snippet.

Not only will it force the file to be downloaded but it allows you to specify a custom filename that it should be saved as.

if(isset($_GET['download_file'])){
    header("Content-type: application/octet-stream");
    header("Content-Disposition: attachment; filename=Export.txt");
    readfile('Export.txt');
    die;
}

 

The first development release of Magento 2 has a few areas worthy of note for developers of the coming changes to Magento.

Magento 2 now requires PHP 5.3
Zend is still version 1.11.1.
Magento 2 now implements templates on a per modules basis. So now all the different bits of the theme are separated into the modules it belongs to. This means that any existing version 1 theme cannot be dropped into version 2.
Themes in Magento 2 have the concept of variations of the same theme. So a theme can have different CSS and images but use the same templates, this can be configured per store per user agent in the admin. This is useful if you have different seasonable themes that are the same as each other but with a few different images and colours. To achieve the same in Magento 1 you would have to use packages and Magento’s ability to cascade up, this is not longer necessary.

This development release of Magento has a major focus on updating the theme and template system to be more ridged unlike Magento version 1 where the template files could be basically any where within a theme.


 

Magento version two is coming. For those of us who are eagerly awaiting the next major version of the most popular and powerful open source e-commerce platform, you can now see, track and download the code on GitHub.

Not had chance to have an in depth look as yet but we expect great things!

https://github.com/magento/magento2


 

If you are thinking of adding a confirmation of e-mail address to the front-end registration pages of your store e.g the Checkout billing page or the customer account registration, the little snippets below could be of use to you

For the Checkout billing page
1. Locate the magento checkout billing page (billing.phtml) which can be found in app/design/frontend/default/ /template/checkout/onepage
2. Add code 1 below where situable;
Code 1

<div class="field">
<label for="billing:confirm_email" class="required"><em>*</em><?php echo $this->__('Confirm Email Address') ?></label>
<div class="input-box">
<input type="text" name="billing[confirm_email]" title="<?php echo $this->__('Confirm Email') ?>" id="billing:confirm_email" class="input-text required-entry validate-cemail" />
</div>

For the validation of this email confirmation field with the actual email field
3. Locate the Javascript file which Magento uses for validation (validation.js) in /js/prototype
4. Add code 3 where suitable e.g immediately after this line(code 2) in validation.js
Code 2

return !(pass.length < 7);
    }],

Code 3

['validate-cemail', 'Please make sure your emails match.', function(v) {
var conf = $$('.validate-cemail')[0];
var pass = false;
if ($('email')) {
pass = $('email');
}
var emailElements = $$('.validate-email');
for (var i = 0; i < emailElements.size(); i++) {
var emailElement = emailElements[i];
if (emailElement.up('form').id == conf.up('form').id) {
pass = emailElement;
}
}
if ($$('.validate-admin-email').size()) {
pass = $$('.validate-admin-email')[0];
}
return (pass.value == conf.value);
}],

Then that should just do exactly what you want.

For the Customer Account Registration page

1. Locate the magento account register page ,register.phtml in
app/design/frontend/ /default/template/persistent/customer/form/
2. Include code 4 where suitable
Code 4

<div class="field">
<label for="confirm_email" class="required"><em>*</em><?php echo $this->__('Confirm Email Address') ?></label>
<div class="input-box">
<input type="text" name="confirm_email" title="<?php echo $this->__('Confirm Email') ?>" id="confirm_email" class="input-text required-entry validate-cemail" />
</div>
</div>

After this, you should have another field on your registration page which can be subjected to any styling you need to do, most importantly when styling do not change the tag id’s and class names, in a situation where you need to change them, you must also change the javascript selectors accordingly.

I hope this works for you.


 

If you have created a new product type and need to enable it to be included with configurable products you need to let Magento know that it should allow your product type to work with configurable products. To do this open your config xml and add the following xml.

<config>
    <global>
        <catalog>
            <product>
                <type>
                    <configurable translate="label" module="catalog">
                        <allow_product_types>
                            <custom_type_name/>
                        </allow_product_types>
                    </configurable>
                </type>
            </product>
        </catalog>
    </global>
</config>

This tells Magento to include your product type for use with configurable products.


 

I recently needed magento to be able to load a product, and if that product was part of a configurable product detect this and return the parent product if that existed. Looking around google I came across this code snippet and thought it should work

$_product = Mage::getModel('catalog/product')->load($productId);
$parentIdArray = $_product->loadParentProductIds()
                 ->getData('parent_product_ids');
if(!empty($parentIdArray)) {
    // do something
}

The problem is that the loadParentProductIds method was depreciated in 1.4.2.0 and I’m running 1.6. The new way of doing detecting if a product has a parent is to do this

$configurable_product_model = Mage::getModel('catalog/product_type_configurable');
$parentIdArray= $configurable_product_model->getParentIdsByChild($productId);
if(!empty($parentIdArray)) {
    // do something
}

Using this method I overrode the Mage_Catalog_Model_Product class and added this method, which will always return a configurable product if the product is associated with one. Be aware, that if you products belong to more than one configurable product you will have to modify the logic

public function getConfigurableProduct() {
	switch ($this->type_id) {
		case 'configurable':
			return $this;
			break;
		default:
			$configurable_product_model = Mage::getModel('catalog/product_type_configurable');
			$parentId= $configurable_product_model->getParentIdsByChild($this->getId());
			if(isset($parentId[0])) {
				$this->load($parentId[0]);
			}
			break;
	}

	return $this;
}

 

If you are a PHP developer looking for a job in the Bradford area then please do get in touch with Edmonds Commerce.

We are a team of PHP developers who focus on e-commerce based on open source packages such as Magento, osCommerce, Prestashop, OpenCart and others. We also do a fair bit of WordPress, Drupal, Zend Framework etc as well. We even do bespoke PHP development.

If you are a skilled PHP developer and would like to join a team of enthusiastic developers in a friendly flexible environment with a focus on productivity, personal skills development and fun then get in touch with us today.


 
rss icon