Showing posts with label CSS. Show all posts
Showing posts with label CSS. Show all posts

Wednesday, 16 February 2022

Blogger EU Cookie Message Missing Problem & Solution

My EU Cookie Message Disappeared From My Site - How To Get It Back

By Strictly-Software

I had a bit of a weird experience recently, I found out, only from Google informing me, that for some reason one of my Blogger sites was not showing the EU Cookie Notice that should appear on all Blogger sites if in a European country where "Consent to use Cookies", is required by all website users.

It used to show, and my other blogger sites were still working and in fact, on my own PC, it was still showing the correct message e.g:

"This site uses cookies from Google to deliver its services and to analyse traffic. Your IP address and user agent are shared with Google, together with performance and security metrics, to ensure quality of service, generate usage statistics and to detect and address abuse."

However, when I viewed the site Google had told me about on another PC this was not appearing for some reason. 

I cleared all the cookies, path, domain, and session using the Web Extension called "Web Developer Toolbar", such as this Chrome version. After installing it, a grey cog appears in your toolbar if you fix it to. 

It is really helpful for turning password fields into text, if you want to see what you are typing, or need to see a Browser stored password in the field, or as needed in this instance, for deleting all kinds of Cookies. So after deleting all the Cookies, I refreshed the page and but the EU Cookie Message still didn't show.

Fixing Blogger Cookie Notice Not Showing

If you view the source of a blogger site that is showing the EU Cookie message, then you should find the following code in your source, not generated source, but the standard "View Source" options when you right-click on the page and view the context menu.

The following code should be just above the footer where all your widget scripts are loaded. Notice that I put some HTML comments above my version of the code so I could easily identify it from Bloggers version in the DOM when viewing the source. Why do this if Bloggers code is not in the source anyway? Wait and see.

<!-- this is my code as bloggers only appear in the source sometimes -->
<script defer='' src='/js/cookienotice.js'></script>
<script>
 document.addEventListener('DOMContentLoaded', function(event) {
      window.cookieChoices && cookieChoices.showCookieConsentBar && cookieChoices.showCookieConsentBar(
          (window.cookieOptions && cookieOptions.msg) || 'This site uses cookies from Google to deliver its services and to analyse traffic. Your IP address and user agent are shared with Google, together with performance and security metrics, to ensure quality of service, generate usage statistics and to detect and address abuse.',
          (window.cookieOptions && cookieOptions.close) || 'Ok',
          (window.cookieOptions && cookieOptions.learn) || 'Learn more',
          (window.cookieOptions && cookieOptions.link) || 'https://www.blogger.com/go/blogspot-cookies');
});
</script> 

So to fix the issue, copy the code out of the page and then go to your layout tool in Blogger. Add a widget at the bottom if no JavaScript/Text widget already exists and copy the code into it.

Now the odd thing is that as soon as I saved the widget and then my blogger site. I went to the website having issues and viewed the source code. When I did I saw that not only was my version of the code was in the HTML, but somehow this had put Bloggers own version back into the HTML as well!

Why this would do that I have no idea. However, it meant that I now had two lots of the same script being loaded and 2 lots of the EU Cookie code that shows the DIV and the options for wording appearing in my HTML.

The good thing though, is that this did not cause a problem for my site. I found by adding that code into a widget at the bottom of my page above Bloggers magically re-appearing code, that it did NOT cause the message to appear twice, but also that when I removed my own version of the code, the Blogger version remained.

Also even though I have put in a version of the Blogger code that uses English sentences into the HTML when I use a Proxy or VPN to visit a European country such as Germany, the wording appears in German.

I suspect that my code runs first as it's first in the DOM, then the Google code runs, overwriting my DIV with their DIV and of course the correct wording for the country we are in.

So as I thought everything was working, I removed my own code and saved the site. I then went to it, deleted path, domain, and session cookies, and then refreshed the page again and saw the blogger cookie code running okay. When viewing the source I could see that my code had gone but the blogger code was now still in the HTML, whereas it wasn't before.

However......

After a few hours when I came back to the computer which had not been showing the message and I re-checked by clearing all cookies (path, domain and session), and saw that Bloggers code had disappeared again, and the message was now not showing again!

Why this has happened I do not know as I had not re-saved the Blogger site in question during the time away so I have no idea what caused the Blogger EU Code to disappear again

There really should be an option in settings to force the Cookie compliance code to be inserted but as there isn't the answer seems to be to just leave your version of the cookie code in the HTML source in a widget at the bottom of the layout.

Why this works without causing issues I have no idea and it sounds like a bodge which it is, but as I cannot find any real answers to this problem online, or in Googles KB, I had to come up with a solution that worked to comply with Google's request and this seems to do it.

So the fact that when you have two lots of the same code in your HTML does NOT cause the message to appear twice is a good thing. This means that even if the original code re-appears then you are okay, and if it doesn't then your own code, which is a direct copy of the blogger code, runs instead. 

Also as your code runs first, if it is causing Bloggers code to also re-appear in the HTML then that will run afterwards ensuring the correct European language is shown in the message.

You can view the JavaScript which is loaded in by Blogger by just appending /js/cookienotice.js to any blogger site e.g this one, http://blog.strictly-software.com/js/cookienotice.js. You can then see the functions and HTML they use to show the DIV. You can also see at the top the ID's and Classes they put on the Cookie Message DIV.

So if you want to check which version of the EU Cookie code is running when both sets of JavaScript exist, you could add a bit of code underneath that checks for the Cookie DIV on display, and add some CSS to target cookieChoicesInfo, which is the ID of the DIV that is shown and you could change the background colour of the DIV to see if it is your DIV or Bloggers DIV that appears.

For example, you could put this under your JavaScript code to change the background colour of the DIV with the following code.

<style>
#cookieChoiceInfo{
	background-color: green !important;
}
</style>

Obviously green is a horrible colour for a background, but it easily stands out. When I did this I saw a Green DIV appear with the message in the correct language displayed, despite my EU options having English as the language for all the wording. 

This is because our code to load the script, and the cookie options into the page runs first, before any Blogger code that appears lower down in the HTML / DOM. When that Blogger code does run, it overwrites the DIV and the wording in the correct European language.

If you right-click on the DIV and choose "inspect" then the Developer Console will appear and you will be able to see that your style to change the background colour is being used on the Cookie message DIV. 

As it's a CSS style block with !important after the style, when the Blogger code overwrites the DIV and wording, the style for the background colour of the DIV is still being determined by our CSS Style block.

So the answer if your EU Cookie Compliance Message disappears is to add your own copy of their code into the site through a widget. 

This shouldn't cause any problems due to any duplicate DIV overwriting your DIV and if it disappears again then at least your version remains.

I just don't understand two things.

1. Why did the Cookie code disappear in the first place?

2. Why did the Blogger code re-appear when I added my own version of Bloggers own EU Cookie message code into the HTML and then why did it dissapear again a couple of hours? 

If anyone can answer these questions then please let me know. A search inside Googles Adsense site does not reveal any useful answers at all.

People just suggest adding query strings to your URL to force it to appear which is no good if your site is linked to from various Search Engines and other sites. Or to just delete all the cookies and refresh the page. 

These are two useless suggestions, and the only thing that seems to work for me is the solution I came up with above. So if you have the same problem try this solution.


By Strictly-Software

Thursday, 27 December 2018

Boggle - Online Game

Playing Boggle Online - A Game For XMAS In Pure JavaScript, CSS and HTML

By Strictly-Software

I made this online version of Boggle, the shake letters and make words from letters that join together as my Dad was learning JavaScript, HTML and CSS. So I made it purely in those languages.

You too can play the game if you want online on any up to date browser that is standard compliant and runs JavaScript on my site at https://www.strictly-software.com/games/boggle.html

The version I made uses a single Boggle object with a number of settings, properties and timers. I have split all the functions out into their own methods and added some features that let you edit the game such as:

-The time the game plays for. It defaults to 03:00 minutes but you can change it to any time in the 00:00 format.
-There is a drop down box with Easy, Medium and Hard for you to select. Each option has a different array of letters that are randomly picked for the game. You are more likely to get multiple X, Z and Qu's in the hard level than the easy one.
-There is an option to select the MAXIMUM red letters than appear in a game. It defaults to 3. You might not get 3 but you won't get over 3. You can change this to another numerical value up to 9. When you pick a word containing a red letter you get double points.
-There is a random tick box which means that the letters chosen for the game are purely picked at random from the alphabet array defined in the Boggle object.

If your browser is working (I have tested it on my TV, Laptop, Tablet and phone) then the countdown timer should turn from green to yellow after 90 seconds and then start flashing red during the last 30 seconds before beeping at the end.

If your TV doesn't do all this then it is down the the TV's browser. Test it online on a PC/Laptop first to ensure it all works.

We played a few games of it at Christmas and it worked perfectly.

It is an ideal way for someone learning HTML, JavaScript and CSS to understand the code, tweak it and learn about selectors, short cuts, regular expressions and so on.

It makes use of my lightweight framework which supports chaining, setting HTML, removing nodes callbacks, CSS selectors and much more

You can read about the Getme.js framework and how I made it here > http://blog.strictly-software.com/2009/10/build-your-own-framework.html.

I use SS instead of $ like jQuery and other frameworks and I am of the mindset that pure JavaScript should be used as much as possible. 

An example of chaining is joining multiple functions together with one initial selector to pick the array of nodes to work on.

SS("DIV .mycontrols input).setAtts({style:"color:black;"}).setHTML("Game Over!);

Where the node list (array) from the first selector is passed into the second function so that only those relevant nodes/elements are acted upon. Read the Getme.js article for more details.

All the files can be downloaded to your local machine to play offline and In Chrome to see the code in action go to More Tools > Developer Tools and open the Console in the bottom part of the screen.

Turn the debug variable in the Boggle.html file to true and you will see all the debug to help you understand which functions are being called and if any errors are shown they will appear in red. 

Play around and make the CSS, HTML different and add extra functions or features with JavaScript.


Enjoy the game, we did!

Monday, 15 January 2018

Quickly Grab Generated Source Code With One Click

Quickly Grab Generated Source Code With One Click


By Strictly-Software

Now that my broken arm is getting better I will be doing more code. It still hurts like mad though, the arm bone didn't even look like it belonged anywhere near the shoulder where it was dislocated.

If you want WordPress plugins then go and check out the main site which I need to do some work on. I am also thinking of building an alternative search engine to get round Google's/CIA/NSA's de-ranking and demonetisation.

I used to have a Super Search Engine years ago, that took the top 10 items from Google, BING and Yahoo, however they kept changing the source code until it all became AJAX loaded in on the fly and too hard to scrape.

I think with the push or deletion of alternative news down the rankingsand pro-establishment news gaining viewers they would never had got a year ago due to Facebook's subservience to the USA and Israeli governments. More and more people will move to new decentralised social media platforms and once that happens Facebook and Google, who are already losing out to duckduckgo.com  due to privacy concerns will lose money in their share price as well as many members.                                 

The problem is money of course and too few people click on adverts or donate out the kindness of their heart.

I think, like search.darkpolitriks.com, that has a starting page of core main #altnews websites and podcasts, I could write my own one and charge £10 for a relevant #altnews blog or channel to be added to the SERP, just so that small alternative sites have the same chance of being found in results and sites like CNN and the BBC are weeded out.

Easiest way of creating a SERP. Just ensure the site is relevant and not mainstream.

Anyway I was fixing a bug today when I realised that it was a bookmark with an http source on an https site that prevented the lock from showing.

Sometimes I don't think people realise how dangerous loading third party scripts can be.

Just loading in a CSS stylesheet could cause nightmares.

For example say your site loaded in a stylesheet from www.SomeSiteIDontControl1.com which loads in a background PNG image which in turn loads in another remote 3rd party stylesheet from www.SomeSiteIDontControl2.com.

Then one day the person in control of that site changes that 2nd image to a dangerous .js file or .exe that loads in an XSS attack.

You are so far removed from the actual cause of the problem that with minification and compression you might have no hope in finding the dangerous file.

So one day the 2nd CSS file that you are loading looks something like this:


background:url(http://www.somesiteIdontcontrol2.com/images/background.png) no-repeat 16px 0;


Then one day this site owner changes his background image to be an .js file e.g


background:url(http://www.somesiteIdontcontrol2.com/images/dodgyscript.js) no-repeat 16px 0;


And when the page loads, and after your onDOMLoad event loads in these scripts it hits your user with the JavaScript sites code.

A recursive script might be handy to run every day to check diagnostics by referencing every URL it finds in any style-sheet or JavaScript on your site.

Follow it backwards and check every other URL it finds.

Another way, if you are perfectly happy with your code is to create local versions of the files and images and keep it all on a server you control so no-one could malform the objects being loaded.

This is a bookmarklet script I wrote years ago that shows me the DOM loaded afterwards and not before.

I wanted to see what scripts and files had been added since I pressed the View Source button that shows the HTML and JS/CSS before any code is run on the page.

I use it all the time. I created a bookmarklet and added it to my bookmark bar so it's within easy reach with a URL to www.google.com and save it.

I then edit it and change the location of the JavaScript I want from www.google.com to the code so that it runs. This might not be necessary anymore but I had add a real URL in the old days.

This code basically takes a snapshot of the DOM once all 3rd party objects have modified the code, loaded videos, changed images and anything else sites like to do when onDOMLoad (not onWindowLoad, which only fires once every image and external object has been loaded.

As you are loading the code with a press of a button there is plenty of time for the onDOM onWindow and onFrame load events to fire, plus many others.


javascript:(function()%7b function htmlEscape(s)%7bs=s.replace(/&/g,'&amp;');s=s.replace(/>/g,'&gt;');s=s.replace(/</g,'&lt;');return s;%7d x=window.open(); x.document.write('<pre>' + htmlEscape('<html>\n' + document.documentElement.innerHTML + '\n</html>')); x.document.close(); %7d)();


As the HTML 5 spec still allows for href="javascript: ..... " then a link or button can run JavaScript when it really should be running external document.addEventListener events to each object needing code to fire when hit.

The code just creates a URL encoded function called htmlEscape which replaces brackets and ampersands and opens a new window writing this new code out into the document.documentElement.innerHTML.

Not hard to do but very useful.


By Strictly-Software

© 2018 Strictly-Software

Tuesday, 24 July 2012

Use Blogger to create blogs quickly and automate the content easily

Using Google's blogger.com over wordpress.com

Whereas blogger used to be pretty basic since the new format of blogger arrived on the free blog scene it has been much easier and quicker to set up a blog than other free CMS systems and I would recommend using the new blogger.com system over the free hosted wordpress.com site any day.

Obviously having your own server and your own code running on it is the best way to go but if you are trying to get a blog up quickly or want to automate it by sending posts by emails then I would say blogger.com is better than wordpress.com because of its new simplistic design and ease of use and for a number of other reasons.

Whereas in Wordpress you have to use a plugin (which you cannot use on their free version) to post articles by email to the site e.g Postie in blogger it is built in.

As blogger only uses tags and not categories it is a shame they cannot either have an Automatic Tagging widget like my own or allow you to post tags in the subject line as you can when you send the email.

This is possible in the Wordpress plugin Postie (available for the non hosted version)  which needs a fix to get it working properly: Fixing Postie to use Categories

But as we are talking about the free blogging versions they both have downsides on the the automated posting front.

I have a number of horse racing sites that are on my own server and also use blogger e.g:

http://ukhorseracingstar.blogspot.co.uk/
http://ukhorseracingautobot.blogspot.co.uk/


However before I created UK Horse Racing Star I tried to create a Wordpress free blog on their wordpess.com setup page to use their free domain e.g something like: ukhorseracingstar.wordpress.com.

The registration process went through okay including double email confirmation but when I tried to login it either allowed me to login but not post any articles or change settings OR it just wouldn't let me login in the first place.

During sign up it didn't say "This user name or URL is unacceptable" or that "this goes against our Terms of Service" (for whatever reason), and it really should have done if certain words are unacceptable to their Terms. If they know a word is banned from their URL's then why not say so at registration time?


On one day I tried creating 4 sites all with different names and they were all blocked with no reason given either by email (when I tried complaining) or by their system. Not good service at all.

If you go to https://signup.wordpress.com/signup/ now and try and create a blog with the name ukhorseracingstar it will say "Sorry that site already exists" and it does - by me along with 3 other variations - although I cannot use any of them!

Therefore I tried the new blogger system.

I know this strictly-software.com blog is using the old layout but I haven't got round to changing the styling -  I'm a developer not a designer or CSS guru!

However with the new blogger template and layout tools it was so easy to create a new site I had UK Horse Racing Star up in minutes with widgets down the side for links, RSS Feeds of racing results, banners, text and scripts.

It really was a very simple process to re-size uploaded images, change the background colour, add custom CSS and script.

Therefore I don't know if it's against Wordpress rules to have sites related to horse racing but if you have your own copy of the software you can do what you want with it (GPL and all that) so I have a Wordpress site hosted on my own server www.ukhorseracingtipster.com which is almost ready to rumble.

Also as wordpress.com won't even let you show Google AdSense on their free blog system OR it seems let you create sites with certain words in it like "horse" or "racing" (and whatever else is in their ban list) then I would recommend blogger for free blog hosting because you can show adverts (on non adult themed sites - e.g not gambling or porn sites - I know from my warning by Google over this so be warned)

Their new system is so simple and easy to use you can get a good looking site up in minutes and it took me less than 20 minutes to create both of these blogs:

http://ukhorseracingstar.blogspot.co.uk/
http://ukhorseracingautobot.blogspot.co.uk/ 

Whereas on wordpress.com's free blogging system it really is a very cut down version of their downloadable software and you cannot add your own images, css, scripts, widgets or plugins etc on blogger.com you can do all of this and more. Hopefully they will be extending their widget selections in the future to add more features and drag n drop functionality to their system.

So there is my two pence on the wordpress.com versus blogger.com debate.

Tuesday, 20 December 2011

HTML Hack to get Flash Banners to click through to external URL's

Flash Banner Click Hack

This might be old news to some of you but for those of us who spend most of our time developing rather than designing or cutting up sites this is a neat hack for getting flash banners to have click-through events without having to build them into the Flash Object itself.

I was given some banners the other day written in flash to put on a new site I am working on the-jag.com.

However these banners did not have any links built into them and as we all know you unless a flash object has a click event and a redirect to a URL, either hardcoded or passed in as a parameter then you cannot just add an <A> tag around it as you would with an animated gif or another image as it just won't work.

As CSS is not my speciality I asked a friend how to hack this so I wouldn't have to go back to the designer to get such a URL click through parameter added and these are the steps he gave me.

So if you ever want to add a click event or <A> around a flash banner then this is what you can do.

1. The original banner code. This was the standard OBJECT / EMBED mix, which although not standard compliant is still used a lot on the web.


<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" 
 width="300" height="300" id="banner-300-300" align="middle">
<param name="allowScriptAccess" value="sameDomain" />
<param name="allowFullScreen" value="false" />
<param name="wmode" value="transparent">
<param name="movie" value="banner-300-300.swf" />
<param name="quality" value="high" />
<param name="bgcolor" value="#fff200" /> 
 <embed src="banner-300-300.swf" 
  quality="high" 
  bgcolor="#fff200" 
  width="300" 
  height="300" 
  name="banner-300-300" 
  align="middle" 
  wmode="transparent" 
  allowScriptAccess="sameDomain"
  allowFullScreen="false" 
  type="application/x-shockwave-flash" 
  pluginspage="http://www.macromedia.com/go/getflashplayer" />
</object>



2. First off I added the wmode="transparent" parameter to the object and embed tag to stop the flash object being the top most element in the DOM. This allows you to then add other objects on top of it.

3. I then wrapped the object in a DIV tag that was position relative, had the same width and height as the banner I was showing which was 468x60 and had the same background colour.

This was because adding the wmode="transparent" removed the colour from the banner so it needed to be replaced by the DIV.


<div style="position:relative;background:#fff200;width:300px;height:300px;">


4. I then added some styling to the actual object tag to make it absolutely positioned within the DIV and positioned as the first item within it e.g top: 0px; left: 0px;

I also add a z-index on it of 5. You will see why later.


<object style="position:absolute;top:0px;left:0px;z-index:5;" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" 


5. I then added my <A> tag with the href of the URL I wanted the user to go to when they clicked the flash banner at the bottom of the <OBJECT> and before the closing </DIV>.


</object>
<a href="http://www.google.com" title="Google Search Engine" />Google Search Engine</a>
</div>


6. I then added some styling to the <A> element so that it was also positioned absolutely within the DIV and was the same size as the banner.

I also made sure the text within the anchor element was hidden off screen by adding text-indent:-9000px; to it. This allows search engines to still access the anchor text for Search Engine Optimisation but it doesn't appear on screen which would look silly.

I also made sure the <A> was the top element in the DOM (above the FLASH object) by increasing it's z-index to a figure larger than the value of 5 I had set earlier on the DIV (see point 4)


</object>
<a style="position:absolute;top:0px;left:0px;z-index:10;width:468px;height:60px;text-indent:-9000px;" href="http://www.google.com" title="Google Search Engine" />Google Search Engine</a>
</div>



7. Putting this all together looks like this.


<div style="position:relative;background:#fff200;width:468px;height:60px;">
 <object style="position:absolute;top:0px;left:0px;z-index:5;" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" width="468" height="60" id="jag-banner-468-60" align="middle">
 <param name="allowScriptAccess" value="sameDomain" />
 <param name="allowFullScreen" value="false" />
 <param name="wmode" value="transparent">
 <param name="movie" value="banner-468-60.swf" />
 <param name="quality" value="high" />
 <param name="bgcolor" value="#fff200" /> 
  <embed src="jag-banner-468-60.swf" quality="high" bgcolor="#fff200" width="468" height="60" name="banner-468-60" align="middle" wmode="transparent" allowScriptAccess="sameDomain" allowFullScreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" />
 </object>
 <a style="position:absolute;top:0px;left:0px;z-index:10;width:468px;height:60px;text-indent:-9000px;" href="http://www.google.com" title="Google Search Engine" />Google Search Engine</a>
</div>


I tested this code in the latest versions of Google, Firefox, IE as well as going back to IE 7 in quirks mode and the banner was shown as it should and any click on it took the user to the desired anchor location. No text within the anchor was seen on the screen.

This is just a hack that non designers, like myself, might like to know for future reference as it saves having to ask the developer of the flash file to re-develop it to allow for click-throughs.

Saturday, 3 October 2009

Correctly measuring element dimensions

Obtaining an Elements correct width and height

Should be easy shouldn't it? You could check the elements style.width and style.height property but if they haven't been set by an inline style or with Javascript this won't help. You can use the browser specific style functions to return the current value but there are big differences between IE's currentStyle and the standard getComputedStyle functions.

If you want the height and width in pixels because you need the values for further computations such as positioning an element in the window then you will probably go for offsetWidth and offsetHeight and in fact most of the frameworks will resort to this method within their CSS functions if those dimensions are required. This is because even if you have specified a CSS style for the width and height in pt, em, % or any other unit the offsets will return a value in px. This is very useful as its a very easy method to get an accurate measurement that works cross browser.

Now I was working with some absolutely positioned floating DIV's earlier today and I required the dimensions of an inner DIV for use in a positioning calculation. The issue was that the floating DIV contained numerous inner DIV's only one of which was actually visible at one time. To make one of these sections appear the outer DIV was made visible and all of the inner DIVs apart from the one required to be shown were hidden. When the DIV was closed both the outer and inner DIVs were set to display:none;

I won't go into the reasons for this method apart from saying that the DIV's contained links and the reason I did it this way was for SEO so that all the links were available in the DOM server-side for bots to spider. Too many people nowadays create too much content on the fly with Javascript and forget about the fact that anything created this way is hidden from crawlers.


The problem - Measuring a DIV hidden from the flow

If you want to obtain the dimensions of an element that is currently hidden from the flow using offsetWidth and offsetHeight you must first put that element back into the DOM so that a measurement can be made. The usual method which frameworks like jQuery and Prototype use is to store the existing values for visibility, display and position, set those values to hidden, block and absolute, take a measurement and then revert the styles back to their original values e.g from Prototypes getDimensions function:
getDimensions: function(element) {
element = $(element);
var display = $(element).getStyle('display');
if (display != 'none' && display != null) // Safari bug
return {width: element.offsetWidth, height: element.offsetHeight};

// All *Width and *Height properties give 0 on elements with display none,
// so enable the element temporarily
var els = element.style;
var originalVisibility = els.visibility;
var originalPosition = els.position;
var originalDisplay = els.display;
els.visibility = 'hidden';
els.position = 'absolute';
els.display = 'block';
var originalWidth = element.clientWidth;
var originalHeight = element.clientHeight;
els.display = originalDisplay;
els.position = originalPosition;
els.visibility = originalVisibility;
return {width: originalWidth, height: originalHeight};
},
Now this is fine if the element you are trying to measure is hiding itself from the flow but if a parent is hiding it or even multiple parents then this won't work.

For example if you have a DIV that is set to display:none that contains another DIV also set to display:none; and then this DIV also contains a DIV set to display:none; which is the one you want to measure you actually have to toggle all 3 into the flow and out again to get an accurate offset measurement.

You can see this in action on the following example page I created: http://www.strictly-software.com/testGetdim.htm

View the source and run the test which will take measurements of the DIV on the left which is always in the flow and then the 3 nested DIVs that are hidden from the flow which will only be made visible once the test has run.

As you can see from the debug JQuery has no problem at all getting the measurements of the visible DIV and the outer most one from the 3 nested DIV's. However the two inner DIV's that require parents to be toggled in and out of the flow for their offsets to be measured do not return an accurate value.


Functions to measure offsets correctly

There are 3 main functions used in this test page that return accurate offset values for the nested DIV elements. The others are just helper functions to return a computed/current/style value and output debug or return an element by id.

// returns an array of elements that need to be made visible to carry out a measurement of an element
function getVisibleObj(elem){
arrEls = []; // holds array of elements we need to make visible to measure X

while(elem && elem!==document){
var es = getStyle(elem,"display"); // method returns current/computed/style value

if(es == 'none'){
arrEls.push(elem);
}

elem = elem.parentNode;
}
return arrEls; //null;
}

// swap styles in and out for an accurate measurment. Taken from jQuery and tweaked by myself to
// handle multiple elements.
function Swap(elem, els, styles, callback){

var obj;

for(var x=0,l=els.length;x<l;x++){
// create hash on element to hold old styles so we can revert later
obj = els[x];
obj.old = {};

// Remember the old values, and insert the new ones
for ( var name in styles ) {
obj.old[ name ] = obj.style[ name ];
obj.style[ name ] = styles[ name ];
}
}

// call the function passing in any element that needs scope
callback.call( elem );


for(var x=0,l=els.length;x<l;x++){
obj = els[x];

// Revert the old values
for ( var name in styles ){
obj.style[ name ] = obj.old[ name ];
}
// delete the hash from the element
try{ delete obj.old; }catch(e){ obj.old=null}
}

}

// offsetWidth/Height is element.width/height +border+padding (standard box model)
// clientWidth/Height is element.width/height +padding (if overflow:scroll then -16px)
function getElementDimensions(el){

el = (typeof(el)=="string")?G(el):el; //return a reference to the element

var w=0,h=0,cw=0,ch=0;

// if element is currently hidden we won't be able to get measurements so we need to find out whether this or
// any other parent objects are hiding this element from the flow
var arrEls = getVisibleObj(el); //returns array of objects we need to show to meaure our element

// create function to do the measuring
function getElDim(){

// get style object
var els = el.style;

// get dimensions
w = el.offsetWidth, h = el.offsetHeight, cw = el.clientWidth, ch = el.clientHeight;

}

// do we need to toggle other objects before getting our dimensions
if(arrEls && arrEls.length>0){
// call function to swap over properties so we can accuratley measure this element
var styles = {visibility: "hidden",display:"block"};
Swap(el, arrEls, styles, getElDim);
}else{
getElDim();
}


// create object
var ret = {
"width":w, //total width (element+border+padding)
"height":h,
"clientWidth":cw, //element+padding
"clientHeight":ch
}

return ret;
}

1. getVisibleObj

This function takes an element as its parameter and then loops up any parent elements storing in an array any that have a style.display set to none. Similar function on the web stop at the first element it comes across that is hidden but if you have multiple parents all hiding their children then only a full list will do.

2. Swap

This function was taken from jQuery and tweaked by myself to handle multiple elements instead of just one. The array of elements from getVisibleObj is passed to this function along with the element that requires measuring. This is then passed to the callback function so that correct scope can be utilised not that I require it here. The first loop stores the current style properties of the elements that require toggling in a hash on the object itself. After the callback is run the element styles are toggled back to their original state and this hash is removed from the element.

3. getElementDimensions

This is the function that actually is called by a user and returns an object with the height and width obtained from the elements offset values after any toggling has been carried out.

The reason I have not toggled position:absolute on elements that need toggling is that it seems to work without me doing this plus on the actual code I was working with earlier it was actually causing an incorrect offsetWidth value to be returned in certain situations. The test page seems to work with or without this property so if you have any issues pass this into the Swap function along with display:block and visibility:hidden.

Sunday, 15 March 2009

Comments For Script Articles - CSS Style Object, Linked Lists, Browser, Lazy Form Validator, Social Bookmarks

Example Scripts, Comments section

There are a number of scripts that I have posted on this site that are actually on another domain and therefore not part of blogger. Therefore I have added this article so that if anyone wants to post comments related to those scripts they can by adding them to this article.


Scripts List

JavaScript Unpacker. This simple form allows you to reverse engineer a block of JavaScript code that has been obfuscated by being encoded and is usually identified because the first few characters of the function look like this eval(p,a,c,k,e,r) . This method is usually used by hackers to try and hide the types of operation they are trying to carry out so its a wonderful way of being able to work out what the code is doing. Just paste the packed code into the box at the top, hit the "Unpack" button and hey presto you now have some readable code

CSS Style Object. A Javascript object that correctly calculates the computed style for Internet Explorer. Currently the example is using a function dedicated to correctly calculating styles for font-sizes but the core details could be applied to other styles requiring a computed size in pixels.

Querystring Parser: A small Javascript object dedicated to parsing a querystring something I thought would be inbuilt into the language but isn't. This article is on the blog and has its own comment section.

Linked Lists: A Javascript object dedicated to handling linked lists where the list box options in a parent list control the options that appear in a child list. The source of the data within the lists is not important this object controls the event handlers and the flow down of the hierarchy when a parent list has an item change as well as other default display options.

Lazy Form Validator: A Javascript object that can be used either in full production or when you want to quickly add client side form validation to a page with nothing more than including a reference to this script and then setting specific classes on each form element if special validation is required.

Social Bookmark Include: A simple include file and Javascript function that can be used on blogs or other sites to include links to social sites such as Digg, Stumble, Reddit etc. The script will append the appropriate URI and title details which it extracts from the source of the page containing the scripts. No need to customise the script on each page its used.

Browser Object. A little object dedicated to the now dirty art of browser sniffing containing details about css box model, spoofing, flash support, browser details etc. Most frameworks will still contain something similar and there are still cases where the the browser type and version is required knowledge due to feature support that cannot be tested with object testing.

Please specify which script you are commenting about when posting. Thanks.