Thursday, 27 December 2018
Boggle - Online Game
Tuesday, 24 January 2017
PHP7 Support For Strictly AutoTags
PHP7 Support For Strictly AutoTags
By Strictly-Software
If you are using the popular Strictly AutoTags plugin then everything should be working fine however if you have upgraded to PHP 7 then that will have caused problems.
Not every developer has the time or knowledge to know that a new PHP version will remove features or cause issues with their plugins. However in this case it's due to the /e modifier being dropped.
$content = preg_replace("/(\.[”’\"]?\s*[A-Z][a-z]+\s[a-z])/e","strtolower('$1')",$content);
The only difference apart from the callback is that I am using @ @ as wrappers around my regular expression this is just so I can see it more easily with far less escaping required.
So replace the line above which is about line 1345 of the strictly-autotags/strictlyautotags.class.php file.
$content = preg_replace_callback("@(\.[”’\"]?\s*[A-Z][a-z]+\s[a-z])@",
function ($matches) {
return strtolower($matches[0]);
},
$content);
Other people have used this fix for the plugin in the WordPress forum so it should work. I don't use PHP7 yet so never had to deal with it.
However if you are a developer please help others out on the forum. I have had over 223,616 downloads of the free version. If just everyone of those people had donated me £1 then I could spent my whole time working on it but everyone wants everything for free it seems nowadays which is why I have my premium plugin with more features > Strictly AutoTags Premium Plugin Version.
Remember you can also find up to date information on my Facebook page for my Automation plugins, this and the Strictly TweetBOT plugin which go hand in hand.
Also remember there is a Facebook page for thee plugins you can check for help as I don't automatically get notified of new problems on the WordPress site for some reason.
You can find this page at https://www.facebook.com/strictlysoftware/
Remember if you have a bug with any of my plugins to do the following:
- Check the WordPress forum for similar bugs and fixes https://wordpress.org/support/plugin/strictly-autotags
- Check the ReadMe file or admin page for any help.
- Check your PHP and APACHE error logs to ensure it's this plugin causing the issues.
- Run though the standard debug practises laid out here: Giving useful debug information.
- Provide as much info to the developer as possible e.g PHP version, WP version, Plugin version, any other installed plugins, when it started failing, was anything else installed near that time, details of your process for tagging.
By Strictly-Software
© 2017 Strictly-Software
Tuesday, 9 August 2016
Fun with Dates! Web Server, SQL Server, IIS and ASP Classic - Problems and Solutions
Fun with Dates! Web Server, SQL Server, IIS and ASP Classic - Problems and Solutions
By Strictly-Software
Dates can be a nightmare especially when moving servers.
A setup that ran perfectly on an old system can crumble up into a nightmare when the code and database is ported to a new server. I recently had this problem moving from a webserver connecting to database server to an all in one server based at the French hosting company OVH.
At first everything seemed okay then I started to notice the errors such as
1. Dates entered on a web page form as dd/mm/yyyy on submission coming back in US format e.g 22/08/2016 would come back as 8/22/2016 why there was no trailing zero I have no idea.
2. Primary Key / Index errors where the date was part of the key and it thought duplicates were being added into the system.
Good Practice
I always thought I ran good practice on my systems by doing the following but despite all these settings I was still getting US dates instead of UK dates shown on the website. However you should still do this as it limits the chances of error.1. I ensure all Stored Procedures have SET DATEFORMAT YMD at the top and I store all dates as ISO format yyyy-mm-dd in the database.
2. All database logins used to pass information to the database are set to have "British English" as their "Default Language".
3. The database properties under options is set to British English.
4. The server properties under Advanced -> Default Language is set to British English.
5. On the website I always ask users and use client/server side validation to ensure they enter the dates as UK format dd/mm/yyyy.
6. I then convert that with a simple function into ISO format yyyy-mm-dd hh-mm-ss to pass to the stored procedure that saves the date. Having the SET DATEFORMAT YMD at the top of the stored procedure also helps to ensure SQL treats dates in that order Year - Month - Day etc.
I also always have on my site a Kill page which cleans out all session and application data e.g
<%
Application.Contents.RemoveAll()
Session.Contents.RemoveAll()
Session.Abandon()
%>
This is great if I need to wipe all stored info quickly especially as I have another page that gives me loads of Session, Application, Cookie and HTTP information. It also gives me much more including dates and times from the Web Server e.g NOW() and SQL Server e.g GETDATE() so I can check they are in sync.
I also show the default locale and currency formats. A simple version is below.
<%
response.write("<p>")
response.write("Default LCID is: " & Session.LCID & "<br>")
response.write("Date format is: " & date() & "<br>")
response.write("Currency format is: " & FormatCurrency(350))
%>
The LCID stands for the Server Locale and you can set it either in your Global.asa page if you use one or on the login page or in a global include that all pages use. English - United Kingdom has a value of 2057, the USA is 1033. You can read more about the locales here.
The result I got from my test page was
Default LCID is: 2057
Date format is: 09/08/2016
Currency format is: £350.00
This is all correct.
I have never had to resort to setting the Session.LCID on the website before and the Web Servers globalization settings were set the to the UK. This made it all the more stranger that I was getting US dates.
However I followed ALL of the steps below apart from the last step - which really is a last resort and it fixed the issue. It really is a shame that there isn't just one place where you can set your region and date formats that affects SQL and your Website but there just isn't.
Maybe a clever programmer could write something that would burrow away into all the servers settings and give you a report of what needs changing?
I already have a console .NET app that I run from a command prompt on any machine that tells me whether I can connect to the DB with specific ADO connection string params and LOCALHOST. It returns information about SQL logins, security such as access to extended stored procedures and any collation differences if there are any. It also shows me installed memory and disk space, used memory and disk space, all connected drives mapped drives and user logon history. Plus it attempts to send out an email using LOCALHOST as the mail relay using no ports and standard ports.
It also checks that it can access the outside world with a WebHTTP request to obtain the actual IP address of the machine before doing a PING to Google to test for speed. If I had the time I would probably love to delve into a project to solve the date issue as it's one that just keeps cropping up on new servers.
Debugging, Tests and Solutions
Apart from the good practices which I listed above and resorting to setting Session.LCID = 2057 at the top of your ASP pages there are some other things to try.1. Test that your ISO dates are actually being stored as ISO NOT US e.g 2016-09-08 could be the 8th August in the UK (or ISO), or 9th of July if stored as US format. Do this with a simple SQL statement and login to your database using the connection string properties your website would not as an administrator.
This way you are using the properties of the users login and you can compare the results with you logged in as admin and if they are out of sync you should re-check your login properties again.
SELECT TOP(20) Racedate as ISODate,CONVERT(varchar, Racedate,103) as UKDate,datepart(day,Racedate) as DAYPart,datepart(month,Racedate) as MONTHPart,datepart(year,Racedate) as YEARPart
FROM RACES
ORDER BY Racedate DESC
This should show you how the date is stored as a string (as all dates are really floating point numbers that would make no sense in a select if you saw them), as well as how the database sees each part of the ISO date.
So the DAYPart column should be the right section of the ISODate and left section of the UKDate and the month should be in the middle.
2. Test that your database is using a British format to return data to the client by running this SQL.
SELECT name, alias, UPPER(dateformat) as DateFormat
FROM syslanguages
WHERE langid =
(SELECT value FROM master..sysconfigures
WHERE comment = 'default language')
If everything is setup correctly you should get results like below:
Name - Alias - Dateformat
British - British English - DMY
If you don't get your desired country format back then the issue could be purely on the SQL Server / Database so go back over the good practices to ensure the Server/Database and Logins all have British English (en-gb) as their Default Languages / Locales in any setting you can see.
If you know that dates were entered for today and they look like ISO Date format in the tables then run a simple SELECT with a DATEDIFF(DAY,Stamp,GETDATE())=0 clause to see if they are returned.
If they are then you know the dates are being stored in the DB correctly so the issue is probably due to the web server.
3. Some people say that you should store your dates in 6 columns, Year, Month, Day, Hour, Minute, Second but personally I don't think this level of normalization is necessary OR should be.
However if you only have a couple of places to change then it might offer a solution. However if you already have a big database with lots of dates being shown and entered it would be a lot of work to normalize like this.
4. Go into your web servers Control Panel and select Language. Then ensure all possible date formats, languages and locales are set to use your desired location e.g chose UK instead of US and ensure the date formats are dd/mm/yyyy not mm/dd/yyyy.
There should be an "Advanced" link on the left where you can set the order of preference related to languages there as well. You will need to restart the machine for these to take affect.
5. Follow these steps from your Control Panel so that all users get to use your own regional settings. It's just one more place regions and formats are set which should be looked at if you are having an issue.
- Go to Control Panel.
- Click Region and you will see a screen with 3 tabs (Formats, Location and Administrative).
- Click Formats and choose the settings you prefer.
- Click Additional settings.
- Click Date tab.
- Change Short date to desired format and confirm dialog.
- Click Location and choose the settings you prefer.
- Click Administrative tab.
- For "Welcome screen and new user accounts", click copy settings.
- From the new window, click both checkboxes for "welcome screen and system accounts" and "new user accounts" (if you skip this step, you will still see the issue because IIS uses system account).
- Approve all changes for Region by clicking OK on all open windows.
- Open Command prompt, write iisreset and enter.
- If you still don't see the changes try logoff and logon.
- Or reboot.
6. Go into IIS and at Server level and Database level go into the .NET Globalization settings and change the options Culture and UI Culture to English (en). Even if you are using ASP classic it is still worth doing this.
7. Compare the webpages showing up the US dates in different browsers, FireFox, Chrome and IE for example. If there is a difference then it could be down to your browsers locale settings. You may have had an anti virus checker run and reset some browser properties without you knowing so it's worth a shot especially if you know that not everyone is seeing the same values as yourself.
8. If it really comes down to it and you cannot resolve the issue then you could wrap all your dates from any SQL returned to your web pages in a function that uses VBScript to split the day, month and year apart before putting them back together in the format you want.
An example is below. You can use the built in functions Day(val), Month(val), or Year(val) or DatePart("d",val) to get the part of the date out. This function also uses a quick easy way to append zeros onto single character numbers 1-9 become 01 or 09.
You will also see by this method whether or not the ASP code manages to select the correct part of the date out of the SQL column returned to you.
For example if you have a date of 12/08/2016 (where 12 is the day), and you use Datepart("d",dtDate), where dtDate is the variable holding 12/08/2016. Then you will see if you get back the correct value of 12 (UK) or 08 (US). If you get an issue like this then check all your web server settings.
Function CorrectDate(dtDate)
Dim dDay, dMonth, dYear
dDay = Datepart("d",dtDate)
dMonth = Datepart("m",dtDate)
dYear = Datepart("yyyy",dtDate)
CorrectDate = QuickNoFormat(dDay) & "-" & QuickNoFormat(dMonth) & "-" & dYear
End Function
Function QuickNoFormat(intNo)
'* If the number is only 1 character long add a zero to the front e.g 8 becomes 08
If IsNumeric(intNo) Then
QuickNoFormat = Right(Cstr(Cint(intNo) + 100),2)
Else
QuickNoFormat = intNo
End If
End Function
Hopefully by following the good practice guide you shouldn't run into problems but if you do the list of solutions should help you out. It did with my latest Windows 2012 server.
Let me know if this is of any help for you.
By Strictly-Software
© 2016 Strictly-Software
Thursday, 9 July 2015
DEBUG Stored Procedures Using PRINT or RAISERROR in TSQL
DEBUG Stored Procedures Using PRINT or RAISERROR in TSQL
By Strictly SoftwareUsually when I am having to write stored procedures with many sections within a transaction I set a @DEBUG BIT variable at the top of the procedure to help with debug.
Then I add checks to see if it is enabled and at various points in the procedure, usually at the start and end plus before and after each block of code I would output some debug telling me what is going on.
This really helps me when I have problems with the procedure and need to know where any bug is happening.
An example of a basic stored procedure with transactions so I can rollback the code if something goes wrong, plus the use of a TRY CATCH so that I can log error details to a table is shown below.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[usp_net_clean_up]
@SitePK int
AS
BEGIN
SET NOCOUNT ON;
DECLARE @ROWS INT,
@DEBUG BIT
SELECT @DEBUG = 1
IF @DEBUG = 1
PRINT 'IN usp_net_clean_up - SitePK: ' + CAST(@SitePK as varchar)
BEGIN TRAN
BEGIN TRY
UPDATE NIGHTLY_JOBS
SET Pending = 0
WHERE SitePK = @SitePK
-- capture data errors
SELECT @ROWS = @@ROWCOUNT
IF @ROWS = 0 OR @ERROR != 0
BEGIN
IF @DEBUG = 1
PRINT 'No rows updated'
GOTO HANDLE_ERROR
END
UPDATE LOCK_FILES
SET Locked = 0
WHERE Locked = 1
AND SitePK = @SitePK
AND DATEDIFF(Day,Stamp,GETDATE())=0
SELECT @ROWS = @@ROWCOUNT
IF @ROWS = 0 OR @ERROR != 0
BEGIN
IF @DEBUG = 1
PRINT 'No rows updated'
GOTO HANDLE_ERROR
END
END TRY
BEGIN CATCH
IF @DEBUG = 1
BEGIN
PRINT 'IN CATCH ERROR'
PRINT ERROR_MESSAGE()
PRINT ERROR_LINE()
END
-- all ERROR functions will be available inside this proc
EXEC dbo.usp_sql_log_error @SitePK
-- rollback after anything you want to do such as logging the error
-- to a table as that will get rolled back as well if you don't!
IF @@TRANCOUNT > 0
ROLLBACK TRAN
GOTO HANDLE_ERROR
END CATCH
IF @DEBUG = 1
PRINT 'End of proc - no errors'
IF @@TRANCOUNT > 0
COMMIT TRAN
GOTO EXIT_PROC
HANDLE_ERROR:
IF @DEBUG = 1
PRINT 'IN HANDLE ERROR'
RETURN 1 -- I use 1 for success despite SQL recommendations!
EXIT_PROC:
IF @DEBUG = 1
PRINT 'IN EXIT_PROC'
RETURN 0 -- failure
END
To be honest I only used the function previously to raise custom errors but you easily use it for debugging as well.
This is an example of a super fast way to insert 100,000 rows into a table (using the TEMPDB), and using RAISERROR to output debug messages related to the time it takes plus some examples of the placeholder types which are listed at the bottom of the page.
SET NOCOUNT ON
SET DATEFORMAT YMD
DECLARE @StartStamp VARCHAR(20),
@StopStamp VARCHAR(20),
@ROWS INT
SELECT @StartStamp = CONVERT(varchar, GETDATE(),13)
RAISERROR('Start insert at %s',0,1,@StartStamp) WITH NOWAIT;
-- ensure our table doesn't already exist
IF OBJECT_ID('tempdb.dbo.random_data','U') IS NOT NULL
DROP TABLE tempdb.dbo.random_data;
RAISERROR('Start insert of data',0,1)
-- super fast insert of 100,000 rows into a table
SELECT TOP (100000)
RowNo = ISNULL(CAST( ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS INT),0),
RandomID = NEWID()
INTO tempdb.dbo.random_data
FROM master.sys.all_columns ac1
CROSS JOIN master.sys.all_columns ac2
CROSS JOIN master.sys.all_columns ac3
SELECT @ROWS = @@ROWCOUNT, @StopStamp = CONVERT(varchar, GETDATE(),13)
RAISERROR('There are %d rows in the table. Error Code was %u. Insert completed at %s',0,1,@ROWS,@@ERROR,@StopStamp) WITH NOWAIT;
-- output results
SELECT * FROM tempdb.dbo.random_data
-- drop our table
DROP TABLE tempdb.dbo.random_data;
-- ensure it is dropped
IF OBJECT_ID('tempdb.dbo.random_data','U') IS NULL
RAISERROR('Dropped table %s',0,1,'tempdb.dbo.random_data')
ELSE
RAISERROR('Could not drop table %s',0,1,'tempdb.dbo.random_data')
09 Jul 2015 11:37:18 Start insert at 09 Jul 2015 11:37:18 Start insert of data There are 100000 rows in the table. Error Code was 0. Insert completed at 09 Jul 2015 11:37:18 Dropped table tempdb.dbo.random_data
As you can see you can enter multiple parameters into the RAISERROR function.
The only thing you must remember is that you cannot use functions such as GETDATE(), CONVERT() or CAST() as substitution values. They must all be literals which is why I am converting the time stamps into strings first.
I hope you also notice how fast the insert of 100,000 rows all with unique values in the 2nd column is.
It takes less than one second!
This method is much faster than any WHILE loop or CURSOR method to insert records and you should add it to your box of tricks for future use.
Some people use number tables for insert jobs like this but there is no need when you have system tables with thousands of rows within them.
The trick is to use two CROSS JOINS to to the system tables master.sys.all_columns to create the necessary rows for the insert.
CROSS JOINS are hardly used by many people but they are very useful when you need to do insert jobs like this quickly.
Note how each row is ordered sequentially from 1 to 100,000 and the 2nd column has a unique GUID inside it. This is created from the NEWID() function.
So these are just two methods for adding debug to your TSQL code and it is up to you which method you find the most useful for the job at hand.
RAISERROR function parameter substitution values
%d or %i = signed integer %o = unsigned octal %p = pointer %s = string %u = unsigned integer %x or %X = unsigned hexadecimal
By Strictly Software
© 2015 Strictly Software
Friday, 18 April 2014
How to send a developer USEFUL information - Debugging Strictly AutoTags
How to send a developer USEFUL information - Debugging Strictly AutoTags
By Strictly-SoftwareI understand that a lot of people who use CMS systems like Joomla or WordPress don't know how to code otherwise they would be using proper code they had written themselves.
However most people don't know how to code and therefore they install plugins and themes that they download for free and then expect them to do everything they want and more. On top of that they expect instant free support.They don't seem to realise that:
a) A developers time is not spent just working for free on open source projects
b) A donation for time spent fixing a problem that is only apparent to the user in question would be nice at the very least.
c) A developer cannot fix a problem on a server across the world without:
-Access to their system or website e.g logins, FTP, SSH, Database etc.
-Information about the problem and how the developer can go about replicating it to fix it.
If the developer cannot replicate the problem then how on earth are they supposed to be able to fix it for you?
Therefore the first thing you should do if you have a problem with 3rd party code is check to see if other people have had the same PROBLEM and whether the same SOLUTION works for you.
It may be you are asking a common rookie mistake that many previous people have done before and all you need to do is find out from those people what they did to fix it.
However if a search of Google, BING, Techie Forums like stackoverflow.com and others does not reveal an answer then you should go through a step by step guide to narrow down the problem before contacting the developer in question. Believe it or not they do have lives and don't live to fix other peoples bugs.
Below I have reproduced one the debug notes I give out to my WordPress plugin users for one of my own plugins Strictly AutoTags, It should be used as a guide when you are asking for help but please note some questions are plugin specific.
However in general the steps are useful for ALL plugins or problems and therefore they should be read by all WordPress users.
This step by step routine should ALWAYS be followed by the user before even thinking of emailing me. Also if I do find a problem and fix it for you then some kind of appreciation would be nice e.g a donation would not go a miss.
Steps to narrowing down your problem with a WordPress plugin
1. If you add a post but no tags are added then it does not mean the plugin is not working just that no tags could be found to associate with the post.
2. Test the plugin is working by creating a new post with the following content and saving it as a draft (this is relevant to Strictly AutoTags and may not be needed with your own problem) :
Article Title:
The CIA now admits responsibility for torture at Guantanamo Bay
Content Body:
Today the CIA admitted it was responsible for the recent accusations of torture at Guantanamo Bay.
Billy Bob Johnson, the chief station manager at the Guantanamo Bay prison said that the USA had to hold its hands up and admit that it had allowed its CIA operatives to feed the prisoners nothing but McDonalds and Kentucky Fried Chicken meals whilst forcing them to listen to Christian Rock Music for up to 20 hour periods at a time without any break.
The CIA apologised for the allegations and promised to review its policy of using fast food and Christian Rock Music as a method of torture.
3. Save the draft post and check the number of tags that get added. The plugin should have found a number of words to use even if you have no existing saved tags in your site. It is always best to save the article as a draft, check which tags have been used, remove or add any yourself before publishing an article.
4. Some people have complained that they have added words to the stop/noise word list which still get tagged and think the plugin is broken. This is not the case and the problem is usually that the user hasn't removed any new noise words from the system first BEFORE re-scanning. The noise words are only used in the auto discovery stage of the auto tagging and if tags have already been saved in the system then the site will use them in it's relevancy check whether or not they have been marked as noise words. Version 2.0 has a new option to aid the easy removal of noise words from the saved post tag list and this option should be run whenever new noise words are added.
5. If you have articles with lots of capital words in the title e.g THIS IS A TEST ARTICLE or body then set the Ignore Capital Percentage to a level appropriate for your site. Otherwise words will be treated as acronyms when they shouldn't.
6. If you don't want the plugin to hunt out possible new tags for your site then turn Auto Discovery OFF. Then only existing saved post tags will be used to find relevant tags in new articles.
7. Auto Discovery will find new possible words to use as tags using the settings you give it so set them carefully. However if these new words are not found to be relevant to your article they won't get saved against the post OR in the system. Use the Rank Title and Rank HTML options to ensure words in the post title or already in special formatting HTML such as headers or strong tags are considered more relevant than other words.
8. If you have any problems make sure it not related to Wordpress, your server/hosting or other plugins before requesting support.
9. Please check existing support tickets before writing a new support ticket as the problem may have already been answered.
10. Always disable all other plugins and leave just Strictly AutoTags on before considering it the likely cause of a problem.
11. If you are going to write a new support question that hasn't already been answered can you please provided the following information all which can be got from your host, WP, plugins, DB or a combination of all.
12. Download the wp-config.php file from your server, edit it and turn the constant WP_DEBUG to TRUE and re-upload e.g
define('WP_DEBUG', false);
define('WP_DEBUG', true);
It will mean your visitors see a lot text all over the screen but it will also help you find any critical errors.
Notices and Warnings do not matter as much. But if you see anything Critical or Erroring - take note to supply the developer with.
If nothing is notable return it to FALSE ASAP!
For example load a version of phpinfo.php onto your server but call it something else so hackers cannot guess it e.g my-3467phpINF.php this way you can see what your server has installed but they can't!
It is very important you tell the developer all of the following information so they know what they are working with.
- Version of PHP (or other language) you are running (make sure it's compatible with the code)
- Version of MySQL (or other database system) you are running (make sure it's compatible with the code)
- Any error message you get when you run the routine that breaks.
- The time it takes to run before breaking.
- If you can hit F12 and view the console any Nework/JavaScript errors you may have - also if you have lots of 404's due to missing files fix those as that will cause overhead. If you don't have them just create blank file with the same name.
- If you can code, turn on the debug constant in the plugin, change your IP in the MyIP function to your own IP address (just type "What is my IP" into Google to get a value, re-upload the file (after backing up) and send me the output of the debug.
- If you have lots of browser add-ons try it in a fresh install of a new browser, e.g download Opera/Safari for windows and test it on that.
- If possible install HTTP Fox on FireFox, open it, and then press play just before doing the action that causes the problem. This will give you all the HTTP requests and responses from the server. Look for any 500 status codes or errors. Send me anything unusual - and only related to my site/plugin as it will also record all the plugin guff from your FireFox extensions as well.
- The more information the better, so screeen shots, video casts (free online, click play, do action, stop, send link etc).and step by step guides of what YOU did to reproduce the problem will help.
- How many articles are on your site?
- Is it a big or small site?
- Do you get hacked a lot?
- What were the last errors in your hosts error_log (available through VMIN and SSH e.g PUTTY using a less command on the error log)
"When I do X nothing happens"
"When I hit the send button it breaks"
Buy Strictly AutoTags NOW!
Remember there ids a PRO version of Strictly AutoTags which you csn buy from etsy.com or my own site.
For only £40 you get all the normal features plus:
- The ability to match on tag but tag another.
- Set up your "TOP TAGS" whih wil be ranked above all overs.
- Turn text links like www.strictly-software.com into real clikable links like www.strictly-software.com.
- Remove old HTML like B and I and replace them with modern tsgs like E and I.
- Set limits on the
Sunday, 20 September 2009
Trouble with this keyword and namespaces
I was working on some code the other night which belonged to a site similar to my own in which numerous scripts and "semi frameworks" were being included. By semi framework I mean an add-on script that includes numerous functions that will almost certainly be replicated elsewhere in the site (DOM manipulation, event handlers etc).
The code involved using an iframe and then running an onload event as soon as the content had loaded so that I could resize the iframe to the correct dimensions for the content within. I had a bit of code like this:
addEvent(document.getElementById('myIframe'),"load",resizeIframe);
// resize iframe content onload
function resizeIframe(){
var dc = S.getIframeDoc(this); // return iframe document
var h = dc.body.scrollHeight; // get height of document within iframe
this.height = h+30+"px"; // set height of iframe+30 to ensure no scrollbars
}
As you can see the function resizeIframe which is called when the iframe loads uses the this keyword to reference itself rather than getting a reference to itself using getElementById which is fine as long as you are using a proper browser that supports the DOM 2 event model. However as IE does not support this model it has a problem with the this keyword in that it references the global window object instead of the iframe.
However this is a well known problem and many a solution has been created to get round this issue in Internet Explorer. On the site in question I use the following function which as you can see handles DOM 2, IE's event model and the older DOM 0 event model. It also correctly handles the this keyword problem by storing a reference in the DOM to the function. Read up on PPKs event handler content for more details.
addEvent = function( obj, type, fn, cp )
{
if(obj){
if(obj.addEventListener){
cp = cp || false;
obj.addEventListener( type, fn, cp );
}else if ( obj.attachEvent ) {
obj[type+fn] = function(){fn.call(obj,window.event);}
obj.attachEvent( 'on'+type, obj[type+fn] );
}else{
var ev='on'+type;
var oldevent = obj[ev];
if (typeof oldevent != 'function'){
obj[ev]=fn;
}else{
obj[ev] = function(){ oldevent();fn();}
}
}
}
}However when testing the site in Internet Explorer I was getting errors when trying to reference the contentWindow.document in my resizeIframe function saying its null or not an object.
The reason being that the this keyword was referencing the window object and there is no such object property on the global object.
I spent some time scratching my head and looking over the function at hand and then when I put some debug code into the addEvent function and noticed it not appearing it at all the problem suddenly made sense. After a quick search through the other JS files being included on the page in question I came across the following function in a script called sorttable.js used for sorting table contents.
function addEvent(elm, evType, fn, useCapture)
{
if (elm.addEventListener){
elm.addEventListener(evType, fn, useCapture);
return true;
}else if (elm.attachEvent){
var r = elm.attachEvent("on"+evType, fn);
return r;
} else {
var o = elm[evType];
if(typeof(o)=="function"){
elm[evType] = function(){o();fn();}
}else{
elm[evType] = function(){fn();};
}
}
}As you can see its another addEvent function and one that doesn't handle the this keyword problem in IE.
As this script was being included after my own file it was overwriting the previous addEvent function and therefore was the cause of the error.
Now this self taught lesson reminded me of a recent post I wrote about the amount of duplicate frameworks and semi frameworks being included on websites at the moment. I reckon that on this page in question there was at least 5 different places where a function to add an event listener was being declared:
-My own addEvent function in my standard library strictly.js
-The addEvent function in the sorttable.js script
-JQueries own methods to bind events - different names but doing the same action.
-GooglesAJAX library would surely have its own event handlers.
-AddThis add-on also had a similar event handler.
Therefore 5 scripts all doing the same thing. I explain it more in my earlier post:
http://blog.strictly-software.com/2009/08/large-number-of-duplicate-frameworks.html
where I discuss the possibility of a standard global API for implementing these sort of functions that are nearly always replicated in add-on scripts. This would allow developers to choose the framework to handle this type of work and add-on developers wouldn't have to worry about implementing duplicate code.
Another solution would be if the add-ons would separate their code out into 2 files. The first file would contain the core functionality and then the other file would contain the functions that could/should be handled by the main framework used by the site.
This would allow the site developer to reduce the size of their codebase as they could choose to remove the 2nd file (if they wished) and allow their primary framework to handle the work that a lot of add-ons duplicate such as DOM manipulation and event handling.
Obviously this works only if the add-on is using the same naming convention as the many frameworks and if the frameworks don't even share the same naming convention then this would seem hard to achieve. However we could always use wrapper functions or aliases to point the add-on functions at the desired framework objects e.g for our addEvent function:
// addEvent used by this script
// params supplied
// obj = object, type = event, fn = function
// set alias so that add-on can use sites primary framework e.g jQuery/Prototype
A = addEvent = function(obj,type,fn){
$(obj).bind(type,fn);
}Which allows the add-on to add event listeners with a call to A or addEvent with either call just being a pointer to the frameworks bind method. The add-on provider could either provide these alias wrappers themselves or just outline the interface required and allow the developer to implement the code.
And of course if the user of the add-on didn't use a framework then they could choose to utilise the 2nd files functions as is even if they were duplicated in 5 other places.
This is all just ideas at the moment but I am developing an add-on at the moment that is going to try this approach.
Why Namespaces are such a good idea
Another solution to the problem of duplicated functions is to always use namespaces to define your functions and objects so that there is little if no chance of two functions having the same name. The writer of the sorttable.js file didn't use a namespace to define his functions but if I had of defined my own addEvent function like so instead:
Strictly.addEvent = function(obj, type, fn){ ...
// call like so
Strictly.addEvent(document.getElementById('myIframe'),"load",Strictly.resizeIframe);
I would not have had any problem working out why my function wasn't working as expected unless one of the other add-ons also had used the namespace Strictly!
Obviously using namepaces may solve the problem of functions being overwritten but it doesn't solve the issue of duplicated functionality.
Object Comparisons in Internet Explorer
Now whilst I was scratching my head in relation to the this problem I looked into creating a little test function that would tell me whether this equated to the global object or not as I was going a bit offtrack and of course a simple this === window should do the trick. However whilst looking into the different methods of object comparision I came across some of the differences between browsers of how object comparison is carried out. I don't know why I thought IE wouldn't be the odd one out as it always is but you might find the results interesting or you may not.
Make sure you view the test page in IE and a standards compliant browser like Firefox for comparison so that you see what I mean:
www.strictly-software.com/thistest.htm
window === window.top is true in Firefox and false in IE.
window == document is false in Firefox and true in IE.
var _w=window;
_w === window.top is true in Firefox and false in IE.
When this relates the the global window object:
this === window.top is true in Firefox and false in IE
this === self is true in Firefox and false in IE
This may all be old news as far as JS developers are concerned but it was news to me so I thought I would post the link anyway.
Thursday, 20 August 2009
Problems with IE 8 Developer Toolbar
IE 8 Developer Toolbar Hanging and Locking Browser
Update 25-Sep-09
I have found that one of the primary causes of IE 8 hanging with the developer toolbar is its console logger. If you have a script that outputs messages to the console I have found that IE will hang until all the messages have been outputted to the console. The more messages you have the longer it takes. Also unlike Firebug which seems to output the messages during normal page load activity IE seems to cache all the messages and then output them all in one batch (or has the appearance of doing so). The CPU seems to max out during the outputting of these messages.
I have been doing a lot of work lately with styles, fades and CSS which has obviously meant working with Internet Explorer building in code to handle the differences between IE and other browsers e.g getting computed styles from IEs currentStyle, Opacity differences etc. This has meant using trying to use the Developer Toolbar which was shipped as standard in IE 8.
It should be a great add-on as it lets you do all the things Firebug has allowed developers to do for a long while including switching Javascript on/off, clearing sessions and cookies, viewing the DOM, inspecting elements and their styles and the ability to output debug to the console.
However I have found that this developer toolbar add-on has a tendency to hang especially after the first use of it. I can go to a page and then open the developer window to change the browser or document modes or step through some debug. However if I minimise the window and go back to the main window and then try to open the developer window again the majority of the time it will refuse to come back to focus. Even if I try to maximise or restore the window or go to the desktop to find it. I have also noticed that when I do get focus back it will only partially be visible as if its trying to load content but struggling.
In fact checking the Task Manager usually reveals a CPU of 50% or more. There will be two processes open one for the developer window the other for the main IE window but even though the developer window is hanging it seems the process with the high CPU is the browser window.
I first thought it may just be some heavy Javascript code running on the page but I have had this problem with numerous sites and other people in the office have had similar issues.
I don't know if this is common issue that developers have found but at the moment I am tending to use Firebug-lite or a custom DIV for outputting debug if I need to and custom pages for killing sessions and checking the current document mode and browser mode which are the 3 most common tasks I find myself doing which is a shame as I really like the layout and functionality the toolbar offers. Its just a shame that it seems to run very badly at the moment.
Sunday, 5 April 2009
Problems with Firebug and raised errors
Tuesday, 17 February 2009
Using Firebug Lite for Debugging
- The browser is not Firefox, as I use the full version of Firebug for that browser.
- The version of the site is the development server. Check a constant or an IP address.
- A global Debug flag is enabled.
win.minimize();
if((typeof(firebug)!="undefined") && firebug.env && firebug.env.init)
if(typeof(window.console)!="undefined")
var Debugger = {
ready: false, // once a console is loaded will be set to true
debugCache: [], // holds debug messages until console is loaded and ready
hasCache: false, // flag when cache has messages
debugCount: 0, // message counter
debugInterval: null, // setInterval timer pointer
forceFirebug: true, // if true for Safari/Chrome we will use firebug lite for debug not their own console
debug: true, // flag to enable/disable debug in case you only want to output certain sections
ShowDebug("Output this debug message");
Debugger.debug = false; //turn off debug messages
ShowDebug("This will not be shown");
Debugger.debug = true; //turn debug messages back on
ShowDebug("This will be shown");
